diff --git a/README.md b/README.md index 73661d0..612aec1 100644 --- a/README.md +++ b/README.md @@ -73,8 +73,16 @@ differences: * `aws_region`: *Optional. Default `""`.* The region to use for accessing ECR. This is required if you are using ECR. This region will help determine the full repository URL you are accessing (e.g., `012345678910.dkr.ecr.us-east-1.amazonaws.com`) +* `aws_ec2_credentials`: *Optional. Default `false`.* If set, allows the retrieval of + AWS credentials from the EC2 metadata. + * `aws_role_arn`: *Optional. Default `""`.* If set, then this role will be - assumed before authenticating to ECR. + assumed before authenticating to ECR. It is overridden by `aws_role_arns` if + latter is also specified. This is kept for backward compatibility. + +* `aws_role_arns`: *Optional. Default `""`.* A comma-delimited list of AWS IAM roles. + If set, these roles will be assumed in the specified order before authenticating to ECR. + It overrides `aws_role_arn`. * `debug`: *Optional. Default `false`.* If set, progress bars will be disabled and debugging output will be printed instead. @@ -110,7 +118,7 @@ differences: This is used to validate the certificate of the docker registry when the registry's certificate is signed by a custom authority (or itself). -### Signing with Docker Hub +### Signing with Docker Hub Configure Docker Content Trust for use with the [Docker Hub](https:/hub.docker.io) and Notary service by specifying the above source parameters as follows: @@ -265,7 +273,7 @@ Fetches an image at the exact digest specified by the version. The resource will produce the following files: -* `./repository`: A file containing the image's full repository name, e.g. `concourse/concourse`. +* `./repository`: A file containing the image's full repository name, e.g. `concourse/concourse`. For ECR images, this will include the registry the image was pulled from. * `./tag`: A file containing the tag from the version. * `./digest`: A file containing the digest from the version, e.g. `sha256:...`. diff --git a/commands/check.go b/commands/check.go index 646ffba..d155af5 100644 --- a/commands/check.go +++ b/commands/check.go @@ -49,7 +49,8 @@ func (c *Check) Execute() error { return fmt.Errorf("invalid payload: %s", err) } - if req.Source.AwsAccessKeyId != "" && req.Source.AwsSecretAccessKey != "" && req.Source.AwsRegion != "" { + if ((req.Source.AwsAccessKeyId != "" && req.Source.AwsSecretAccessKey != "") || + (req.Source.AwsEC2Credentials)) && req.Source.AwsRegion != "" { if !req.Source.AuthenticateToECR() { return fmt.Errorf("cannot authenticate with ECR") } diff --git a/commands/in.go b/commands/in.go index cbffa4e..4ded5d0 100644 --- a/commands/in.go +++ b/commands/in.go @@ -65,7 +65,8 @@ func (i *In) Execute() error { dest := i.args[1] - if req.Source.AwsAccessKeyId != "" && req.Source.AwsSecretAccessKey != "" && req.Source.AwsRegion != "" { + if ((req.Source.AwsAccessKeyId != "" && req.Source.AwsSecretAccessKey != "") || + (req.Source.AwsEC2Credentials)) && req.Source.AwsRegion != "" { if !req.Source.AuthenticateToECR() { return fmt.Errorf("cannot authenticate with ECR") } diff --git a/commands/out.go b/commands/out.go index 03a8fa1..28a5e3d 100644 --- a/commands/out.go +++ b/commands/out.go @@ -62,7 +62,8 @@ func (o *Out) Execute() error { src := o.args[1] - if req.Source.AwsAccessKeyId != "" && req.Source.AwsSecretAccessKey != "" && req.Source.AwsRegion != "" { + if ((req.Source.AwsAccessKeyId != "" && req.Source.AwsSecretAccessKey != "") || + (req.Source.AwsEC2Credentials)) && req.Source.AwsRegion != "" { if !req.Source.AuthenticateToECR() { return fmt.Errorf("cannot authenticate with ECR") } diff --git a/types.go b/types.go index e9aade4..841c2df 100644 --- a/types.go +++ b/types.go @@ -15,7 +15,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go/aws/credentials/stscreds" + "github.com/aws/aws-sdk-go/aws/ec2metadata" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ecr" "github.com/aws/aws-sdk-go/service/ecr/ecriface" @@ -55,12 +57,14 @@ type OutResponse struct { } type AwsCredentials struct { + AwsEC2Credentials bool `json:"aws_ec2_credentials,omitempty"` AwsAccessKeyId string `json:"aws_access_key_id,omitempty"` AwsSecretAccessKey string `json:"aws_secret_access_key,omitempty"` AwsSessionToken string `json:"aws_session_token,omitempty"` AwsRegion string `json:"aws_region,omitempty"` AWSECRRegistryId string `json:"aws_ecr_registry_id,omitempty"` AwsRoleArn string `json:"aws_role_arn,omitempty"` + AwsRoleArns string `json:"aws_role_arns,omitempty"` } type BasicCredentials struct { @@ -278,19 +282,43 @@ func (source *Source) Metadata() []MetadataField { func (source *Source) AuthenticateToECR() bool { logrus.Warnln("ECR integration is experimental and untested") - mySession := session.Must(session.NewSession(&aws.Config{ - Region: aws.String(source.AwsRegion), - Credentials: credentials.NewStaticCredentials(source.AwsAccessKeyId, source.AwsSecretAccessKey, source.AwsSessionToken), - })) - var config aws.Config + var mySession *session.Session - // If a role arn has been supplied, then assume role and get a new session - if source.AwsRoleArn != "" { - config = aws.Config{Credentials: stscreds.NewCredentials(mySession, source.AwsRoleArn)} + if source.AwsEC2Credentials { + mySession = session.Must(session.NewSession(&aws.Config{ + Region: aws.String(source.AwsRegion), + Credentials: credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(session.New())}), + })) + + } else { + mySession = session.Must(session.NewSession(&aws.Config{ + Region: aws.String(source.AwsRegion), + Credentials: credentials.NewStaticCredentials(source.AwsAccessKeyId, source.AwsSecretAccessKey, source.AwsSessionToken), + })) + } + + // If aws role arns chain has been supplied, then assume roles in turn and get a new session + if source.AwsRoleArns != "" { + logrus.Warnln("Using `aws_role_arns` rather than `aws_role_arn`, see documentation") + awsRoleArnsList := strings.Split(source.AwsRoleArns, ",") + + for _, roleArn := range awsRoleArnsList { + logrus.Debugf("assuming new role: %s", roleArn) + mySession = session.Must(session.NewSession(&aws.Config{ + Region: aws.String(source.AwsRegion), + Credentials: stscreds.NewCredentials(mySession, roleArn), + })) + } + } else if source.AwsRoleArn != "" { //Assume one aws role only, kept for backward compatibility. + logrus.Debugf("assuming new role: %s", source.AwsRoleArn) + mySession = session.Must(session.NewSession(&aws.Config{ + Region: aws.String(source.AwsRegion), + Credentials: stscreds.NewCredentials(mySession, source.AwsRoleArn), + })) } - client := ecr.New(mySession, &config) + client := ecr.New(mySession) result, err := source.GetECRAuthorizationToken(client) if err != nil { logrus.Errorf("failed to authenticate to ECR: %s", err)