github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/creds/ssm/manager.go (about) 1 package ssm 2 3 import ( 4 "encoding/json" 5 "errors" 6 "strings" 7 8 "code.cloudfoundry.org/lager" 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/aws/awserr" 11 "github.com/aws/aws-sdk-go/aws/credentials" 12 "github.com/aws/aws-sdk-go/aws/session" 13 "github.com/aws/aws-sdk-go/service/ssm" 14 "github.com/pf-qiu/concourse/v6/atc/creds" 15 ) 16 17 const DefaultPipelineSecretTemplate = "/concourse/{{.Team}}/{{.Pipeline}}/{{.Secret}}" 18 const DefaultTeamSecretTemplate = "/concourse/{{.Team}}/{{.Secret}}" 19 20 type SsmManager struct { 21 AwsAccessKeyID string `mapstructure:"access_key" long:"access-key" description:"AWS Access key ID"` 22 AwsSecretAccessKey string `mapstructure:"secret_key" long:"secret-key" description:"AWS Secret Access Key"` 23 AwsSessionToken string `mapstructure:"session_token" long:"session-token" description:"AWS Session Token"` 24 AwsRegion string `mapstructure:"region" long:"region" description:"AWS region to send requests to"` 25 PipelineSecretTemplate string `mapstructure:"pipeline_secret_template" long:"pipeline-secret-template" description:"AWS SSM parameter name template used for pipeline specific parameter" default:"/concourse/{{.Team}}/{{.Pipeline}}/{{.Secret}}"` 26 TeamSecretTemplate string `mapstructure:"team_secret_template" long:"team-secret-template" description:"AWS SSM parameter name template used for team specific parameter" default:"/concourse/{{.Team}}/{{.Secret}}"` 27 Ssm *Ssm 28 } 29 30 func (manager *SsmManager) MarshalJSON() ([]byte, error) { 31 health, err := manager.Health() 32 if err != nil { 33 return nil, err 34 } 35 36 return json.Marshal(&map[string]interface{}{ 37 "aws_region": manager.AwsRegion, 38 "pipeline_secret_template": manager.PipelineSecretTemplate, 39 "team_secret_template": manager.TeamSecretTemplate, 40 "health": health, 41 }) 42 } 43 44 func (manager *SsmManager) Init(log lager.Logger) error { 45 session, err := manager.getSession() 46 if err != nil { 47 log.Error("failed-to-create-aws-session", err) 48 return err 49 } 50 51 manager.Ssm = &Ssm{ 52 api: ssm.New(session), 53 } 54 55 return nil 56 } 57 58 func (manager *SsmManager) getSession() (*session.Session, error) { 59 60 config := &aws.Config{Region: &manager.AwsRegion} 61 if manager.AwsAccessKeyID != "" { 62 config.Credentials = credentials.NewStaticCredentials(manager.AwsAccessKeyID, manager.AwsSecretAccessKey, manager.AwsSessionToken) 63 } 64 65 return session.NewSession(config) 66 } 67 68 func (manager *SsmManager) Health() (*creds.HealthResponse, error) { 69 health := &creds.HealthResponse{ 70 Method: "GetParameter", 71 } 72 73 _, _, _, err := manager.Ssm.getParameterByName("__concourse-health-check") 74 if err != nil { 75 if errObj, ok := err.(awserr.Error); ok && strings.Contains(errObj.Code(), "AccessDenied") { 76 health.Response = map[string]string{ 77 "status": "UP", 78 } 79 80 return health, nil 81 } 82 83 health.Error = err.Error() 84 return health, nil 85 } 86 87 health.Response = map[string]string{ 88 "status": "UP", 89 } 90 91 return health, nil 92 } 93 94 func (manager *SsmManager) IsConfigured() bool { 95 return manager.AwsRegion != "" 96 } 97 98 func (manager *SsmManager) Validate() error { 99 if _, err := creds.BuildSecretTemplate("pipeline-secret-template", manager.PipelineSecretTemplate); err != nil { 100 return err 101 } 102 103 if _, err := creds.BuildSecretTemplate("team-secret-template", manager.TeamSecretTemplate); err != nil { 104 return err 105 } 106 107 // All of the AWS credential variables may be empty since credentials may be obtained via environemnt variables 108 // or other means. However, if one of them is provided, then all of them (except session token) must be provided. 109 if manager.AwsAccessKeyID == "" && manager.AwsSecretAccessKey == "" && manager.AwsSessionToken == "" { 110 return nil 111 } 112 113 if manager.AwsAccessKeyID == "" { 114 return errors.New("must provide aws access key id") 115 } 116 117 if manager.AwsSecretAccessKey == "" { 118 return errors.New("must provide aws secret access key") 119 } 120 121 return nil 122 } 123 124 func (manager *SsmManager) NewSecretsFactory(log lager.Logger) (creds.SecretsFactory, error) { 125 126 session, err := manager.getSession() 127 if err != nil { 128 log.Error("failed-to-create-aws-session", err) 129 return nil, err 130 } 131 132 pipelineSecretTemplate, err := creds.BuildSecretTemplate("pipeline-secret-template", manager.PipelineSecretTemplate) 133 if err != nil { 134 return nil, err 135 } 136 137 teamSecretTemplate, err := creds.BuildSecretTemplate("team-secret-template", manager.TeamSecretTemplate) 138 if err != nil { 139 return nil, err 140 } 141 142 return NewSsmFactory(log, session, []*creds.SecretTemplate{pipelineSecretTemplate, teamSecretTemplate}), nil 143 } 144 145 func (manager *SsmManager) Close(logger lager.Logger) { 146 // TODO - to implement 147 }