AWS Identity
How the Workers authenticate to FloatMe’s service APIs on AWS, and the
change that replaces the static IAM user keys with a role assumed
through Auth0. The AWS and Auth0 halves live in the infrastructure
repo; its docs page "Cloudflare Workers identity" is the design record.
This page is the Worker-side plan. Nothing here is implemented yet.
Today
The auth Worker signs requests to user-service, the transactions
service, floatmetrics, and the QA service with SigV4 through
aws4fetch, using FLOATME_AWS_ACCESS_KEY_ID and
FLOATME_AWS_SECRET_ACCESS_KEY from Worker secrets. Two call sites
build the client:
-
cloudflare/workers/auth/handlers/signup-v2.ts,createUserServiceUser -
cloudflare/helpers/qa-helper.ts, the integration-user path, which hard-codesus-west-2
The keys belong to the test-cloudflare-workers and
prod-cloudflare-workers IAM users, are minted by hand, arrive as
GitHub secrets, and reach the Workers through each worker’s
secrets.sh. They have never been rotated, and user-service’s
user-creation handler accepts calls only from those user names.
Target
No AWS credential is stored anywhere. The Worker gets a client-credentials token from Auth0, exchanges it with STS for temporary credentials on a role, caches them, and signs as before.
Auth0 /oauth/token (client_credentials, audience = AWS API identifier)
-> access token, subject "<client_id>@clients"
STS AssumeRoleWithWebIdentity (role ARN, that token, fixed session name)
-> access key, secret, session token, ~1h
aws4fetch AwsClient with sessionToken
STS’s AssumeRoleWithWebIdentity is an unsigned Query API call, so no credential is needed to make it. The Auth0 client secret is the only secret, and rotating it is an Auth0 action.
Changes
New helper
cloudflare/helpers/aws-credentials.ts exporting one function that
returns a ready AwsClient for a given region. Internally:
-
Read cached credentials from KV under a key per environment. If they expire more than five minutes out, use them.
-
Otherwise request an Auth0 token with
grant_type=client_credentialsagainstAUTH0_BASE_URLforAUTH0_AWS_AUDIENCE. Cache the token in KV for its lifetime, since Auth0 meters machine-to-machine tokens per month and every isolate starting cold would otherwise mint one. -
Call STS with
RoleArn=FLOATME_AWS_ROLE_ARN,WebIdentityToken, andRoleSessionName=<worker name>. Parse the XML credentials. -
Write the credentials and expiry to KV, and return the client.
Both existing call sites switch to it. The qa-helper.ts region stays
hard-coded until the QA service exists in more than one region.
Config
Per environment in wrangler.toml, non-secret:
-
FLOATME_AWS_ROLE_ARN, from the infrastructure root’s output -
AUTH0_AWS_AUDIENCE, the API identifier created in the tenant -
a
kv_namespacesbinding for the credential cache
Secrets, through secrets.sh and the deploy workflow:
-
AUTH0_AWS_CLIENT_IDandAUTH0_AWS_CLIENT_SECRET, the machine-to-machine application. Separate from the authentication and management clients so the token can do nothing but assume the role.
Env in cloudflare/helpers/env.ts gains those and, after cutover,
loses FLOATME_AWS_ACCESS_KEY_ID and FLOATME_AWS_SECRET_ACCESS_KEY.
Staging environment
Staging is where this lands first, and the repo has no staging
environment yet. It needs a [env.staging] stanza in each worker’s
wrangler.toml with staging routes and the staging API hostnames, a
staging block in deploy.yaml populating the same variables the test
block does, and the secrets script run for it. Which event deploys
staging follows the infrastructure repo’s release flow for staging.
Sequencing
-
infrastructure: staging Auth0 tenant root creates the application and API; staging AWS root creates the OIDC provider and role. -
user-service: caller check becomes config-driven and matches on the role name.
-
This repo: helper, config, staging environment, cutover of the two call sites.
-
Verify a signup end to end in staging, then check CloudTrail shows the assume with the Auth0 subject and the API Gateway log shows the invoke.
-
Prod follows the same steps once the prod tenant and root are ready. Then the static-key secrets and the IAM users are deleted.
Notes
-
Session credentials are one hour. The five-minute refresh margin means a Worker never presents credentials that expire mid-request.
-
If Auth0 is unavailable, cached credentials keep working until they expire. That is the new failure mode this design adds; the Workers already cannot log users in without Auth0, so it is not a new dependency, only a wider one.
-
The role session name is what shows in CloudTrail and in the ARN user-service sees. Keep it fixed per worker; user-service matches on the role name segment, not the session name.