From fe89b2a76994ec53d9d3452a5f4e4d8811751c9f Mon Sep 17 00:00:00 2001 From: Richard Hagen Date: Tue, 19 Mar 2024 12:41:27 +0100 Subject: [PATCH] Migrate to managed identities (#116) * update schema and readme for new managed identities * Use AzureDb driver for workload identity auth * Added version log * Added version log * use correct image * Add support for deployment annotations, pod labels and service account annotations --- Makefile | 14 ++------------ README.md | 4 +++- azure-infrastructure/createSchema.sql | 15 ++++++++++++++- charts/Chart.yaml | 4 ++-- charts/templates/deployment.yaml | 12 +++++++----- charts/templates/secret.yaml | 8 -------- charts/templates/serviceaccount.yaml | 4 ++++ charts/values.yaml | 9 +++++++-- config/config.go | 6 ++---- go.mod | 7 +++++++ go.sum | 8 ++++++++ main.go | 5 ++++- pkg/utils/mssql/mssql.go | 13 +++++-------- run/collector.go | 2 +- 14 files changed, 66 insertions(+), 45 deletions(-) delete mode 100644 charts/templates/secret.yaml diff --git a/Makefile b/Makefile index 3b4a23c..bb780f0 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,7 @@ DOCKER_REGISTRY=radixdev.azurecr.io VERSION=latest -IMAGE_NAME=$(DOCKER_REGISTRY)/radix-cost-allocation:$(VERSION) -DB_PASSWORD=a_password - -# to deploy run: "make deploy DB_PASSWORD=" - -# to deploy db: "make deploy-azure DB_PASSWORD=" +BRANCH := $(shell git rev-parse --abbrev-ref HEAD) +IMAGE_NAME=$(DOCKER_REGISTRY)/radix-cost-allocation:$(BRANCH)-$(VERSION) build: docker build -t $(IMAGE_NAME) . @@ -14,12 +10,6 @@ push: az acr login -n $(DOCKER_REGISTRY) docker push $(IMAGE_NAME) -deploy: - helm upgrade --install radix-cost-allocation ./charts --set db.password=$(DB_PASSWORD) - -deploy-azure: - az deployment group create --resource-group common --template-file ./azure-infrastructure/azuredeploy.json --parameters sqlAdministratorLoginPassword=$(DB_PASSWORD) - .PHONY: test test: go test -cover `go list ./...` diff --git a/README.md b/README.md index 7a3cfbc..9f4a35a 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ We use arm template and github action to create azure resources The SQL Server database and objects are deployed on push to master and release branch. All SQL scripts on azure-infrastructure must be idempotent. +Note: The Github Workflow is not allowed to create new external users, so you must run it locally. Se more here: https://github.com/equinor/radix-vulnerability-scanner/issues/54 + ## Deploy to cluster Installation on cluster is handled by flux through [flux repo](https://github.com/equinor/radix-flux). Before being installed, it requires that there exist a namespace called `radix-cost-allocation`. In that namespace there must be a secret called `cost-db-secret` that contains the database password. This is handled through the setup script in [radix-platform](https://github.com/equinor/radix-platform) @@ -67,4 +69,4 @@ Create a copy of .env.template and name it .env. Set variables to allow local de --------- -[Security notification](./SECURITY.md) \ No newline at end of file +[Security notification](./SECURITY.md) diff --git a/azure-infrastructure/createSchema.sql b/azure-infrastructure/createSchema.sql index 94add2b..aebb3fd 100644 --- a/azure-infrastructure/createSchema.sql +++ b/azure-infrastructure/createSchema.sql @@ -16,4 +16,17 @@ BEGIN CREATE ROLE datareader END -GRANT SELECT ON SCHEMA::cost TO datareader \ No newline at end of file +GRANT SELECT ON SCHEMA::cost TO datareader + + +IF NOT EXISTS(SELECT 1 FROM sys.database_principals WHERE name = 'radix-id-vulnerability-scan-writer-$(RADIX_ZONE)') +BEGIN + CREATE USER [radix-id-vulnerability-scan-writer-$(RADIX_ZONE)] FROM EXTERNAL PROVIDER; +END +ALTER ROLE datawriter ADD MEMBER [radix-id-vulnerability-scan-writer-$(RADIX_ZONE)] + +IF NOT EXISTS(SELECT 1 FROM sys.database_principals WHERE name = 'radix-id-vulnerability-scan-reader-$(RADIX_ZONE)') +BEGIN + CREATE USER [radix-id-vulnerability-scan-reader-$(RADIX_ZONE)] FROM EXTERNAL PROVIDER; +END +ALTER ROLE datareader ADD MEMBER [radix-id-vulnerability-scan-reader-$(RADIX_ZONE)] diff --git a/charts/Chart.yaml b/charts/Chart.yaml index 09aed8c..a47d461 100644 --- a/charts/Chart.yaml +++ b/charts/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v1 -appVersion: 0.3.4 -version: 0.6.3 +appVersion: 1.0.0 +version: 1.0.0 description: Pull cost data from containers and push to sql server name: radix-cost-allocation diff --git a/charts/templates/deployment.yaml b/charts/templates/deployment.yaml index 698427a..158fb60 100644 --- a/charts/templates/deployment.yaml +++ b/charts/templates/deployment.yaml @@ -5,6 +5,10 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "cost-allocation.labels" . | nindent 4 }} + {{- with .Values.deploymentAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} spec: replicas: 1 selector: @@ -14,6 +18,9 @@ spec: metadata: labels: {{- include "cost-allocation.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} spec: serviceAccount: {{ include "cost-allocation.serviceAccountName" . }} securityContext: @@ -34,8 +41,6 @@ spec: value: {{ .Values.schedule.nodeSync | quote }} - name: SCHEDULE_POD_SYNC value: {{ .Values.schedule.podSync | quote }} - - name: SQL_USER - value: {{ .Values.db.user }} - name: SQL_DATABASE value: {{ .Values.db.database }} - name: SQL_SERVER @@ -46,9 +51,6 @@ spec: value: {{ .Values.logLevel }} - name: APP_NAME_EXCLUDE_LIST value: {{ .Values.appNameExcludeList }} - envFrom: - - secretRef: - name: {{ .Values.secret.name }} resources: {{- toYaml .Values.resources | nindent 12 }} securityContext: diff --git a/charts/templates/secret.yaml b/charts/templates/secret.yaml deleted file mode 100644 index 9a646c7..0000000 --- a/charts/templates/secret.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Values.secret.name }} - namespace: {{ .Release.Namespace }} -type: Opaque -stringData: - SQL_PASSWORD: {{ .Values.db.password }} diff --git a/charts/templates/serviceaccount.yaml b/charts/templates/serviceaccount.yaml index 2602549..7882af7 100644 --- a/charts/templates/serviceaccount.yaml +++ b/charts/templates/serviceaccount.yaml @@ -5,3 +5,7 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "cost-allocation.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} diff --git a/charts/values.yaml b/charts/values.yaml index 441c7b8..1a439f2 100644 --- a/charts/values.yaml +++ b/charts/values.yaml @@ -12,16 +12,21 @@ image: secret: name: sql-credential +# Annotations to add to the Deployment +deploymentAnnotations: {} +# Extra pod labels +podLabels: {} + serviceAccount: # The name of the service account to use. # If not set, a name is generated using the fullname template name: "" + # Annotations to add to the service account + annotations: {} db: - user: radixwriter database: sqldb-radix-cost-allocation server: sql-radix-cost-allocation-dev.database.windows.net - password: password port: "1433" queryTimeout: "30" diff --git a/config/config.go b/config/config.go index 27acddd..d422f4e 100644 --- a/config/config.go +++ b/config/config.go @@ -14,10 +14,8 @@ type AppConfig struct { type SQLConfig struct { Server string Database string `envconfig:"default=sqldb-radix-cost-allocation"` - User string - Password string - Port int `envconfig:"default=1433"` - QueryTimeout int `envconfig:"default=30"` + Port int `envconfig:"default=1433"` + QueryTimeout int `envconfig:"default=30"` } // CronSchedule defines cron schedules for jobs diff --git a/go.mod b/go.mod index 41bfeef..30da1b7 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,10 @@ require ( require ( dario.cat/mergo v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/equinor/radix-common v1.7.1 // indirect @@ -29,6 +33,7 @@ require ( github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -39,12 +44,14 @@ require ( github.com/imdario/mergo v0.3.13 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect diff --git a/go.sum b/go.sum index e7b57af..02ab7a8 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,12 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 h1:8kDqDngH+DmVBiCtIjCFTGa7MBnsIOkF9IccInFEbjk= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -11,6 +15,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= @@ -36,6 +41,7 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -86,6 +92,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= @@ -111,6 +118,7 @@ github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4 github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/main.go b/main.go index 766a5f7..ceffbb2 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "context" "os" "os/signal" + "runtime/debug" "syscall" "time" @@ -31,6 +32,9 @@ func main() { log.Fatal().Err(err).Msg("Failed to initialize logger") } + info, _ := debug.ReadBuildInfo() + log.Info().Str("version", info.Main.Version).Msg("Starting") + go func() { if err := run.InitAndStartCollector(ctx, appConfig.SQL, appConfig.Schedule, appConfig.AppNameExcludeList); err != nil { log.Fatal().Msg(err.Error()) @@ -39,7 +43,6 @@ func main() { <-ctx.Done() } - func setupLogger(ctx context.Context, logLevel string, prettyPrint bool) (context.Context, error) { zerolog.DurationFieldUnit = time.Millisecond level, err := zerolog.ParseLevel(logLevel) diff --git a/pkg/utils/mssql/mssql.go b/pkg/utils/mssql/mssql.go index a93452a..99cf28e 100644 --- a/pkg/utils/mssql/mssql.go +++ b/pkg/utils/mssql/mssql.go @@ -4,14 +4,12 @@ import ( "database/sql" "fmt" - mssql "github.com/microsoft/go-mssqldb" + "github.com/microsoft/go-mssqldb/azuread" ) // OpenSQLServer opens a new connection to a SQL Server -func OpenSQLServer(server, database, userID, password string, port int) (*sql.DB, error) { - c, err := mssql.NewConnector( - GetSQLServerDsn(server, database, userID, password, port), - ) +func OpenSQLServer(server, database string, port int) (*sql.DB, error) { + c, err := azuread.NewConnector(GetSQLServerDsn(server, database, port)) if err != nil { return nil, err } @@ -20,9 +18,8 @@ func OpenSQLServer(server, database, userID, password string, port int) (*sql.DB } // GetSQLServerDsn builds a SQL Server specific DSN -func GetSQLServerDsn(server, database, userID, password string, port int) string { - dsn := fmt.Sprintf("server=%s;user id=%s;password=%s;database=%s", - server, userID, password, database) +func GetSQLServerDsn(server, database string, port int) string { + dsn := fmt.Sprintf("server=%s;database=%s;fedauth=ActiveDirectoryDefault", server, database) if port > 0 { dsn = fmt.Sprintf("%s;port=%d", dsn, port) diff --git a/run/collector.go b/run/collector.go index d3c5cb1..92db767 100644 --- a/run/collector.go +++ b/run/collector.go @@ -47,7 +47,7 @@ func InitAndStartCollector(ctx context.Context, sqlConfig config.SQLConfig, cron return errors.WithMessage(err, "failed to get kubernetes clients") } - db, err := mssqlUtils.OpenSQLServer(sqlConfig.Server, sqlConfig.Database, sqlConfig.User, sqlConfig.Password, sqlConfig.Port) + db, err := mssqlUtils.OpenSQLServer(sqlConfig.Server, sqlConfig.Database, sqlConfig.Port) if err != nil { return errors.WithMessage(err, "failed to init database driver") }