Skip to content

feat(aws): support container credentials in AwsNativeSource#659

Closed
nidcode wants to merge 1 commit into
googleapis:mainfrom
nidcode:feat/aws-native-source-ecs-container-credentials
Closed

feat(aws): support container credentials in AwsNativeSource#659
nidcode wants to merge 1 commit into
googleapis:mainfrom
nidcode:feat/aws-native-source-ecs-container-credentials

Conversation

@nidcode
Copy link
Copy Markdown

@nidcode nidcode commented May 8, 2026

Problem

When running on ECS Fargate (task IAM role), EKS Pod Identity, AWS Greengrass, or any other environment that exposes credentials via the container credentials provider, the WIF (external_account / AWS) credential flow fails:

  • AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY are not in the environment — the credential URI is exposed via AWS_CONTAINER_CREDENTIALS_RELATIVE_URI / AWS_CONTAINER_CREDENTIALS_FULL_URI instead.
  • AwsNativeSource::getSigningVarsFromUrl() is hard-coded to the EC2 IMDS pattern (<securityCredentialsUrl>/<role-name>); the ECS / EKS endpoint returns the credential JSON directly without a role-name suffix, so even pointing securityCredentialsUrl at the ECS URL would not work.

The user-visible failure today is:

LogicException: Unable to get credentials from ENV, and no security credentials URL provided
  at Google\Auth\CredentialSource\AwsNativeSource::fetchSubjectToken

…even though the same task can resolve credentials with aws-sdk-php's CredentialProvider::defaultProvider(). This forces downstream applications to add a "bridge" in their bootstrap code that resolves AWS credentials via aws-sdk-php and putenvs them so that AwsNativeSource can pick them up — clearly something the auth library should be able to do natively.

Change

Add a third credential resolution step in AwsNativeSource::fetchSubjectToken(), slotted between the existing ENV lookup and the existing IMDS-style securityCredentialsUrl fallback:

Order Source Status
1 AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY env existing
2 AWS_CONTAINER_CREDENTIALS_{RELATIVE,FULL}_URI new
3 EC2 IMDS via securityCredentialsUrl constructor arg existing
4 LogicException existing (message updated)

The new path:

  • Reads AWS_CONTAINER_CREDENTIALS_RELATIVE_URI and prefixes it with http://169.254.170.2, OR uses AWS_CONTAINER_CREDENTIALS_FULL_URI directly.
  • Honors AWS_CONTAINER_AUTHORIZATION_TOKEN (literal) and AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE (file contents) by setting an Authorization: header on the GET request — required by EKS Pod Identity and IAM Roles Anywhere container scenarios.
  • Parses the JSON response (AccessKeyId / SecretAccessKey / Token) — same schema as the EC2 metadata response — so the rest of the SigV4 pipeline is unchanged.
  • Returns null when no container credentials env var is set, so the caller falls through to the existing securityCredentialsUrl path.

The new method getSigningVarsFromContainerCredentials() mirrors the visibility (public static, marked @internal) of getSigningVarsFromEnv() / getSigningVarsFromUrl() for consistency and testability.

Tests

$ vendor/bin/phpunit tests/CredentialSource/AwsNativeSourceTest.php
PHPUnit 9.6.34 by Sebastian Bergmann and contributors.

..............                                                    14 / 14 (100%)

OK (14 tests, 66 assertions)

Four new tests under tests/CredentialSource/AwsNativeSourceTest.php:

  • testGetSigningVarsFromContainerCredentialsReturnsNullWhenEnvNotSet — guarantees the new path is opt-in (HTTP handler must not be invoked when no env var is set).
  • testGetSigningVarsFromContainerCredentialsRelativeUri — verifies the http://169.254.170.2 prefix and the absence of an Authorization: header for the ECS Fargate task-role case.
  • testGetSigningVarsFromContainerCredentialsFullUriWithAuthToken — covers EKS Pod Identity (FULL_URI + AWS_CONTAINER_AUTHORIZATION_TOKEN) and the optional-Token-in-response case.
  • testFetchSubjectTokenFromContainerCredentials — end-to-end: with AWS_CONTAINER_CREDENTIALS_RELATIVE_URI set and no securityCredentialsUrl, fetchSubjectToken() produces a SigV4-signed STS GetCallerIdentity request whose Authorization header references the access key fetched from the container endpoint.

The existing testFetchSubjectTokenWithoutSecurityCredentialsUrlOrEnvThrowsException is updated for the new exception message.

Backwards compatibility

  • No constructor signature change.
  • New behavior is strictly additive: when the new env vars are absent, behavior is identical to today (env → securityCredentialsUrl → throw).
  • The LogicException message is updated from "Unable to get credentials from ENV, and no security credentials URL provided" to mention container credentials. This message is not part of the public API; if keeping the legacy wording is preferred I'm happy to drop the rewording in a follow-up commit.

CLA

Will sign the individual CLA when the bot prompts.

When running on ECS Fargate (task IAM role), EKS Pod Identity, AWS
Greengrass, or any other environment exposing credentials through the
container credentials provider, AWS does not place the static
credentials in the standard `AWS_*_KEY_ID` environment variables and
the EC2 IMDS-style `securityCredentialsUrl` does not apply because the
endpoint returns the credential JSON directly without a role-name
suffix.

Today `AwsNativeSource::fetchSubjectToken()` only attempts environment
variables and the `securityCredentialsUrl` constructor argument, which
makes the WIF flow unusable in those environments without a separate
shim that resolves AWS credentials via aws-sdk-php and re-exports them
into `putenv` before the call.

Add a third resolution path that consumes
`AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` /
`AWS_CONTAINER_CREDENTIALS_FULL_URI` (with optional
`AWS_CONTAINER_AUTHORIZATION_TOKEN` /
`AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE` headers), per
https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html.
The endpoint returns a JSON body using the same `AccessKeyId` /
`SecretAccessKey` / `Token` schema as the EC2 credentials endpoint,
so the rest of the SigV4 signing pipeline is unchanged.

Resolution order in `fetchSubjectToken`:

  1. `AWS_ACCESS_KEY_ID` env (existing)
  2. Container credentials endpoint (new)
  3. EC2 IMDS-style `securityCredentialsUrl` (existing)
  4. throw `LogicException`

The exception message is updated to reflect the new third option, and
the existing tests for the throw path are adjusted accordingly. New
unit tests cover:

  - container env vars unset → return null
  - relative-uri → http://169.254.170.2 endpoint, no Authorization
  - full-uri + AWS_CONTAINER_AUTHORIZATION_TOKEN, optional Token field
  - end-to-end fetchSubjectToken from container credentials produces
    a SigV4-signed subject token using the access key returned by
    the container endpoint.
@nidcode nidcode requested a review from a team as a code owner May 8, 2026 12:52
@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 8, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@nidcode
Copy link
Copy Markdown
Author

nidcode commented May 8, 2026

Apologies for the noise — closing this for now while we keep using a downstream env-var bridge in our application bootstrap. Happy to re-open later if there is upstream interest in container credentials support for AwsNativeSource. Feel free to reuse the patch from https://github.com/nidcode/google-auth-library-php/tree/feat/aws-native-source-ecs-container-credentials.

@nidcode nidcode closed this May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant