From 79570aded944a79fcb8f9b6e04cff4dca05c6be3 Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 9 Dec 2019 10:02:05 +0800 Subject: [PATCH 01/11] Draft the codes of read credential from aws secret manager --- Dockerfile | 2 +- pkg/adapter/anchore/client/client.go | 82 +++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 12d0c64..0d9061e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM alpine:3.10 LABEL "maintainer"="dev@anchore.com" LABEL "commit"=$COMMIT -LABEL "source"="https://github.com/anchore/harbor-scanner-adapter" +LABEL "source"="https://github.com/cafeliker/harbor-scanner-adapter-anchore" RUN apk update && apk add --no-cache curl bash ca-certificates && update-ca-certificates diff --git a/pkg/adapter/anchore/client/client.go b/pkg/adapter/anchore/client/client.go index 1c3886d..54fa73c 100644 --- a/pkg/adapter/anchore/client/client.go +++ b/pkg/adapter/anchore/client/client.go @@ -4,9 +4,6 @@ import ( "crypto/tls" "encoding/json" "fmt" - "github.com/anchore/harbor-scanner-adapter/pkg/model/anchore" - "github.com/parnurzeal/gorequest" - log "github.com/sirupsen/logrus" "math" "net/url" "path" @@ -14,6 +11,14 @@ import ( "strconv" "strings" "time" + + "github.com/anchore/harbor-scanner-adapter/pkg/model/anchore" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/secretsmanager" + "github.com/parnurzeal/gorequest" + log "github.com/sirupsen/logrus" ) const ( @@ -38,10 +43,81 @@ type ClientConfig struct { } func getNewRequest(clientConfiguration *ClientConfig) *gorequest.SuperAgent { + reloadCredential(clientConfiguration) timeout := time.Duration(clientConfiguration.TimeoutSeconds) * time.Second return gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: clientConfiguration.TLSVerify}).SetBasicAuth(clientConfiguration.Username, clientConfiguration.Password).Timeout(timeout) } +// Reload the anchore user name and password if AWS Secret Manager is used +func reloadCredential(clientConfiguration *ClientConfig) { + if strings.HasPrefix(clientConfiguration.Username, "aws:secretmanager") { + if getAWSSecret(clientConfiguration.Username) != "" { + clientConfiguration.Username = getAWSSecret(clientConfiguration.Username) + } + } + if strings.HasPrefix(clientConfiguration.Password, "aws:secretmanager") { + if getAWSSecret(clientConfiguration.Password) != "" { + clientConfiguration.Password = getAWSSecret(clientConfiguration.Password) + } + } +} + +func getAWSSecret(configValue string) string { + // The expected format is aws:secretmanager:: + fileds := strings.Split(configValue, ":") + region, name, key := fileds[2], fileds[3], fileds[4] + + //Create a Secrets Manager client + svc := secretsmanager.New(session.New(), &aws.Config{Region: aws.String(region)}) + input := &secretsmanager.GetSecretValueInput{ + SecretId: aws.String(name), + VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified + } + + result, err := svc.GetSecretValue(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case secretsmanager.ErrCodeDecryptionFailure: + // Secrets Manager can't decrypt the protected secret text using the provided KMS key. + fmt.Println(secretsmanager.ErrCodeDecryptionFailure, aerr.Error()) + + case secretsmanager.ErrCodeInternalServiceError: + // An error occurred on the server side. + fmt.Println(secretsmanager.ErrCodeInternalServiceError, aerr.Error()) + + case secretsmanager.ErrCodeInvalidParameterException: + // You provided an invalid value for a parameter. + fmt.Println(secretsmanager.ErrCodeInvalidParameterException, aerr.Error()) + + case secretsmanager.ErrCodeInvalidRequestException: + // You provided a parameter value that is not valid for the current state of the resource. + fmt.Println(secretsmanager.ErrCodeInvalidRequestException, aerr.Error()) + + case secretsmanager.ErrCodeResourceNotFoundException: + // We can't find the resource that you asked for. + fmt.Println(secretsmanager.ErrCodeResourceNotFoundException, aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + } else { + // Decrypts secret using the associated KMS CMK. + var secretString string + if result.SecretString != nil { + secretString = *result.SecretString + // a map container to decode the JSON structure into + kmap := make(map[string]string) + json.Unmarshal([]byte(secretString), &kmap) + return kmap[key] + } + } + + return "" +} + // Handle error responses generically func unmarshalError(body []byte, response gorequest.Response) (anchore.Error, error) { result := anchore.Error{} From c50d5f6cde5f57c3cd0801f1e6683b31593fa331 Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 9 Dec 2019 15:11:20 +0800 Subject: [PATCH 02/11] Add more debug logs --- pkg/adapter/anchore/client/client.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/adapter/anchore/client/client.go b/pkg/adapter/anchore/client/client.go index 54fa73c..90622f9 100644 --- a/pkg/adapter/anchore/client/client.go +++ b/pkg/adapter/anchore/client/client.go @@ -51,11 +51,13 @@ func getNewRequest(clientConfiguration *ClientConfig) *gorequest.SuperAgent { // Reload the anchore user name and password if AWS Secret Manager is used func reloadCredential(clientConfiguration *ClientConfig) { if strings.HasPrefix(clientConfiguration.Username, "aws:secretmanager") { + log.Debug("Start to load user name from AWS Secret Manager") if getAWSSecret(clientConfiguration.Username) != "" { clientConfiguration.Username = getAWSSecret(clientConfiguration.Username) } } if strings.HasPrefix(clientConfiguration.Password, "aws:secretmanager") { + log.Debug("Start to load password from AWS Secret Manager") if getAWSSecret(clientConfiguration.Password) != "" { clientConfiguration.Password = getAWSSecret(clientConfiguration.Password) } @@ -67,6 +69,8 @@ func getAWSSecret(configValue string) string { fileds := strings.Split(configValue, ":") region, name, key := fileds[2], fileds[3], fileds[4] + log.WithFields(log.Fields{"region": region, "name": name, "key": key}).Debug("pass in secret manager parameters") + //Create a Secrets Manager client svc := secretsmanager.New(session.New(), &aws.Config{Region: aws.String(region)}) input := &secretsmanager.GetSecretValueInput{ From 0237b989669c61f84d1fe8d3a66641500f907b14 Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 9 Dec 2019 16:47:46 +0800 Subject: [PATCH 03/11] Resolve conflict --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0d9061e..501c9b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM alpine:3.10 LABEL "maintainer"="dev@anchore.com" LABEL "commit"=$COMMIT -LABEL "source"="https://github.com/cafeliker/harbor-scanner-adapter-anchore" +LABEL "source"="https://github.com/anchore/harbor-scanner-adapter RUN apk update && apk add --no-cache curl bash ca-certificates && update-ca-certificates From dccbb1062d4e2ea3aae3ea22765495056eb4c14b Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 9 Dec 2019 16:50:28 +0800 Subject: [PATCH 04/11] Fix a typo --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 501c9b1..12d0c64 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM alpine:3.10 LABEL "maintainer"="dev@anchore.com" LABEL "commit"=$COMMIT -LABEL "source"="https://github.com/anchore/harbor-scanner-adapter +LABEL "source"="https://github.com/anchore/harbor-scanner-adapter" RUN apk update && apk add --no-cache curl bash ca-certificates && update-ca-certificates From 1804790551df21842cc7146f2822e81046212489 Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 23 Dec 2019 11:11:19 +0800 Subject: [PATCH 05/11] Apply the factory pattern to load the credential --- go.mod | 1 + pkg/adapter/anchore/client/client.go | 80 +---------------- pkg/adapter/anchore/credential/awsloader.go | 89 +++++++++++++++++++ .../anchore/credential/defaultloader.go | 7 ++ pkg/adapter/anchore/credential/factory.go | 17 ++++ 5 files changed, 118 insertions(+), 76 deletions(-) create mode 100644 pkg/adapter/anchore/credential/awsloader.go create mode 100644 pkg/adapter/anchore/credential/defaultloader.go create mode 100644 pkg/adapter/anchore/credential/factory.go diff --git a/go.mod b/go.mod index fd5dc4a..0e7dcd1 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/anchore/harbor-scanner-adapter go 1.12 require ( + github.com/aws/aws-sdk-go v1.25.48 github.com/elazarl/goproxy v0.0.0-20190711103511-473e67f1d7d2 // indirect github.com/elazarl/goproxy/ext v0.0.0-20191011121108-aa519ddbe484 // indirect github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc diff --git a/pkg/adapter/anchore/client/client.go b/pkg/adapter/anchore/client/client.go index 90622f9..8f28fae 100644 --- a/pkg/adapter/anchore/client/client.go +++ b/pkg/adapter/anchore/client/client.go @@ -11,7 +11,7 @@ import ( "strconv" "strings" "time" - + "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/credential" "github.com/anchore/harbor-scanner-adapter/pkg/model/anchore" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" @@ -43,85 +43,13 @@ type ClientConfig struct { } func getNewRequest(clientConfiguration *ClientConfig) *gorequest.SuperAgent { - reloadCredential(clientConfiguration) + credenitalLoader := factory.CreateCredentialLoader(clientConfiguration) + credenitalLoader.load() + timeout := time.Duration(clientConfiguration.TimeoutSeconds) * time.Second return gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: clientConfiguration.TLSVerify}).SetBasicAuth(clientConfiguration.Username, clientConfiguration.Password).Timeout(timeout) } -// Reload the anchore user name and password if AWS Secret Manager is used -func reloadCredential(clientConfiguration *ClientConfig) { - if strings.HasPrefix(clientConfiguration.Username, "aws:secretmanager") { - log.Debug("Start to load user name from AWS Secret Manager") - if getAWSSecret(clientConfiguration.Username) != "" { - clientConfiguration.Username = getAWSSecret(clientConfiguration.Username) - } - } - if strings.HasPrefix(clientConfiguration.Password, "aws:secretmanager") { - log.Debug("Start to load password from AWS Secret Manager") - if getAWSSecret(clientConfiguration.Password) != "" { - clientConfiguration.Password = getAWSSecret(clientConfiguration.Password) - } - } -} - -func getAWSSecret(configValue string) string { - // The expected format is aws:secretmanager:: - fileds := strings.Split(configValue, ":") - region, name, key := fileds[2], fileds[3], fileds[4] - - log.WithFields(log.Fields{"region": region, "name": name, "key": key}).Debug("pass in secret manager parameters") - - //Create a Secrets Manager client - svc := secretsmanager.New(session.New(), &aws.Config{Region: aws.String(region)}) - input := &secretsmanager.GetSecretValueInput{ - SecretId: aws.String(name), - VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified - } - - result, err := svc.GetSecretValue(input) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case secretsmanager.ErrCodeDecryptionFailure: - // Secrets Manager can't decrypt the protected secret text using the provided KMS key. - fmt.Println(secretsmanager.ErrCodeDecryptionFailure, aerr.Error()) - - case secretsmanager.ErrCodeInternalServiceError: - // An error occurred on the server side. - fmt.Println(secretsmanager.ErrCodeInternalServiceError, aerr.Error()) - - case secretsmanager.ErrCodeInvalidParameterException: - // You provided an invalid value for a parameter. - fmt.Println(secretsmanager.ErrCodeInvalidParameterException, aerr.Error()) - - case secretsmanager.ErrCodeInvalidRequestException: - // You provided a parameter value that is not valid for the current state of the resource. - fmt.Println(secretsmanager.ErrCodeInvalidRequestException, aerr.Error()) - - case secretsmanager.ErrCodeResourceNotFoundException: - // We can't find the resource that you asked for. - fmt.Println(secretsmanager.ErrCodeResourceNotFoundException, aerr.Error()) - } - } else { - // Print the error, cast err to awserr.Error to get the Code and - // Message from an error. - fmt.Println(err.Error()) - } - } else { - // Decrypts secret using the associated KMS CMK. - var secretString string - if result.SecretString != nil { - secretString = *result.SecretString - // a map container to decode the JSON structure into - kmap := make(map[string]string) - json.Unmarshal([]byte(secretString), &kmap) - return kmap[key] - } - } - - return "" -} - // Handle error responses generically func unmarshalError(body []byte, response gorequest.Response) (anchore.Error, error) { result := anchore.Error{} diff --git a/pkg/adapter/anchore/credential/awsloader.go b/pkg/adapter/anchore/credential/awsloader.go new file mode 100644 index 0000000..c4a9064 --- /dev/null +++ b/pkg/adapter/anchore/credential/awsloader.go @@ -0,0 +1,89 @@ +package credential + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/client" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/secretsmanager" + log "github.com/sirupsen/logrus" +) + +type AWSCredenitalLoader struct{} + +func (c *AWSCredenitalLoader) load(clientConfiguration client.ClientConfig) { + if strings.HasPrefix(clientConfiguration.Username, "aws:secretmanager") { + log.Debug("Start to load user name from AWS Secret Manager") + if getAWSSecret(clientConfiguration.Username) != "" { + clientConfiguration.Username = getAWSSecret(clientConfiguration.Username) + } + } + if strings.HasPrefix(clientConfiguration.Password, "aws:secretmanager") { + log.Debug("Start to load password from AWS Secret Manager") + if getAWSSecret(clientConfiguration.Password) != "" { + clientConfiguration.Password = getAWSSecret(clientConfiguration.Password) + } + } +} + +func getAWSSecret(configValue string) string { + // The expected format is aws:secretmanager::: + fileds := strings.Split(configValue, ":") + region, name, key := fileds[2], fileds[3], fileds[4] + + log.WithFields(log.Fields{"region": region, "name": name, "key": key}).Debug("pass in secret manager parameters") + + //Create a Secrets Manager client + svc := secretsmanager.New(session.New(), &aws.Config{Region: aws.String(region)}) + input := &secretsmanager.GetSecretValueInput{ + SecretId: aws.String(name), + VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified + } + + result, err := svc.GetSecretValue(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case secretsmanager.ErrCodeDecryptionFailure: + // Secrets Manager can't decrypt the protected secret text using the provided KMS key. + fmt.Println(secretsmanager.ErrCodeDecryptionFailure, aerr.Error()) + + case secretsmanager.ErrCodeInternalServiceError: + // An error occurred on the server side. + fmt.Println(secretsmanager.ErrCodeInternalServiceError, aerr.Error()) + + case secretsmanager.ErrCodeInvalidParameterException: + // You provided an invalid value for a parameter. + fmt.Println(secretsmanager.ErrCodeInvalidParameterException, aerr.Error()) + + case secretsmanager.ErrCodeInvalidRequestException: + // You provided a parameter value that is not valid for the current state of the resource. + fmt.Println(secretsmanager.ErrCodeInvalidRequestException, aerr.Error()) + + case secretsmanager.ErrCodeResourceNotFoundException: + // We can't find the resource that you asked for. + fmt.Println(secretsmanager.ErrCodeResourceNotFoundException, aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + } else { + // Decrypts secret using the associated KMS CMK. + var secretString string + if result.SecretString != nil { + secretString = *result.SecretString + // a map container to decode the JSON structure into + kmap := make(map[string]string) + json.Unmarshal([]byte(secretString), &kmap) + return kmap[key] + } + } + + return "" +} diff --git a/pkg/adapter/anchore/credential/defaultloader.go b/pkg/adapter/anchore/credential/defaultloader.go new file mode 100644 index 0000000..2398909 --- /dev/null +++ b/pkg/adapter/anchore/credential/defaultloader.go @@ -0,0 +1,7 @@ +package credential + +import "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/client" + +type DefaultCredenitalLoader struct{} + +func (c *DefaultCredenitalLoader) load(client.ClientConfig) {} diff --git a/pkg/adapter/anchore/credential/factory.go b/pkg/adapter/anchore/credential/factory.go new file mode 100644 index 0000000..c6f027c --- /dev/null +++ b/pkg/adapter/anchore/credential/factory.go @@ -0,0 +1,17 @@ +package credential + +import ( + "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/client" + "strings" +) + +type CredentialLoader interface { + load(client.ClientConfig) +} + +func CreateCredentialLoader(clientConfiguration client.ClientConfig) CredentialLoader { + if strings.HasPrefix(clientConfiguration.Password, "aws:secretmanager") { + return &AWSCredenitalLoader{} + } + return &DefaultCredenitalLoader +} From 8cc17c5e380f06e1400445eb7c4e373382a5b7fc Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 23 Dec 2019 11:22:33 +0800 Subject: [PATCH 06/11] fix import cycle --- pkg/adapter/anchore/client/client.go | 2 +- pkg/adapter/anchore/credential/awsloader.go | 16 +++++----------- pkg/adapter/anchore/credential/defaultloader.go | 4 +++- pkg/adapter/anchore/credential/factory.go | 7 +++---- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/pkg/adapter/anchore/client/client.go b/pkg/adapter/anchore/client/client.go index 8f28fae..7a15e80 100644 --- a/pkg/adapter/anchore/client/client.go +++ b/pkg/adapter/anchore/client/client.go @@ -44,7 +44,7 @@ type ClientConfig struct { func getNewRequest(clientConfiguration *ClientConfig) *gorequest.SuperAgent { credenitalLoader := factory.CreateCredentialLoader(clientConfiguration) - credenitalLoader.load() + clientConfiguration.Password = credenitalLoader.load() timeout := time.Duration(clientConfiguration.TimeoutSeconds) * time.Second return gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: clientConfiguration.TLSVerify}).SetBasicAuth(clientConfiguration.Username, clientConfiguration.Password).Timeout(timeout) diff --git a/pkg/adapter/anchore/credential/awsloader.go b/pkg/adapter/anchore/credential/awsloader.go index c4a9064..5cc90ae 100644 --- a/pkg/adapter/anchore/credential/awsloader.go +++ b/pkg/adapter/anchore/credential/awsloader.go @@ -5,7 +5,6 @@ import ( "fmt" "strings" - "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/client" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/session" @@ -15,19 +14,14 @@ import ( type AWSCredenitalLoader struct{} -func (c *AWSCredenitalLoader) load(clientConfiguration client.ClientConfig) { - if strings.HasPrefix(clientConfiguration.Username, "aws:secretmanager") { - log.Debug("Start to load user name from AWS Secret Manager") - if getAWSSecret(clientConfiguration.Username) != "" { - clientConfiguration.Username = getAWSSecret(clientConfiguration.Username) - } - } - if strings.HasPrefix(clientConfiguration.Password, "aws:secretmanager") { +func (c *AWSCredenitalLoader) load(key string) string { + if strings.HasPrefix(key, "aws:secretmanager") { log.Debug("Start to load password from AWS Secret Manager") - if getAWSSecret(clientConfiguration.Password) != "" { - clientConfiguration.Password = getAWSSecret(clientConfiguration.Password) + if getAWSSecret(key) != "" { + return getAWSSecret(key) } } + return key } func getAWSSecret(configValue string) string { diff --git a/pkg/adapter/anchore/credential/defaultloader.go b/pkg/adapter/anchore/credential/defaultloader.go index 2398909..7a2115a 100644 --- a/pkg/adapter/anchore/credential/defaultloader.go +++ b/pkg/adapter/anchore/credential/defaultloader.go @@ -4,4 +4,6 @@ import "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/client" type DefaultCredenitalLoader struct{} -func (c *DefaultCredenitalLoader) load(client.ClientConfig) {} +func (c *DefaultCredenitalLoader) load(key string) { + return key +} diff --git a/pkg/adapter/anchore/credential/factory.go b/pkg/adapter/anchore/credential/factory.go index c6f027c..af9b64e 100644 --- a/pkg/adapter/anchore/credential/factory.go +++ b/pkg/adapter/anchore/credential/factory.go @@ -1,16 +1,15 @@ package credential import ( - "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/client" "strings" ) type CredentialLoader interface { - load(client.ClientConfig) + load(string) string } -func CreateCredentialLoader(clientConfiguration client.ClientConfig) CredentialLoader { - if strings.HasPrefix(clientConfiguration.Password, "aws:secretmanager") { +func CreateCredentialLoader(key string) CredentialLoader { + if strings.HasPrefix(key, "aws:secretmanager") { return &AWSCredenitalLoader{} } return &DefaultCredenitalLoader From ef8106075a3af26638bfa1af0aac13680ebd6ad9 Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 23 Dec 2019 11:26:51 +0800 Subject: [PATCH 07/11] cleanup import --- pkg/adapter/anchore/client/client.go | 4 ---- pkg/adapter/anchore/credential/defaultloader.go | 2 -- 2 files changed, 6 deletions(-) diff --git a/pkg/adapter/anchore/client/client.go b/pkg/adapter/anchore/client/client.go index 7a15e80..33f0119 100644 --- a/pkg/adapter/anchore/client/client.go +++ b/pkg/adapter/anchore/client/client.go @@ -13,10 +13,6 @@ import ( "time" "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/credential" "github.com/anchore/harbor-scanner-adapter/pkg/model/anchore" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/secretsmanager" "github.com/parnurzeal/gorequest" log "github.com/sirupsen/logrus" ) diff --git a/pkg/adapter/anchore/credential/defaultloader.go b/pkg/adapter/anchore/credential/defaultloader.go index 7a2115a..dc4baff 100644 --- a/pkg/adapter/anchore/credential/defaultloader.go +++ b/pkg/adapter/anchore/credential/defaultloader.go @@ -1,7 +1,5 @@ package credential -import "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/client" - type DefaultCredenitalLoader struct{} func (c *DefaultCredenitalLoader) load(key string) { From c6e1556119ce9b4af4c5f2c3fa48525c75d3f0fe Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 23 Dec 2019 11:30:54 +0800 Subject: [PATCH 08/11] Fix typo --- pkg/adapter/anchore/credential/defaultloader.go | 2 +- pkg/adapter/anchore/credential/factory.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/adapter/anchore/credential/defaultloader.go b/pkg/adapter/anchore/credential/defaultloader.go index dc4baff..f0dc7a8 100644 --- a/pkg/adapter/anchore/credential/defaultloader.go +++ b/pkg/adapter/anchore/credential/defaultloader.go @@ -2,6 +2,6 @@ package credential type DefaultCredenitalLoader struct{} -func (c *DefaultCredenitalLoader) load(key string) { +func (c *DefaultCredenitalLoader) load(key string) string { return key } diff --git a/pkg/adapter/anchore/credential/factory.go b/pkg/adapter/anchore/credential/factory.go index af9b64e..c43667c 100644 --- a/pkg/adapter/anchore/credential/factory.go +++ b/pkg/adapter/anchore/credential/factory.go @@ -12,5 +12,5 @@ func CreateCredentialLoader(key string) CredentialLoader { if strings.HasPrefix(key, "aws:secretmanager") { return &AWSCredenitalLoader{} } - return &DefaultCredenitalLoader + return &DefaultCredenitalLoader{} } From 222e00b9900fc4a1d6a61bf6233cd496c3fb9210 Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 23 Dec 2019 11:35:46 +0800 Subject: [PATCH 09/11] Fix the credential factory usage --- pkg/adapter/anchore/client/client.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/adapter/anchore/client/client.go b/pkg/adapter/anchore/client/client.go index 33f0119..c5db395 100644 --- a/pkg/adapter/anchore/client/client.go +++ b/pkg/adapter/anchore/client/client.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" "time" + "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/credential" "github.com/anchore/harbor-scanner-adapter/pkg/model/anchore" "github.com/parnurzeal/gorequest" @@ -39,8 +40,8 @@ type ClientConfig struct { } func getNewRequest(clientConfiguration *ClientConfig) *gorequest.SuperAgent { - credenitalLoader := factory.CreateCredentialLoader(clientConfiguration) - clientConfiguration.Password = credenitalLoader.load() + credenitalLoader := credential.CreateCredentialLoader(clientConfiguration.Password) + clientConfiguration.Password = credenitalLoader.load(clientConfiguration.Password) timeout := time.Duration(clientConfiguration.TimeoutSeconds) * time.Second return gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: clientConfiguration.TLSVerify}).SetBasicAuth(clientConfiguration.Username, clientConfiguration.Password).Timeout(timeout) From 95da945188b5a1dfec1f246a8014e8a91b874028 Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 23 Dec 2019 14:10:34 +0800 Subject: [PATCH 10/11] Change the method name to LoadFromCredentialStore --- pkg/adapter/anchore/client/client.go | 5 +++-- pkg/adapter/anchore/credential/awsloader.go | 11 ++++++----- pkg/adapter/anchore/credential/defaultloader.go | 4 ++-- pkg/adapter/anchore/credential/factory.go | 6 +++--- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/pkg/adapter/anchore/client/client.go b/pkg/adapter/anchore/client/client.go index c5db395..de679af 100644 --- a/pkg/adapter/anchore/client/client.go +++ b/pkg/adapter/anchore/client/client.go @@ -40,8 +40,9 @@ type ClientConfig struct { } func getNewRequest(clientConfiguration *ClientConfig) *gorequest.SuperAgent { - credenitalLoader := credential.CreateCredentialLoader(clientConfiguration.Password) - clientConfiguration.Password = credenitalLoader.load(clientConfiguration.Password) + passwordConfig := clientConfiguration.Password + credenitalLoader := credential.CreateCredentialLoader(passwordConfig) + clientConfiguration.Password = credenitalLoader.LoadFromCredentialStore(passwordConfig) timeout := time.Duration(clientConfiguration.TimeoutSeconds) * time.Second return gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: clientConfiguration.TLSVerify}).SetBasicAuth(clientConfiguration.Username, clientConfiguration.Password).Timeout(timeout) diff --git a/pkg/adapter/anchore/credential/awsloader.go b/pkg/adapter/anchore/credential/awsloader.go index 5cc90ae..0d8b1a1 100644 --- a/pkg/adapter/anchore/credential/awsloader.go +++ b/pkg/adapter/anchore/credential/awsloader.go @@ -14,14 +14,15 @@ import ( type AWSCredenitalLoader struct{} -func (c *AWSCredenitalLoader) load(key string) string { - if strings.HasPrefix(key, "aws:secretmanager") { +func (c *AWSCredenitalLoader) LoadFromCredentialStore(passwordConfig string) string { + if strings.HasPrefix(passwordConfig, "aws:secretmanager") { log.Debug("Start to load password from AWS Secret Manager") - if getAWSSecret(key) != "" { - return getAWSSecret(key) + value := getAWSSecret(passwordConfig) + if value != "" { + return value } } - return key + return passwordConfig } func getAWSSecret(configValue string) string { diff --git a/pkg/adapter/anchore/credential/defaultloader.go b/pkg/adapter/anchore/credential/defaultloader.go index f0dc7a8..7632149 100644 --- a/pkg/adapter/anchore/credential/defaultloader.go +++ b/pkg/adapter/anchore/credential/defaultloader.go @@ -2,6 +2,6 @@ package credential type DefaultCredenitalLoader struct{} -func (c *DefaultCredenitalLoader) load(key string) string { - return key +func (c *DefaultCredenitalLoader) LoadFromCredentialStore(passwordConfig string) string { + return passwordConfig } diff --git a/pkg/adapter/anchore/credential/factory.go b/pkg/adapter/anchore/credential/factory.go index c43667c..5485b68 100644 --- a/pkg/adapter/anchore/credential/factory.go +++ b/pkg/adapter/anchore/credential/factory.go @@ -5,11 +5,11 @@ import ( ) type CredentialLoader interface { - load(string) string + LoadFromCredentialStore(passwordConfig string) string } -func CreateCredentialLoader(key string) CredentialLoader { - if strings.HasPrefix(key, "aws:secretmanager") { +func CreateCredentialLoader(passwordConfig string) CredentialLoader { + if strings.HasPrefix(passwordConfig, "aws:secretmanager") { return &AWSCredenitalLoader{} } return &DefaultCredenitalLoader{} From 527fce397bee3c7efb5285cf783f1fa11c59edf2 Mon Sep 17 00:00:00 2001 From: Ye Liu Date: Mon, 9 Dec 2019 10:02:05 +0800 Subject: [PATCH 11/11] Enable reading credential from aws secret manager --- go.mod | 1 + pkg/adapter/anchore/client/client.go | 12 ++- pkg/adapter/anchore/credential/awsloader.go | 84 +++++++++++++++++++ .../anchore/credential/defaultloader.go | 7 ++ pkg/adapter/anchore/credential/factory.go | 16 ++++ 5 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 pkg/adapter/anchore/credential/awsloader.go create mode 100644 pkg/adapter/anchore/credential/defaultloader.go create mode 100644 pkg/adapter/anchore/credential/factory.go diff --git a/go.mod b/go.mod index fd5dc4a..0e7dcd1 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/anchore/harbor-scanner-adapter go 1.12 require ( + github.com/aws/aws-sdk-go v1.25.48 github.com/elazarl/goproxy v0.0.0-20190711103511-473e67f1d7d2 // indirect github.com/elazarl/goproxy/ext v0.0.0-20191011121108-aa519ddbe484 // indirect github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc diff --git a/pkg/adapter/anchore/client/client.go b/pkg/adapter/anchore/client/client.go index 1c3886d..de679af 100644 --- a/pkg/adapter/anchore/client/client.go +++ b/pkg/adapter/anchore/client/client.go @@ -4,9 +4,6 @@ import ( "crypto/tls" "encoding/json" "fmt" - "github.com/anchore/harbor-scanner-adapter/pkg/model/anchore" - "github.com/parnurzeal/gorequest" - log "github.com/sirupsen/logrus" "math" "net/url" "path" @@ -14,6 +11,11 @@ import ( "strconv" "strings" "time" + + "github.com/anchore/harbor-scanner-adapter/pkg/adapter/anchore/credential" + "github.com/anchore/harbor-scanner-adapter/pkg/model/anchore" + "github.com/parnurzeal/gorequest" + log "github.com/sirupsen/logrus" ) const ( @@ -38,6 +40,10 @@ type ClientConfig struct { } func getNewRequest(clientConfiguration *ClientConfig) *gorequest.SuperAgent { + passwordConfig := clientConfiguration.Password + credenitalLoader := credential.CreateCredentialLoader(passwordConfig) + clientConfiguration.Password = credenitalLoader.LoadFromCredentialStore(passwordConfig) + timeout := time.Duration(clientConfiguration.TimeoutSeconds) * time.Second return gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: clientConfiguration.TLSVerify}).SetBasicAuth(clientConfiguration.Username, clientConfiguration.Password).Timeout(timeout) } diff --git a/pkg/adapter/anchore/credential/awsloader.go b/pkg/adapter/anchore/credential/awsloader.go new file mode 100644 index 0000000..0d8b1a1 --- /dev/null +++ b/pkg/adapter/anchore/credential/awsloader.go @@ -0,0 +1,84 @@ +package credential + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/secretsmanager" + log "github.com/sirupsen/logrus" +) + +type AWSCredenitalLoader struct{} + +func (c *AWSCredenitalLoader) LoadFromCredentialStore(passwordConfig string) string { + if strings.HasPrefix(passwordConfig, "aws:secretmanager") { + log.Debug("Start to load password from AWS Secret Manager") + value := getAWSSecret(passwordConfig) + if value != "" { + return value + } + } + return passwordConfig +} + +func getAWSSecret(configValue string) string { + // The expected format is aws:secretmanager::: + fileds := strings.Split(configValue, ":") + region, name, key := fileds[2], fileds[3], fileds[4] + + log.WithFields(log.Fields{"region": region, "name": name, "key": key}).Debug("pass in secret manager parameters") + + //Create a Secrets Manager client + svc := secretsmanager.New(session.New(), &aws.Config{Region: aws.String(region)}) + input := &secretsmanager.GetSecretValueInput{ + SecretId: aws.String(name), + VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified + } + + result, err := svc.GetSecretValue(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case secretsmanager.ErrCodeDecryptionFailure: + // Secrets Manager can't decrypt the protected secret text using the provided KMS key. + fmt.Println(secretsmanager.ErrCodeDecryptionFailure, aerr.Error()) + + case secretsmanager.ErrCodeInternalServiceError: + // An error occurred on the server side. + fmt.Println(secretsmanager.ErrCodeInternalServiceError, aerr.Error()) + + case secretsmanager.ErrCodeInvalidParameterException: + // You provided an invalid value for a parameter. + fmt.Println(secretsmanager.ErrCodeInvalidParameterException, aerr.Error()) + + case secretsmanager.ErrCodeInvalidRequestException: + // You provided a parameter value that is not valid for the current state of the resource. + fmt.Println(secretsmanager.ErrCodeInvalidRequestException, aerr.Error()) + + case secretsmanager.ErrCodeResourceNotFoundException: + // We can't find the resource that you asked for. + fmt.Println(secretsmanager.ErrCodeResourceNotFoundException, aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + } else { + // Decrypts secret using the associated KMS CMK. + var secretString string + if result.SecretString != nil { + secretString = *result.SecretString + // a map container to decode the JSON structure into + kmap := make(map[string]string) + json.Unmarshal([]byte(secretString), &kmap) + return kmap[key] + } + } + + return "" +} diff --git a/pkg/adapter/anchore/credential/defaultloader.go b/pkg/adapter/anchore/credential/defaultloader.go new file mode 100644 index 0000000..7632149 --- /dev/null +++ b/pkg/adapter/anchore/credential/defaultloader.go @@ -0,0 +1,7 @@ +package credential + +type DefaultCredenitalLoader struct{} + +func (c *DefaultCredenitalLoader) LoadFromCredentialStore(passwordConfig string) string { + return passwordConfig +} diff --git a/pkg/adapter/anchore/credential/factory.go b/pkg/adapter/anchore/credential/factory.go new file mode 100644 index 0000000..5485b68 --- /dev/null +++ b/pkg/adapter/anchore/credential/factory.go @@ -0,0 +1,16 @@ +package credential + +import ( + "strings" +) + +type CredentialLoader interface { + LoadFromCredentialStore(passwordConfig string) string +} + +func CreateCredentialLoader(passwordConfig string) CredentialLoader { + if strings.HasPrefix(passwordConfig, "aws:secretmanager") { + return &AWSCredenitalLoader{} + } + return &DefaultCredenitalLoader{} +}