From c16063e9f7a35056b03d8adde8f8474036d2961d Mon Sep 17 00:00:00 2001 From: Frank Jogeleit Date: Tue, 25 Jul 2023 10:46:16 +0200 Subject: [PATCH] Check AWS env values Signed-off-by: Frank Jogeleit --- pkg/config/config.go | 22 ++++----- pkg/config/resolver_test.go | 38 +++++++++------- pkg/config/target_factory.go | 76 +++++++++++++++++-------------- pkg/config/target_factory_test.go | 40 ++++++++-------- 4 files changed, 95 insertions(+), 81 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index affa6dc0..1b13e32f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -103,13 +103,17 @@ type Webhook struct { Channels []Webhook `mapstructure:"channels"` } +type AWSConfig struct { + AccessKeyID string `mapstructure:"accessKeyID"` + SecretAccessKey string `mapstructure:"secretAccessKey"` + Region string `mapstructure:"region"` + Endpoint string `mapstructure:"endpoint"` +} + // S3 configuration type S3 struct { TargetBaseOptions `mapstructure:",squash"` - AccessKeyID string `mapstructure:"accessKeyID"` - SecretAccessKey string `mapstructure:"secretAccessKey"` - Region string `mapstructure:"region"` - Endpoint string `mapstructure:"endpoint"` + AWSConfig `mapstructure:",squash"` Prefix string `mapstructure:"prefix"` Bucket string `mapstructure:"bucket"` BucketKeyEnabled bool `mapstructure:"bucketKeyEnabled"` @@ -122,10 +126,7 @@ type S3 struct { // Kinesis configuration type Kinesis struct { TargetBaseOptions `mapstructure:",squash"` - AccessKeyID string `mapstructure:"accessKeyID"` - SecretAccessKey string `mapstructure:"secretAccessKey"` - Region string `mapstructure:"region"` - Endpoint string `mapstructure:"endpoint"` + AWSConfig `mapstructure:",squash"` StreamName string `mapstructure:"streamName"` Channels []Kinesis `mapstructure:"channels"` } @@ -133,11 +134,8 @@ type Kinesis struct { // SecurityHub configuration type SecurityHub struct { TargetBaseOptions `mapstructure:",squash"` + AWSConfig `mapstructure:",squash"` AccountID string `mapstructure:"accountId"` - AccessKeyID string `mapstructure:"accessKeyID"` - SecretAccessKey string `mapstructure:"secretAccessKey"` - Region string `mapstructure:"region"` - Endpoint string `mapstructure:"endpoint"` Channels []SecurityHub `mapstructure:"channels"` } diff --git a/pkg/config/resolver_test.go b/pkg/config/resolver_test.go index 38153c2c..be8bd6f0 100644 --- a/pkg/config/resolver_test.go +++ b/pkg/config/resolver_test.go @@ -107,15 +107,17 @@ var testConfig = &config.Config{ MinimumPriority: "debug", CustomFields: map[string]string{"field": "value"}, }, - AccessKeyID: "AccessKey", - SecretAccessKey: "SecretAccessKey", + AWSConfig: config.AWSConfig{ + AccessKeyID: "AccessKey", + SecretAccessKey: "SecretAccessKey", + Endpoint: "https://storage.yandexcloud.net", + Region: "ru-central1", + }, Bucket: "test", BucketKeyEnabled: false, KmsKeyID: "", ServerSideEncryption: "", - Endpoint: "https://storage.yandexcloud.net", PathStyle: true, - Region: "ru-central1", Prefix: "prefix", Channels: []config.S3{{}}, }, @@ -125,12 +127,14 @@ var testConfig = &config.Config{ MinimumPriority: "debug", CustomFields: map[string]string{"field": "value"}, }, - AccessKeyID: "AccessKey", - SecretAccessKey: "SecretAccessKey", - StreamName: "policy-reporter", - Endpoint: "https://yds.serverless.yandexcloud.net", - Region: "ru-central1", - Channels: []config.Kinesis{{}}, + AWSConfig: config.AWSConfig{ + AccessKeyID: "AccessKey", + SecretAccessKey: "SecretAccessKey", + Endpoint: "https://yds.serverless.yandexcloud.net", + Region: "ru-central1", + }, + StreamName: "policy-reporter", + Channels: []config.Kinesis{{}}, }, SecurityHub: config.SecurityHub{ TargetBaseOptions: config.TargetBaseOptions{ @@ -138,12 +142,14 @@ var testConfig = &config.Config{ MinimumPriority: "debug", CustomFields: map[string]string{"field": "value"}, }, - AccessKeyID: "AccessKey", - SecretAccessKey: "SecretAccessKey", - AccountID: "AccountID", - Endpoint: "https://yds.serverless.yandexcloud.net", - Region: "ru-central1", - Channels: []config.SecurityHub{{}}, + AWSConfig: config.AWSConfig{ + AccessKeyID: "AccessKey", + SecretAccessKey: "SecretAccessKey", + Endpoint: "https://yds.serverless.yandexcloud.net", + Region: "ru-central1", + }, + AccountID: "AccountID", + Channels: []config.SecurityHub{{}}, }, GCS: config.GCS{ TargetBaseOptions: config.TargetBaseOptions{ diff --git a/pkg/config/target_factory.go b/pkg/config/target_factory.go index 549c3996..ad0914a8 100644 --- a/pkg/config/target_factory.go +++ b/pkg/config/target_factory.go @@ -589,24 +589,21 @@ func (f *TargetFactory) createS3Client(config S3, parent S3) target.Client { sugar := zap.S() - if config.AccessKeyID == "" && parent.AccessKeyID == "" { - sugar.Errorf("%s.AccessKeyID has not been declared", config.Name) + if err := checkAWSConfig(config.Name, config.AWSConfig, parent.AWSConfig); err != nil { + sugar.Error(err) + return nil - } else if config.AccessKeyID == "" { + } + + if config.AccessKeyID == "" { config.AccessKeyID = parent.AccessKeyID } - if config.SecretAccessKey == "" && parent.SecretAccessKey == "" { - sugar.Errorf("%s.SecretAccessKey has not been declared", config.Name) - return nil - } else if config.SecretAccessKey == "" { + if config.SecretAccessKey == "" { config.SecretAccessKey = parent.SecretAccessKey } - if config.Region == "" && parent.Region == "" { - sugar.Errorf("%s.Region has not been declared", config.Name) - return nil - } else if config.Region == "" { + if config.Region == "" { config.Region = parent.Region } @@ -680,25 +677,21 @@ func (f *TargetFactory) createKinesisClient(config Kinesis, parent Kinesis) targ } sugar := zap.S() + if err := checkAWSConfig(config.Name, config.AWSConfig, parent.AWSConfig); err != nil { + sugar.Error(err) - if config.AccessKeyID == "" && parent.AccessKeyID == "" { - sugar.Errorf("%s.AccessKeyID has not been declared", config.Name) return nil - } else if config.AccessKeyID == "" { + } + + if config.AccessKeyID == "" { config.AccessKeyID = parent.AccessKeyID } - if config.SecretAccessKey == "" && parent.SecretAccessKey == "" { - sugar.Errorf("%s.SecretAccessKey has not been declared", config.Name) - return nil - } else if config.SecretAccessKey == "" { + if config.SecretAccessKey == "" { config.SecretAccessKey = parent.SecretAccessKey } - if config.Region == "" && parent.Region == "" { - sugar.Errorf("%s.Region has not been declared", config.Name) - return nil - } else if config.Region == "" { + if config.Region == "" { config.Region = parent.Region } @@ -751,25 +744,21 @@ func (f *TargetFactory) createSecurityHub(config SecurityHub, parent SecurityHub } sugar := zap.S() + if err := checkAWSConfig(config.Name, config.AWSConfig, parent.AWSConfig); err != nil { + sugar.Error(err) - if config.AccessKeyID == "" && parent.AccessKeyID == "" { - sugar.Errorf("%s.AccessKeyID has not been declared", config.Name) return nil - } else if config.AccessKeyID == "" { + } + + if config.AccessKeyID == "" { config.AccessKeyID = parent.AccessKeyID } - if config.SecretAccessKey == "" && parent.SecretAccessKey == "" { - sugar.Errorf("%s.SecretAccessKey has not been declared", config.Name) - return nil - } else if config.SecretAccessKey == "" { + if config.SecretAccessKey == "" { config.SecretAccessKey = parent.SecretAccessKey } - if config.Region == "" && parent.Region == "" { - sugar.Errorf("%s.Region has not been declared", config.Name) - return nil - } else if config.Region == "" { + if config.Region == "" { config.Region = parent.Region } @@ -992,3 +981,24 @@ func createReportFilter(filter TargetFilter) *report.ReportFilter { func NewTargetFactory(secretClient secrets.Client) *TargetFactory { return &TargetFactory{secretClient: secretClient} } + +func checkAWSConfig(name string, config AWSConfig, parent AWSConfig) error { + arn := os.Getenv("AWS_ROLE_ARN") + file := os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE") + + noEnvConfig := arn == "" && file == "" + + if noEnvConfig && (config.AccessKeyID == "" && parent.AccessKeyID == "") { + return fmt.Errorf("%s.AccessKeyID has not been declared", name) + } + + if noEnvConfig && (config.SecretAccessKey == "" && parent.SecretAccessKey == "") { + return fmt.Errorf("%s.SecretAccessKey has not been declared", name) + } + + if config.Region == "" && parent.Region == "" { + return fmt.Errorf("%s.Region has not been declared", name) + } + + return nil +} diff --git a/pkg/config/target_factory_test.go b/pkg/config/target_factory_test.go index ffca13dd..c0cb9f40 100644 --- a/pkg/config/target_factory_test.go +++ b/pkg/config/target_factory_test.go @@ -167,42 +167,42 @@ func Test_ResolveTargetWithoutHost(t *testing.T) { } }) t.Run("S3.AccessKey", func(t *testing.T) { - if len(factory.S3Clients(config.S3{Endpoint: "https://storage.yandexcloud.net"})) != 0 { + if len(factory.S3Clients(config.S3{AWSConfig: config.AWSConfig{Endpoint: "https://storage.yandexcloud.net"}})) != 0 { t.Error("Expected Client to be nil if no accessKey is configured") } }) t.Run("S3.SecretAccessKey", func(t *testing.T) { - if len(factory.S3Clients(config.S3{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access"})) != 0 { + if len(factory.S3Clients(config.S3{AWSConfig: config.AWSConfig{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access"}})) != 0 { t.Error("Expected Client to be nil if no secretAccessKey is configured") } }) t.Run("S3.Region", func(t *testing.T) { - if len(factory.S3Clients(config.S3{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret"})) != 0 { + if len(factory.S3Clients(config.S3{AWSConfig: config.AWSConfig{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret"}})) != 0 { t.Error("Expected Client to be nil if no region is configured") } }) t.Run("S3.Bucket", func(t *testing.T) { - if len(factory.S3Clients(config.S3{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1"})) != 0 { + if len(factory.S3Clients(config.S3{AWSConfig: config.AWSConfig{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1"}})) != 0 { t.Error("Expected Client to be nil if no bucket is configured") } }) t.Run("S3.SSE-S3", func(t *testing.T) { - if len(factory.S3Clients(config.S3{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1", ServerSideEncryption: "AES256"})) != 0 { + if len(factory.S3Clients(config.S3{AWSConfig: config.AWSConfig{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1"}, ServerSideEncryption: "AES256"})) != 0 { t.Error("Expected Client to be nil if server side encryption is not configured") } }) t.Run("S3.SSE-KMS", func(t *testing.T) { - if len(factory.S3Clients(config.S3{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1", ServerSideEncryption: "aws:kms"})) != 0 { + if len(factory.S3Clients(config.S3{AWSConfig: config.AWSConfig{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1"}, ServerSideEncryption: "aws:kms"})) != 0 { t.Error("Expected Client to be nil if server side encryption is not configured") } }) t.Run("S3.SSE-KMS-S3-KEY", func(t *testing.T) { - if len(factory.S3Clients(config.S3{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1", BucketKeyEnabled: true, ServerSideEncryption: "aws:kms"})) != 0 { + if len(factory.S3Clients(config.S3{AWSConfig: config.AWSConfig{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1"}, BucketKeyEnabled: true, ServerSideEncryption: "aws:kms"})) != 0 { t.Error("Expected Client to be nil if server side encryption is not configured") } }) t.Run("S3.SSE-KMS-KEY-ID", func(t *testing.T) { - if len(factory.S3Clients(config.S3{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1", ServerSideEncryption: "aws:kms", KmsKeyID: "kmsKeyId"})) != 0 { + if len(factory.S3Clients(config.S3{AWSConfig: config.AWSConfig{Endpoint: "https://storage.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1"}, ServerSideEncryption: "aws:kms", KmsKeyID: "kmsKeyId"})) != 0 { t.Error("Expected Client to be nil if server side encryption is not configured") } }) @@ -212,22 +212,22 @@ func Test_ResolveTargetWithoutHost(t *testing.T) { } }) t.Run("Kinesis.AccessKey", func(t *testing.T) { - if len(factory.KinesisClients(config.Kinesis{Endpoint: "https://yds.serverless.yandexcloud.net"})) != 0 { + if len(factory.KinesisClients(config.Kinesis{AWSConfig: config.AWSConfig{Endpoint: "https://yds.serverless.yandexcloud.net"}})) != 0 { t.Error("Expected Client to be nil if no accessKey is configured") } }) t.Run("Kinesis.SecretAccessKey", func(t *testing.T) { - if len(factory.KinesisClients(config.Kinesis{Endpoint: "https://yds.serverless.yandexcloud.net", AccessKeyID: "access"})) != 0 { + if len(factory.KinesisClients(config.Kinesis{AWSConfig: config.AWSConfig{Endpoint: "https://yds.serverless.yandexcloud.net", AccessKeyID: "access"}})) != 0 { t.Error("Expected Client to be nil if no secretAccessKey is configured") } }) t.Run("Kinesis.Region", func(t *testing.T) { - if len(factory.KinesisClients(config.Kinesis{Endpoint: "https://yds.serverless.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret"})) != 0 { + if len(factory.KinesisClients(config.Kinesis{AWSConfig: config.AWSConfig{Endpoint: "https://yds.serverless.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret"}})) != 0 { t.Error("Expected Client to be nil if no region is configured") } }) t.Run("Kinesis.StreamName", func(t *testing.T) { - if len(factory.KinesisClients(config.Kinesis{Endpoint: "https://yds.serverless.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1"})) != 0 { + if len(factory.KinesisClients(config.Kinesis{AWSConfig: config.AWSConfig{Endpoint: "https://yds.serverless.yandexcloud.net", AccessKeyID: "access", SecretAccessKey: "secret", Region: "ru-central1"}})) != 0 { t.Error("Expected Client to be nil if no stream name is configured") } }) @@ -242,12 +242,12 @@ func Test_ResolveTargetWithoutHost(t *testing.T) { } }) t.Run("SecurityHub.SecretAccessKey", func(t *testing.T) { - if len(factory.SecurityHubs(config.SecurityHub{AccountID: "accountID", AccessKeyID: "access"})) != 0 { + if len(factory.SecurityHubs(config.SecurityHub{AccountID: "accountID", AWSConfig: config.AWSConfig{AccessKeyID: "access"}})) != 0 { t.Error("Expected Client to be nil if no secretAccessKey is configured") } }) t.Run("SecurityHub.Region", func(t *testing.T) { - if len(factory.SecurityHubs(config.SecurityHub{AccountID: "accountID", AccessKeyID: "access", SecretAccessKey: "secret"})) != 0 { + if len(factory.SecurityHubs(config.SecurityHub{AccountID: "accountID", AWSConfig: config.AWSConfig{AccessKeyID: "access", SecretAccessKey: "secret"}})) != 0 { t.Error("Expected Client to be nil if no region is configured") } }) @@ -359,21 +359,21 @@ func Test_GetValuesFromSecret(t *testing.T) { }) t.Run("Get S3 values from Secret", func(t *testing.T) { - clients := factory.S3Clients(config.S3{TargetBaseOptions: config.TargetBaseOptions{SecretRef: secretName}, Endpoint: "endoint", Bucket: "bucket", Region: "region"}) + clients := factory.S3Clients(config.S3{TargetBaseOptions: config.TargetBaseOptions{SecretRef: secretName}, AWSConfig: config.AWSConfig{Endpoint: "endoint", Region: "region"}, Bucket: "bucket"}) if len(clients) != 1 { t.Error("Expected one client created") } }) t.Run("Get S3 values from Secret with KMS", func(t *testing.T) { - clients := factory.S3Clients(config.S3{TargetBaseOptions: config.TargetBaseOptions{SecretRef: secretName}, Endpoint: "endoint", Bucket: "bucket", Region: "region", BucketKeyEnabled: true, ServerSideEncryption: "aws:kms"}) + clients := factory.S3Clients(config.S3{TargetBaseOptions: config.TargetBaseOptions{SecretRef: secretName}, AWSConfig: config.AWSConfig{Endpoint: "endoint", Region: "region"}, Bucket: "bucket", BucketKeyEnabled: true, ServerSideEncryption: "aws:kms"}) if len(clients) != 1 { t.Error("Expected one client created") } }) t.Run("Get Kinesis values from Secret", func(t *testing.T) { - clients := factory.KinesisClients(config.Kinesis{TargetBaseOptions: config.TargetBaseOptions{SecretRef: secretName}, Endpoint: "endpoint", StreamName: "stream", Region: "region"}) + clients := factory.KinesisClients(config.Kinesis{TargetBaseOptions: config.TargetBaseOptions{SecretRef: secretName}, AWSConfig: config.AWSConfig{Endpoint: "endpoint", Region: "region"}, StreamName: "stream"}) if len(clients) != 1 { t.Error("Expected one client created") } @@ -613,21 +613,21 @@ func Test_GetValuesFromMountedSecret(t *testing.T) { }) t.Run("Get S3 values from MountedSecret", func(t *testing.T) { - clients := factory.S3Clients(config.S3{TargetBaseOptions: config.TargetBaseOptions{MountedSecret: mountedSecret}, Endpoint: "endpoint", Bucket: "bucket", Region: "region"}) + clients := factory.S3Clients(config.S3{TargetBaseOptions: config.TargetBaseOptions{MountedSecret: mountedSecret}, AWSConfig: config.AWSConfig{Endpoint: "endpoint", Region: "region"}, Bucket: "bucket"}) if len(clients) != 1 { t.Error("Expected one client created") } }) t.Run("Get S3 values from MountedSecret with KMS", func(t *testing.T) { - clients := factory.S3Clients(config.S3{TargetBaseOptions: config.TargetBaseOptions{MountedSecret: mountedSecret}, Endpoint: "endpoint", Bucket: "bucket", Region: "region", BucketKeyEnabled: true, ServerSideEncryption: "aws:kms"}) + clients := factory.S3Clients(config.S3{TargetBaseOptions: config.TargetBaseOptions{MountedSecret: mountedSecret}, AWSConfig: config.AWSConfig{Endpoint: "endpoint", Region: "region"}, Bucket: "bucket", BucketKeyEnabled: true, ServerSideEncryption: "aws:kms"}) if len(clients) != 1 { t.Error("Expected one client created") } }) t.Run("Get Kinesis values from MountedSecret", func(t *testing.T) { - clients := factory.KinesisClients(config.Kinesis{TargetBaseOptions: config.TargetBaseOptions{MountedSecret: mountedSecret}, Endpoint: "endpoint", StreamName: "stream", Region: "region"}) + clients := factory.KinesisClients(config.Kinesis{TargetBaseOptions: config.TargetBaseOptions{MountedSecret: mountedSecret}, AWSConfig: config.AWSConfig{Endpoint: "endpoint", Region: "region"}, StreamName: "stream"}) if len(clients) != 1 { t.Error("Expected one client created") }