Summary
Google::Auth::ExternalAccount::AwsCredentials#fetch_security_credentials currently resolves AWS credentials from only two sources:
- Environment variables (
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)
- EC2 instance metadata (IMDS)
When running on AWS ECS (Fargate or EC2 launch type), credentials are provided via the ECS credential provider, which uses AWS_CONTAINER_CREDENTIALS_RELATIVE_URI or AWS_CONTAINER_CREDENTIALS_FULL_URI environment variables to point to a local metadata endpoint. This endpoint is not the EC2 IMDS endpoint and has a different API format, so the existing EC2 metadata fallback does not work.
Expected behavior
fetch_security_credentials should check for ECS task role credentials (via AWS_CONTAINER_CREDENTIALS_RELATIVE_URI / AWS_CONTAINER_CREDENTIALS_FULL_URI) between the environment variable check and the EC2 metadata fallback.
Resolution order should be:
- ENV vars (
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY) — current behavior
- ECS task role via
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI — new
- EC2 instance metadata via
credential_source.url — current fallback
Current workaround
We are using prepend to monkey-patch fetch_security_credentials with ECS support:
module AwsEcsCredentialSupport
private
def fetch_security_credentials
env_key = ENV[Google::Auth::CredentialsLoader::AWS_ACCESS_KEY_ID_VAR]
env_secret = ENV[Google::Auth::CredentialsLoader::AWS_SECRET_ACCESS_KEY_VAR]
if env_key && env_secret
return {
access_key_id: env_key,
secret_access_key: env_secret,
session_token: ENV[Google::Auth::CredentialsLoader::AWS_SESSION_TOKEN_VAR]
}
end
if ENV["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"] || ENV["AWS_CONTAINER_CREDENTIALS_FULL_URI"]
creds = Aws::ECSCredentials.new.credentials
if creds.access_key_id && creds.secret_access_key
return {
access_key_id: creds.access_key_id,
secret_access_key: creds.secret_access_key,
session_token: creds.session_token
}
end
end
super
end
end
Google::Auth::ExternalAccount::AwsCredentials.prepend(AwsEcsCredentialSupport)
Related issues in other languages
There is also a third-party Python package aws-ecs-gcp-workload-identity-federation that works around this limitation.
Use case
We use GCP Workload Identity Federation to allow AWS ECS tasks to access Google Cloud resources (BigQuery) without long-lived service account keys. The ECS tasks run on Fargate, where the only credential source available is the ECS task role metadata endpoint.
Summary
Google::Auth::ExternalAccount::AwsCredentials#fetch_security_credentialscurrently resolves AWS credentials from only two sources:AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY)When running on AWS ECS (Fargate or EC2 launch type), credentials are provided via the ECS credential provider, which uses
AWS_CONTAINER_CREDENTIALS_RELATIVE_URIorAWS_CONTAINER_CREDENTIALS_FULL_URIenvironment variables to point to a local metadata endpoint. This endpoint is not the EC2 IMDS endpoint and has a different API format, so the existing EC2 metadata fallback does not work.Expected behavior
fetch_security_credentialsshould check for ECS task role credentials (viaAWS_CONTAINER_CREDENTIALS_RELATIVE_URI/AWS_CONTAINER_CREDENTIALS_FULL_URI) between the environment variable check and the EC2 metadata fallback.Resolution order should be:
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY) — current behaviorAWS_CONTAINER_CREDENTIALS_RELATIVE_URI— newcredential_source.url— current fallbackCurrent workaround
We are using
prependto monkey-patchfetch_security_credentialswith ECS support:Related issues in other languages
There is also a third-party Python package
aws-ecs-gcp-workload-identity-federationthat works around this limitation.Use case
We use GCP Workload Identity Federation to allow AWS ECS tasks to access Google Cloud resources (BigQuery) without long-lived service account keys. The ECS tasks run on Fargate, where the only credential source available is the ECS task role metadata endpoint.