How to Configure OIDC Workload Identity
  • 05 Nov 2026
  • Dark
    Light

How to Configure OIDC Workload Identity

  • Dark
    Light

Article summary

This guide registers an OIDC provider, creates a trusted IAM role, exchanges a JWT, and uses the resulting credentials with Backblaze B2 Cloud Storage.

Prerequisites

Before you begin, you must have the following items:

  • A Backblaze account with IAM enabled.

  • IAM credentials authorized to manage OIDC providers, roles, and role policies.

  • An OIDC provider that meets the compatibility requirements.

  • A representative JWT issued to the intended workload.

  • AWS CLI with jq available for handling responses.

  • A Backblaze B2 bucket for the verification request.

1. Inspect the token

A representative decoded JWT payload is:

{
  "iss": "https://issuer.example.com",
  "aud": "backblaze-workload",
  "sub": "workload:production:reader",
  "iat": 1793300400,
  "exp": 1793304000
}

Record:

  • iss: provider issuer URL.

  • Effective audience: azp when present; otherwise the single aud.

  • sub: stable workload identifier.

Do not register values taken from an untrusted or unrelated token.

2. Register the provider

export AWS_ACCESS_KEY_ID="<administrator-access-key>"
export AWS_SECRET_ACCESS_KEY="<administrator-secret-key>"
export AWS_REGION="us-west-002"
aws iam create-open-id-connect-provider \
  --endpoint-url https://iam.backblazeb2.com \
  --url https://issuer.example.com \
  --client-id-list backblaze-workload

ThumbprintList is optional. When omitted, Backblaze connects to the provider and derives a certificate thumbprint.

Response:

{
  "OpenIDConnectProviderArn": "arn:aws:iam::123456789012:oidc-provider/issuer.example.com"
}

Register each distinct issuer separately.

3. Create the role trust policy

Save as trust-policy.json:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/issuer.example.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "issuer.example.com:aud": "backblaze-workload",
          "issuer.example.com:sub": "workload:production:reader"
        }
      }
    }
  ]
}

Create the role:

aws iam create-role \
  --endpoint-url https://iam.backblazeb2.com \
  --role-name WorkloadReadOnly \
  --max-session-duration 3600 \
  --assume-role-policy-document file://trust-policy.json

Use exact subjects when practical. StringLike supports case-sensitive * and ?, but broad patterns can authorize unintended workloads.

4. Attach role permissions

Save as role-permissions.json:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketLocation",
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::example-data-bucket"
    },
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example-data-bucket/*"
    }
  ]
}
aws iam put-role-policy \
  --endpoint-url https://iam.backblazeb2.com \
  --role-name WorkloadReadOnly \
  --policy-name ReadExampleBucket \
  --policy-document file://role-permissions.json

5. Exchange the JWT

aws sts assume-role-with-web-identity \
  --endpoint-url https://sts.backblazeb2.com \
  --no-sign-request \
  --role-arn arn:aws:iam::123456789012:role/WorkloadReadOnly \
  --role-session-name production-reader \
  --web-identity-token file:///var/run/secrets/oidc/token \
  --duration-seconds 3600

The JWT authenticates this request. Do not provide an IAM authorization header.

Successful response:

{
  "Audience": "backblaze-workload",
  "Provider": "arn:aws:iam::123456789012:oidc-provider/issuer.example.com",
  "SubjectFromWebIdentityToken": "workload:production:reader",
  "AssumedRoleUser": {
    "Arn": "arn:aws:sts::123456789012:assumed-role/WorkloadReadOnly/production-reader"
  },
  "Credentials": {
    "AccessKeyId": "<temporary-access-key>",
    "SecretAccessKey": "<temporary-secret-key>",
    "SessionToken": "<temporary-session-token>",
    "Expiration": "2026-10-29T23:00:00Z"
  }
}

The access key, secret key, and session token are all required.

6. Use the temporary credentials

export AWS_ACCESS_KEY_ID="<temporary-access-key>"
export AWS_SECRET_ACCESS_KEY="<temporary-secret-key>"
export AWS_SESSION_TOKEN="<temporary-session-token>"
export AWS_REGION="us-west-002"
aws s3api list-objects-v2 \
  --endpoint-url https://s3.us-west-002.backblazeb2.com \
  --bucket example-data-bucket

This request is authorized by the role permission policy, not the role trust policy.

Runtime endpoints

Endpoint

When called

Purpose

POST https://sts.backblazeb2.com/

Every exchange

Exchange the JWT for credentials

GET <issuer>/.well-known/openid-configuration

Discovery-cache miss

Locate jwks_uri

GET <jwks_uri>

Key-cache miss or unknown kid

Obtain JWT verification keys

Regional B2 S3 endpoint

After exchange

Perform authorized storage operations

Backblaze does not call the public IAM endpoint or the provider’s token endpoint during the exchange.

Authorization decision

Credentials are returned only when:

JWT signature and required claims are valid
AND issuer identifies a registered provider
AND effective audience is registered
AND provider ARN matches Principal.Federated
AND the trust policy allows sts:AssumeRoleWithWebIdentity
AND all trust conditions match
AND no applicable explicit Deny exists

Troubleshooting

Token exchange fails

Check:

  • The token is a signed JWT rather than an OAuth access token.

  • The discovery document and JWKS are publicly reachable.

  • iss exactly matches a registered provider.

  • The effective audience is registered.

  • exp, iat, and optional nbf are valid.

  • The JWT kid appears in the current JWKS.

  • The provider ARN matches Principal.Federated.

  • The trust-policy subject and other conditions match.

Exchange succeeds but S3 returns AccessDenied

Check:

  • The role permission policy allows the requested S3 action.

  • Bucket and object ARNs are correct.

  • The regional S3 endpoint is correct.

  • AWS_SESSION_TOKEN is set.

  • No applicable policy contains an explicit Deny.

Never log the JWT, temporary secret access key, or session token.

Additional Resources


Was this article helpful?