Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft implementation for Issue #7 with aws secret manager #16

Merged
merged 12 commits into from
Mar 21, 2020
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 9 additions & 3 deletions pkg/adapter/anchore/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ 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"
"sort"
"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 (
Expand All @@ -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)
}
Expand Down
84 changes: 84 additions & 0 deletions pkg/adapter/anchore/credential/awsloader.go
Original file line number Diff line number Diff line change
@@ -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:<region>:<secret name>:<secret key>
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 ""
}
7 changes: 7 additions & 0 deletions pkg/adapter/anchore/credential/defaultloader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package credential

type DefaultCredenitalLoader struct{}

func (c *DefaultCredenitalLoader) LoadFromCredentialStore(passwordConfig string) string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to make the secret/cred configuration more explicit rather than an encoded value in the password, but I think we can start with this as a draft and follow-up with another commit to change that behavior before a release is pushed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we can talk after Feb 3 as I will be in Chinese new year holiday from next week. I'd like to hear more ideas from you ;-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have a great new year holiday! We'll sync up when you return.

return passwordConfig
}
16 changes: 16 additions & 0 deletions pkg/adapter/anchore/credential/factory.go
Original file line number Diff line number Diff line change
@@ -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{}
}