diff --git a/plugins/rest/aws.go b/plugins/rest/aws.go index 349441c838..cc45dfa9c7 100644 --- a/plugins/rest/aws.go +++ b/plugins/rest/aws.go @@ -30,10 +30,11 @@ const ( ec2DefaultTokenPath = "http://169.254.169.254/latest/api/token" // ref. https://docs.aws.amazon.com/AmazonECS/latest/userguide/task-iam-roles.html - ecsDefaultCredServicePath = "http://169.254.170.2" - ecsRelativePathEnvVar = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" - ecsFullPathEnvVar = "AWS_CONTAINER_CREDENTIALS_FULL_URI" - ecsAuthorizationTokenEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN" + ecsDefaultCredServicePath = "http://169.254.170.2" + ecsRelativePathEnvVar = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" + ecsFullPathEnvVar = "AWS_CONTAINER_CREDENTIALS_FULL_URI" + ecsAuthorizationTokenEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN" + ecsAuthorizationTokenFileEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE" // ref. https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html stsDefaultDomain = "amazonaws.com" @@ -277,9 +278,22 @@ func (cs *awsMetadataCredentialService) refreshFromService(ctx context.Context) // if using the AWS_CONTAINER_CREDENTIALS_FULL_URI variable, we need to associate the token // to the request if _, useFullPath := os.LookupEnv(ecsFullPathEnvVar); useFullPath { - token, tokenExists := os.LookupEnv(ecsAuthorizationTokenEnvVar) - if !tokenExists { - return errors.New("unable to get ECS metadata authorization token") + var token string + tokenFilePath, tokenFilePathExists := os.LookupEnv(ecsAuthorizationTokenFileEnvVar) + + if tokenFilePathExists { + tokenBytes, err := os.ReadFile(tokenFilePath) + if err != nil { + return errors.New("failed to read ECS metadata authorization token from file: " + err.Error()) + } + token = string(tokenBytes) + // If token doesn't exist as a file check if it exists as an environment variable + } else { + var tokenExists bool + token, tokenExists = os.LookupEnv(ecsAuthorizationTokenEnvVar) + if !tokenExists { + return errors.New("unable to get ECS metadata authorization token") + } } req.Header.Set("Authorization", token) } diff --git a/plugins/rest/aws_test.go b/plugins/rest/aws_test.go index eccccb56f9..b8f190fa16 100644 --- a/plugins/rest/aws_test.go +++ b/plugins/rest/aws_test.go @@ -358,6 +358,16 @@ func TestMetadataCredentialService(t *testing.T) { assertErr("unable to get ECS metadata authorization token", err, t) os.Unsetenv(ecsFullPathEnvVar) + test.WithTempFS(nil, func(path string) { + // wrong path: bad file token + t.Setenv(ecsFullPathEnvVar, "fullPath") + os.Setenv(ecsAuthorizationTokenFileEnvVar, filepath.Join(path, "bad-file")) + _, err = cs.credentials(context.Background()) + assertErr("failed to read ECS metadata authorization token from file", err, t) + os.Unsetenv(ecsFullPathEnvVar) + os.Unsetenv(ecsAuthorizationTokenFileEnvVar) + }) + // wrong path: creds not found cs = awsMetadataCredentialService{ RoleName: "not_my_iam_role", // not present @@ -525,6 +535,39 @@ func TestMetadataCredentialService(t *testing.T) { assertEq(creds.SessionToken, ts.payload.Token, t) os.Unsetenv(ecsFullPathEnvVar) os.Unsetenv(ecsAuthorizationTokenEnvVar) + + // happy path: credentials fetched from full path var using token from filesystem + files := map[string]string{ + "good_token_file": "THIS_IS_A_GOOD_TOKEN", + } + test.WithTempFS(files, func(path string) { + // happy path: credentials fetched from full path var + cs = awsMetadataCredentialService{ + RegionName: "us-east-1", + credServicePath: "", // not set as we want to test env var resolution + logger: logging.Get(), + } + ts.payload = metadataPayload{ + AccessKeyID: "MYAWSACCESSKEYGOESHERE", + SecretAccessKey: "MYAWSSECRETACCESSKEYGOESHERE", + Code: "Success", + Token: "MYAWSSECURITYTOKENGOESHERE", + Expiration: time.Now().UTC().Add(time.Minute * 2)} // short time + t.Setenv(ecsFullPathEnvVar, ts.server.URL+"/fullPath") + t.Setenv(ecsAuthorizationTokenFileEnvVar, filepath.Join(path, "good_token_file")) + creds, err = cs.credentials(context.Background()) + if err != nil { + // Cannot proceed with test if unable to fetch credentials. + t.Fatal(err) + } + + assertEq(creds.AccessKey, ts.payload.AccessKeyID, t) + assertEq(creds.SecretKey, ts.payload.SecretAccessKey, t) + assertEq(creds.RegionName, cs.RegionName, t) + assertEq(creds.SessionToken, ts.payload.Token, t) + os.Unsetenv(ecsFullPathEnvVar) + os.Unsetenv(ecsAuthorizationTokenFileEnvVar) + }) } func TestMetadataServiceErrorHandled(t *testing.T) {