Skip to content

Commit

Permalink
Merge pull request #1 from alphagov/ec2_credentials_and_iam_roles_chain
Browse files Browse the repository at this point in the history
support EC2 AWS credentials and IAM roles chain

Signed-off-by: Frederic Francois <[email protected]>
  • Loading branch information
fredericfran-gds committed Jul 8, 2021
2 parents 06ffede + 5dd9709 commit aa9afda
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 15 deletions.
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:...`.
Expand Down
3 changes: 2 additions & 1 deletion commands/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
3 changes: 2 additions & 1 deletion commands/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
3 changes: 2 additions & 1 deletion commands/out.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
46 changes: 37 additions & 9 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit aa9afda

Please sign in to comment.