使用 AWS SDK Go 从 Fargate 任务中的角色加载 AWS 凭证的正确方法是什么?

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

我有以下片段:

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

每当代码在 EC2 实例上 运行ning 或当 access/secret 密钥通过变量传递(用于本地测试)时,它都可以正常工作。

但是,由于 NoCredentialProviders: no valid providers in chain,在 ECS+Fargate 上 运行ning 时此代码失败。检查了 运行ning 容器的环境变量,它有预期的 AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,所以 credentials.EnvProvider 应该读取它。

所以,我的问题是,阅读这些凭据的正确方法是什么?因为我面临的问题不是缺少权限(这表明策略/角色中存在错误),而是该代码无法获取凭据。

更新

我已将其缩小为使用 ec2rolescreds

使用这个简单的例子:

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))
    }
}

如果我删除 ec2rolescreds,在本地和 ECS+Fargate 中一切正常。

但是,如果我按原样 运行 这段代码,我会得到与 NoCredentialProviders: no valid providers in chain

相同的错误

因此,可以使用 Config 对象配置会话。

通读此对象的规格,它说凭据:

// 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

默认值已经是我的代码片段所做的,所以我删除了所有 awsCredentials 块,现在它在任何地方都可以正常工作。在本地,EC2、Fargate...

更新

为了扩展答案,删除 awsCredentials 使这项工作有效的原因是,如果您检查 SDK 的代码,https://github.com/aws/aws-sdk-go/blob/master/aws/defaults/defaults.go#L107,默认凭据会同时检查 EnvProviderRemoteCredProvider.

通过覆盖默认链凭据,无法在 RemoteCredProvider 中查找凭据,这是处理环境变量 AWS_CONTAINER_CREDENTIALS_FULL_URI.

的提供者

解决方案是使用会话而不是凭据来初始化客户端,即:

conf := aws.NewConfig().WithRegion("us-east-1")
sess := session.Must(session.NewSession(conf))

svc := s3.New(sess)
// others:
//   svc := sqs.New(sess)
//   svc := dynamodb.New(sess)
//   ... 

因为,正如@Ay0 所指出的,默认的凭证链已经包含了 EnvProviderRemoteCredProvider .

如果您仍然需要凭证,您可以使用:

creds := stscreds.NewCredentials(sess, "myRoleARN")

作为 documentation points out. Notice that the policy of the role must have the sts:AssumeRole action enabled. For more information, here are the stscreds.NewCredentials(...) docs