What's the correct way of loading AWS credentials from role in a Fargate task using AWS SDK Go?

I have the following snippet:

awsCredentials := credentials.NewChainCredentials(
    []credentials.Provider{
        &ec2rolecreds.EC2RoleProvider{
            Client: ec2metadata.New(newSession, aws.NewConfig()),
        },
        &credentials.SharedCredentialsProvider{},
        &credentials.EnvProvider{},
    })

which works fine whenever the code is running on an EC2 instance or when the access/secret key are passed through variables (used for local testing).

However, this code is failing when running on ECS+Fargate because NoCredentialProviders: no valid providers in chain. Checked the environment variables of the running container and it has the expected AWS_CONTAINER_CREDENTIALS_RELATIVE_URI, so the credentials.EnvProvider should read it.

So, my question is, what's the correct way of reading these credentials? Because the problem I'm facing is not about lack of permissions (which would indicate an error in the policy / role), but that code is not able to get the credentials.

UPDATE

I have narrowed this to the use of ec2rolescreds.

Using this simple example:

package main

import (
    "fmt"
    "log"

    "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/ec2metadata"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
)

func main() {
    newSession, err := session.NewSession()

    if err != nil {
        log.Fatal(err)
    }

    awsCredentials := credentials.NewChainCredentials(
        []credentials.Provider{
            &ec2rolecreds.EC2RoleProvider{
                Client: ec2metadata.New(newSession, aws.NewConfig()),
            },
            &credentials.SharedCredentialsProvider{},
            &credentials.EnvProvider{},
        })

    sess, err := session.NewSession(&aws.Config{
        Region:      aws.String("us-east-1"),
        Credentials: awsCredentials},
    )

    if err != nil {
        log.Fatal(err)
    }
    // Create S3 service client
    svc := s3.New(sess)

    result, err := svc.ListBuckets(nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("Buckets:")

    for _, b := range result.Buckets {
        fmt.Printf("* %s created on %s\n",
            aws.StringValue(b.Name), aws.TimeValue(b.CreationDate))
    }
}

If I remove ec2rolescreds, everything works fine both local and in ECS+Fargate.

However, if I run this code as is, I get the same error of NoCredentialProviders: no valid providers in chain

1 answer

  • answered 2020-09-24 13:18 Ay0

    So, a session can be configured using a Config object.

    Reading through the specs of this object, it says for Credentials:

    // The credentials object to use when signing requests. Defaults to a
    // chain of credential providers to search for credentials in environment
    // variables, shared credential file, and EC2 Instance Roles.
    Credentials *credentials.Credentials
    

    The defaults are already what my snippet was doing, so I removed all the awsCredentials block and now it's working fine everywhere. Locally, EC2, Fargate...