Plainwork

Plainwork / CI OIDC Atlas / Bitbucket Pipelines OIDC: AWS trust policy for sub

Bitbucket Pipelines OIDC for AWS: the sub claim and trust policies that match it

Bitbucket Pipelines can give a step a signed OIDC token so a job assumes an AWS role without stored access keys. What AWS compares with your trust policy is the token's sub, and Bitbucket's is unlike most CI platforms: it is made of UUIDs, not names. This page lists what Atlassian's documentation (read on 13 Oct 2026) says the token contains, three trust policies that follow from it, and the traps that make a correct-looking policy fail.

What Bitbucket puts in the token

FieldValueCan you change it?
Issuer (iss)https://api.bitbucket.org/2.0/workspaces/{WORKSPACE}/pipelines-config/identity/oidc, one per workspaceNo
Audience (aud)ari:cloud:bitbucket::workspace/<workspace-uuid>, shown in the repository's Pipelines, OpenID Connect settingsYes: up to 10 audiences of at most 150 characters, under oidc: audiences:
Subject (sub){REPOSITORY_UUID}[:{ENVIRONMENT_UUID}]:{STEP_UUID}Atlassian's pages do not describe a way to change it
Where the token isThe environment variable BITBUCKET_STEP_OIDC_TOKENSet oidc: true on the step

The braces are part of each UUID. Atlassian's example subject for a deployment step is {1de489be-ce6a-42a0-a8c8-eadbf1174ac7}:{bd715740-c970-486b-b68a-b421ec2a1f8b}:{759de0c6-eaee-4eaa-b7a6-c507eec759a7}: repository, deployment environment, step. For a step with no deployment environment the middle part is absent: Atlassian says the environment UUID "shows up only if the step is assigned to a deployment environment". The token lifetime is not stated on the pages we cite, so do not build a flow that depends on a particular value.

Step 1: register the provider in AWS

In IAM, add an OpenID Connect identity provider. The provider URL is the issuer above (with your workspace slug), and the audience is the one Bitbucket shows in the repository settings. Atlassian's page also prints the thumbprint you should get from OpenSSL for the root CA; check it against the current page instead of copying a number from a blog.

Step 2: ask for a token in the step

Atlassian's example, which assumes the role through the AWS CLI's web identity support:

image: amazon/aws-cli
pipelines:
  default:
    - step:
        oidc: true
        script:
          - export AWS_REGION=us-west-2
          - export AWS_ROLE_ARN=arn:aws:iam::XXXXXXXXXXXX:role/oidc-demo
          - export AWS_WEB_IDENTITY_TOKEN_FILE=$(pwd)/web-identity-token
          - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
          - aws s3 cp s3://bucket/XXXXXX ./XXXXXXX

Do not print the token in a shared build log. For debugging, paste one into the OIDC token debugger, which decodes it in your browser and sends nothing anywhere.

Step 3: write the trust policy

Atlassian warns that the basic setup lets "any repository under the workspace" assume the role. Narrow it with the sub condition. The condition key is the issuer without https://, then :sub. These follow Atlassian's three examples; replace the placeholders, keep the braces literal, and use StringLike, because the step UUID changes on every run.

Only one repository:

"Condition": {
  "StringLike": {
    "api.bitbucket.org/2.0/workspaces/{WORKSPACE}/pipelines-config/identity/oidc:sub": "{REPO_UUID}:{*}"
  }
}

Only deployment steps of one environment (Atlassian's pattern, {REPO_UUID}*:{ENVIRONMENT_UUID}:*, where the first * sits after the repository UUID's closing brace):

"Condition": {
  "StringLike": {
    "api.bitbucket.org/2.0/workspaces/{WORKSPACE}/pipelines-config/identity/oidc:sub": "{REPO_UUID}*:{ENVIRONMENT_UUID}:*"
  }
}

AWS documents StringLike as case-sensitive matching where the value "can include multi-character match wildcards (*) and single-character match wildcards (?) anywhere in the string", so the same pattern in a StringEquals block matches nothing. The third example on Atlassian's page restricts the request's source IP to the Bitbucket Cloud ranges, which is worth adding for production roles. The ranges change, so take them from Atlassian's current list.

Trap 1: you need UUIDs, and the UI shows names

Nothing in the token says the repository's slug or the environment's name in the sub. A policy written as my-repo:* will never match. Get the repository UUID from a real token's repositoryUuid claim (or the Bitbucket API), and the environment UUID from a token produced by a step that uses that deployment environment.

Trap 2: AWS accepts few claims as condition keys

Atlassian's page says: "Currently AWS allows only a set of claims to be used in the trust policy", which is why Bitbucket packs repository, environment and step into the sub. Conditioning on branchName, workspaceUuid or any other custom claim in an AWS trust policy will not work, so a policy that must depend on the branch has to be enforced another way, for example by assigning the deployment step to a protected environment and matching on its UUID.

Trap 3: documented claim names versus the live discovery document

Atlassian's example payload has a claim named deploymentEnvironment with the value testing. The workspace's live discovery document (we fetched one for a sample workspace on 13 Oct 2026) advertises deploymentEnvironmentUuid in claims_supported and no deploymentEnvironment. Both can be true, since discovery lists what the issuer says it supports, and the docs example may be older. Decode a real token before you write a condition, or a check, on either name.

Azure and Google Cloud

  • Microsoft Entra. A standard federated credential compares issuer, subject and audience exactly and case-sensitively, and "wildcard characters aren't supported in any federated identity credential property value". Because the step UUID in a Bitbucket sub changes per run, a standard credential cannot match it. Use a different mechanism (for example a flexible federated identity credential, a preview feature, if Microsoft lists Bitbucket as supported on its current page) or authenticate another way.
  • Google Cloud. Map a stable claim such as repositoryUuid to an attribute and write the condition on that attribute, rather than on the whole sub. Google limits mapped attributes to 127 bytes.

Check a policy before you deploy

Paste a token and the sub pattern from your trust policy into the debugger. If the job already fails with "Not authorized to perform sts:AssumeRoleWithWebIdentity", work through the six-step checklist. Compare with GitLab's id_tokens format or GitHub's immutable sub if you run more than one CI. The CI OIDC Atlas ($12) puts Bitbucket next to ten other CI platforms with the vendor sentence behind every cell.

Sources read 13 Oct 2026: Atlassian Support, "Deploy on AWS using Bitbucket Pipelines OpenID Connect" and "Integrate Pipelines with resource servers using OIDC"; the Bitbucket workspace OpenID discovery document; AWS IAM documentation, condition operators; Microsoft Entra documentation on federated credentials; Google Cloud workload identity federation. Details change between releases; re-read the current Atlassian page before relying on one.

More from the catalogue

Other small tools

See everything →