github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/creds/ssm/ssm.go (about) 1 package ssm 2 3 import ( 4 "strings" 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" 11 "github.com/aws/aws-sdk-go/aws/awserr" 12 "github.com/aws/aws-sdk-go/service/ssm" 13 "github.com/aws/aws-sdk-go/service/ssm/ssmiface" 14 ) 15 16 type Ssm struct { 17 log lager.Logger 18 api ssmiface.SSMAPI 19 secretTemplates []*creds.SecretTemplate 20 } 21 22 func NewSsm(log lager.Logger, api ssmiface.SSMAPI, secretTemplates []*creds.SecretTemplate) *Ssm { 23 return &Ssm{ 24 log: log, 25 api: api, 26 secretTemplates: secretTemplates, 27 } 28 } 29 30 // NewSecretLookupPaths defines how variables will be searched in the underlying secret manager 31 func (s *Ssm) NewSecretLookupPaths(teamName string, pipelineName string, allowRootPath bool) []creds.SecretLookupPath { 32 lookupPaths := []creds.SecretLookupPath{} 33 for _, tmpl := range s.secretTemplates { 34 if lPath := creds.NewSecretLookupWithTemplate(tmpl, teamName, pipelineName); lPath != nil { 35 lookupPaths = append(lookupPaths, lPath) 36 } 37 } 38 return lookupPaths 39 } 40 41 // Get retrieves the value and expiration of an individual secret 42 func (s *Ssm) Get(secretPath string) (interface{}, *time.Time, bool, error) { 43 // Try to get the parameter as string value, by name 44 value, expiration, found, err := s.getParameterByName(secretPath) 45 if err != nil { 46 s.log.Error("unable to retrieve aws ssm secret by name", err, lager.Data{ 47 "secretPath": secretPath, 48 }) 49 return nil, nil, false, err 50 } 51 if found { 52 return value, expiration, true, nil 53 } 54 // Parameter may exist as a complex value so try again using parameter name as root path 55 value, expiration, found, err = s.getParameterByPath(secretPath) 56 if err != nil { 57 s.log.Error("unable to retrieve aws ssm secret by path", err, lager.Data{ 58 "secretPath": secretPath, 59 }) 60 return nil, nil, false, err 61 } 62 if found { 63 return value, expiration, true, nil 64 } 65 return nil, nil, false, nil 66 } 67 68 func (s *Ssm) getParameterByName(name string) (interface{}, *time.Time, bool, error) { 69 param, err := s.api.GetParameter(&ssm.GetParameterInput{ 70 Name: &name, 71 WithDecryption: aws.Bool(true), 72 }) 73 if err == nil { 74 return *param.Parameter.Value, nil, true, nil 75 76 } else if errObj, ok := err.(awserr.Error); ok && errObj.Code() == ssm.ErrCodeParameterNotFound { 77 return nil, nil, false, nil 78 } 79 return nil, nil, false, err 80 } 81 82 func (s *Ssm) getParameterByPath(path string) (interface{}, *time.Time, bool, error) { 83 path = strings.TrimRight(path, "/") 84 if path == "" { 85 path = "/" 86 } 87 value := make(map[string]interface{}) 88 pathQuery := &ssm.GetParametersByPathInput{} 89 pathQuery = pathQuery.SetPath(path).SetRecursive(true).SetWithDecryption(true).SetMaxResults(10) 90 err := s.api.GetParametersByPathPages(pathQuery, func(page *ssm.GetParametersByPathOutput, lastPage bool) bool { 91 for _, param := range page.Parameters { 92 value[(*param.Name)[len(path)+1:]] = *param.Value 93 } 94 return true 95 }) 96 if err != nil { 97 return nil, nil, false, err 98 } 99 if len(value) == 0 { 100 return nil, nil, false, nil 101 } 102 return value, nil, true, nil 103 }