From 4c116af1d05bb1e2757da8df08ffa8e31d742fe8 Mon Sep 17 00:00:00 2001 From: David Minor Date: Wed, 22 Nov 2017 13:21:36 -0800 Subject: [PATCH] s3: add support for ECS task IAM roles ECS container IAM metadata is in a different place than EC2 IAM metadata. Use defaults' RemoteCredProvider function to query the standard locations for the credentials. Give the ECS role precedence over the role available from the underlying EC2 instance. --- docs/content/s3.md | 7 ++++--- s3/s3.go | 12 ++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/content/s3.md b/docs/content/s3.md index 737c2c4cf..f62c5d46b 100644 --- a/docs/content/s3.md +++ b/docs/content/s3.md @@ -51,7 +51,7 @@ Choose a number from below, or type in your own value 13 / Yandex Disk \ "yandex" Storage> 2 -Get AWS credentials from runtime (environment variables or EC2 meta data if no env vars). Only applies if access_key_id and secret_access_key is blank. +Get AWS credentials from runtime (environment variables or EC2/ECS meta data if no env vars). Only applies if access_key_id and secret_access_key is blank. Choose a number from below, or type in your own value 1 / Enter AWS credentials in the next step \ "false" @@ -248,6 +248,7 @@ credentials. In order of precedence: - Access Key ID: `AWS_ACCESS_KEY_ID` or `AWS_ACCESS_KEY` - Secret Access Key: `AWS_SECRET_ACCESS_KEY` or `AWS_SECRET_KEY` - Session Token: `AWS_SESSION_TOKEN` + - Running `rclone` in an ECS task with an IAM role - Running `rclone` on an EC2 instance with an IAM role If none of these option actually end up providing `rclone` with AWS @@ -358,7 +359,7 @@ Choose a number from below 10) s3 11) yandex type> 10 -Get AWS credentials from runtime (environment variables or EC2 meta data if no env vars). Only applies if access_key_id and secret_access_key is blank. +Get AWS credentials from runtime (environment variables or EC2/ECS meta data if no env vars). Only applies if access_key_id and secret_access_key is blank. Choose a number from below, or type in your own value * Enter AWS credentials in the next step 1) false @@ -551,7 +552,7 @@ Choose a number from below, or type in your own value \ "s3" [snip] Storage> s3 -Get AWS credentials from runtime (environment variables or EC2 meta data if no env vars). Only applies if access_key_id and secret_access_key is blank. +Get AWS credentials from runtime (environment variables or EC2/ECS meta data if no env vars). Only applies if access_key_id and secret_access_key is blank. Choose a number from below, or type in your own value 1 / Enter AWS credentials in the next step \ "false" diff --git a/s3/s3.go b/s3/s3.go index 7df10b18d..359c7ef8e 100644 --- a/s3/s3.go +++ b/s3/s3.go @@ -29,6 +29,7 @@ import ( "github.com/aws/aws-sdk-go/aws/corehandlers" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" + "github.com/aws/aws-sdk-go/aws/defaults" "github.com/aws/aws-sdk-go/aws/ec2metadata" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" @@ -48,7 +49,7 @@ func init() { // AWS endpoints: http://docs.amazonwebservices.com/general/latest/gr/rande.html#s3_region Options: []fs.Option{{ Name: "env_auth", - Help: "Get AWS credentials from runtime (environment variables or EC2 meta data if no env vars). Only applies if access_key_id and secret_access_key is blank.", + Help: "Get AWS credentials from runtime (environment variables or EC2/ECS meta data if no env vars). Only applies if access_key_id and secret_access_key is blank.", Examples: []fs.OptionExample{ { Value: "false", @@ -317,6 +318,10 @@ func s3Connection(name string) (*s3.S3, *session.Session, error) { SessionToken: fs.ConfigFileGet(name, "session_token"), } + lowTimeoutClient := &http.Client{Timeout: 1 * time.Second} // low timeout to ec2 metadata service + def := defaults.Get() + def.Config.HTTPClient = lowTimeoutClient + // first provider to supply a credential set "wins" providers := []credentials.Provider{ // use static credentials if they're present (checked by provider) @@ -326,10 +331,13 @@ func s3Connection(name string) (*s3.S3, *session.Session, error) { // * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY &credentials.EnvProvider{}, + // Pick up IAM role if we're in an ECS task + defaults.RemoteCredProvider(*def.Config, def.Handlers), + // Pick up IAM role in case we're on EC2 &ec2rolecreds.EC2RoleProvider{ Client: ec2metadata.New(session.New(), &aws.Config{ - HTTPClient: &http.Client{Timeout: 1 * time.Second}, // low timeout to ec2 metadata service + HTTPClient: lowTimeoutClient, }), ExpiryWindow: 3, },