github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/creds/secretsmanager/secretsmanager.go (about) 1 package secretsmanager 2 3 import ( 4 "encoding/json" 5 "time" 6 7 "github.com/pf-qiu/concourse/v6/atc/creds" 8 9 "code.cloudfoundry.org/lager" 10 "github.com/aws/aws-sdk-go/aws/awserr" 11 "github.com/aws/aws-sdk-go/service/secretsmanager" 12 "github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface" 13 ) 14 15 type SecretsManager struct { 16 log lager.Logger 17 api secretsmanageriface.SecretsManagerAPI 18 secretTemplates []*creds.SecretTemplate 19 } 20 21 func NewSecretsManager(log lager.Logger, api secretsmanageriface.SecretsManagerAPI, secretTemplates []*creds.SecretTemplate) *SecretsManager { 22 return &SecretsManager{ 23 log: log, 24 api: api, 25 secretTemplates: secretTemplates, 26 } 27 } 28 29 // NewSecretLookupPaths defines how variables will be searched in the underlying secret manager 30 func (s *SecretsManager) NewSecretLookupPaths(teamName string, pipelineName string, allowRootPath bool) []creds.SecretLookupPath { 31 lookupPaths := []creds.SecretLookupPath{} 32 for _, tmpl := range s.secretTemplates { 33 if lPath := creds.NewSecretLookupWithTemplate(tmpl, teamName, pipelineName); lPath != nil { 34 lookupPaths = append(lookupPaths, lPath) 35 } 36 } 37 return lookupPaths 38 } 39 40 // Get retrieves the value and expiration of an individual secret 41 func (s *SecretsManager) Get(secretPath string) (interface{}, *time.Time, bool, error) { 42 value, expiration, found, err := s.getSecretById(secretPath) 43 if err != nil { 44 s.log.Error("failed-to-fetch-aws-secret", err, lager.Data{ 45 "secret-path": secretPath, 46 }) 47 return nil, nil, false, err 48 } 49 if found { 50 return value, expiration, true, nil 51 } 52 return nil, nil, false, nil 53 } 54 55 /* 56 Looks up secret by path. Depending on which field is filled it will either 57 return a string value (SecretString) or a map[string]interface{} (SecretBinary). 58 59 In case SecretBinary is set, it is expected to be a valid JSON object or it will error. 60 */ 61 func (s *SecretsManager) getSecretById(path string) (interface{}, *time.Time, bool, error) { 62 value, err := s.api.GetSecretValue(&secretsmanager.GetSecretValueInput{ 63 SecretId: &path, 64 }) 65 if err == nil { 66 switch { 67 case value.SecretString != nil: 68 return *value.SecretString, nil, true, nil 69 case value.SecretBinary != nil: 70 values, err := decodeJsonValue(value.SecretBinary) 71 if err != nil { 72 return nil, nil, true, err 73 } 74 return values, nil, true, nil 75 } 76 } else if errObj, ok := err.(awserr.Error); ok && errObj.Code() == secretsmanager.ErrCodeResourceNotFoundException { 77 return nil, nil, false, nil 78 } 79 80 return nil, nil, false, err 81 } 82 83 func decodeJsonValue(data []byte) (map[string]interface{}, error) { 84 var values map[string]interface{} 85 if err := json.Unmarshal(data, &values); err != nil { 86 return nil, err 87 } 88 return values, nil 89 }