Consider issuing OIDC tokens, for hardened AWS/Google/etc access
OpenID Connect (OIDC) is a technology that's getting adopted by numerous cloud providers for machine-to-machine, cloud-to-cloud authentication. OIDC support would allow a Deno Deploy program to access AWS resources such as DynamoDB without the app having any 'secrets' configured at all!
How the flow works
A JWT can be issued by the provider (e.g. Deno Deploy) for an arbitrary audience (e.g. AWS) and given to the deployment on request. The deployment can then send its new JWT in a request to the other service. Usually the JWT is used to get a new token from that third-party platform which expires after maybe 1 hour.
Because the provider platform issues the JWT, it contains strong assertions about the 'subject' of the token, such as a repository name or a deployment ID. The third-party platform can then be configured to check the token's issuer and subject to determine whether to allow the access. So in AWS you could create an IAM role that can only be assumed by a particular Deno Deploy deployment ID, if deployment ID is in Deno Deploy's JWT.
What is involved
- Setting up some sort of key management and publishing the public keys to a static URL as a JWKS. And maybe rotating the keys on a schedule :)
- Picking an 'issuer' URL and hosting a
.well-known/openid-configurationfile there.- Such as
https://tokens.deploy.deno.com,https://deno.dev,https://deno.com/deploy - This doesn't need to be at the domain root, but it often is.
- For example, Github Actions @ token.actions.githubusercontent.com. More links to live examples in the "JWT issuers" section below.
- Such as
- Surfacing some way for Deploy apps to get up-to-date tokens.
- The
audof the JWT should be customizable per-token, and tokens expire, so just environment variables isn't good enough. - The tokens should include the deployment ID somwhere in
sub, as well as any additional fields that might be relevant to allowing access.
- The
Who implements this already
JWT audiences
These are services I know of that could immediately work with Deno Deploy tokens if it introduced them today.
- AWS has a public API
STS.AssumeRoleWithWebIdentity. You simply call this with a JWT and an IAM role ARN. If the role exists and trusts that JWT, then you receive AWS credentials for that role. This API is rather old but its existence has kinda started driving the new interest in OIDC.- Note that AWS has a quirky legacy requirement where the intermediate TLS certificate will get pinned instead of using the public CA list. I see that deno deploy's intermediate expires in 2027.
- Google Cloud has "Workload Identity Federation" which is newer and designed more for machine-to-machine auth.
- Azure's Workload Identity Federation
- Hashicorp Vault
JWT issuers
These are providers that have prior art on giving tokens to running code.
- Kubernetes can issue OIDC JWTs to pods. These are issued by the cluster itself and include Namespace, Pod, and ServiceAccount info. They are stored in temporary files and get rotated every hour by default. The pod's configuration includes token requests, so they are available as soon as the pod is started.
- Sample openid-configuration from my own cluster.
- Amazon enables this by default for their 'IRSA' solution, which is used with a pod config like so:
The AWS SDKs automatically find and use these tokens, so the user's code does not need any adjustments to work.containers: - ..... env: - name: AWS_REGION value: us-west-2 - name: AWS_ROLE_ARN value: "arn:aws:iam::111122223333:role/s3-reader" - name: AWS_WEB_IDENTITY_TOKEN_FILE # The AWS SDK watches this file value: "/var/run/secrets/eks.amazonaws.com/serviceaccount/token" volumeMounts: - mountPath: "/var/run/secrets/eks.amazonaws.com/serviceaccount/" name: aws-token volumes: - name: aws-token projected: sources: - serviceAccountToken: audience: "sts.amazonaws.com" expirationSeconds: 86400 # AWS configures a longer 24-hour expiration path: token - Google GKE enables this if the cluster has Workload Identity toggled to on.
- Github Actions now has an API endpoint that can issue JWTs. The workload is given environment variables that point to an issuing URL, including a random secret. The tokens contain verbose details like trigger type, branch, githash, relevant user, and workflow ID.
- Gitlab CI issues a default token
$CI_JOB_JWT_V2as of 14.6.- Documentation for integrating for AWS access.
- The audience is not configurable and they document that this can cause multi-party trust issues.
-
openid-configuration for issuer
https://gitlab.com
- CircleCI similarly has a
$CIRCLE_OIDC_TOKENenvironment variable, docs here. They're creating an issuer/JWKS per organization instead of one central signing key for everybody.
Also all kinds of OAuth sign-in providers are OIDC-compliant, like Google Accounts, Cloudflare Access, Auth0, Keycloak, ....
Downsides
- The setup is more complex than static tokens.
- Needing to fetch a token and redeem it with the third party will introduce some latency on the first request served by an isolate if it requires the credentials to serve that request.
- AWS operates a token redemption endpoint in every AWS region, so the closest region could be used instead of
us-east-1, but this is a very specific optimization that the application/SDK would need to be configured for.
- AWS operates a token redemption endpoint in every AWS region, so the closest region could be used instead of
For those reasons, JWTs won't entirely replace static credentials, especially for users just getting started. However it is an excellent tool for hardened access and provides stronger API trust with less credential upkeep.
Huge fan of Workload Identity Federation, it feels like OATH2 for CI/CD. I would love to see this as a new user using Deno Deploy.