Skip to main content
RunBook Academy

KubernetesLX · ServiceAccountsServiceAccounts

External token issuers — IRSA, Workload Identity, SPIFFE

Advanced⏱ ~14 minkubectlcloud provider CLI

What you'll learn

  • Explain how AWS IRSA, GCP Workload Identity, and Azure Workload Identity exchange SA tokens for cloud credentials
  • Configure each provider for production use
  • Identify the failure modes (wrong audience, missing annotation, trust policy)
  • Recognise when SPIFFE/SPIRE is the right pattern for cross-cloud workload identity

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

External token issuers are cloud-provider integrations that exchange a Kubernetes-issued SA token for provider-native credentials. AWS IRSA exchanges for IAM role credentials; GCP Workload Identity exchanges for a GCP service account token; Azure Workload Identity exchanges for an Azure AD token. SPIFFE/SPIRE is the cross-cloud pattern for organisations that span providers. This lesson covers each integration, the configuration, and the production patterns.

AWS IRSA

IAM Roles for Service Accounts (IRSA) is the AWS mechanism for workload identity. The flow:

  1. A Kubernetes Pod projects an SA token with audience sts.amazonaws.com.
  2. The AWS SDK (or a sidecar) presents the token to AWS STS via the AssumeRoleWithWebIdentity API.
  3. STS verifies the token’s signature against the cluster’s OIDC issuer URL and the role’s trust policy.
  4. STS returns temporary IAM credentials (access key, secret key, session token).
  5. The workload uses the credentials to access AWS APIs (S3, SQS, DynamoDB, etc.).
sequenceDiagram
    participant Pod
    participant K8s as Kubernetes API
    participant STS as AWS STS
    participant AWS as AWS API
    Pod->>K8s: TokenRequest (audience: sts.amazonaws.com)
    K8s->>Pod: JWT signed by cluster OIDC issuer
    Pod->>STS: AssumeRoleWithWebIdentity (JWT, role ARN)
    STS->>STS: Verify signature, audience, trust policy
    STS->>Pod: IAM credentials
    Pod->>AWS: Access with IAM credentials

The configuration:

  1. Create an IAM role with a trust policy that trusts the cluster’s OIDC issuer:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::ACCOUNT:oidc-provider/OIDC_ISSUER_URL"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "OIDC_ISSUER_URL:sub": "system:serviceaccount:prod:api-sa"
        }
      }
    }
  ]
}

The sub condition restricts the role to a specific SA in a specific namespace.

  1. Annotate the SA with the role ARN:
apiVersion: v1
kind: ServiceAccount
metadata:
  name: api-sa
  namespace: prod
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT:role/myapp-role
  1. Project the token with audience sts.amazonaws.com:
spec:
  serviceAccountName: api-sa
  volumes:
  - name: aws-token
    projected:
      sources:
      - serviceAccountToken:
          path: aws-token
          audience: sts.amazonaws.com
          expirationSeconds: 900
  containers:
  - name: api
    volumeMounts:
    - name: aws-token
      mountPath: /var/run/secrets/kubernetes.io/serviceaccount  # EKS expects this path
      readOnly: true

The AWS SDK (or pod identity webhook) reads the token, exchanges it with STS, and uses the resulting credentials.

GCP Workload Identity

GCP Workload Identity is the GCP equivalent. The flow:

  1. A Kubernetes SA is bound to a GCP service account (GSA) via an IAM policy binding.
  2. A Pod projects an SA token with audience https://iam.googleapis.com/.
  3. The GCP client library presents the token to the metadata server (or to the IAM credentials API directly).
  4. IAM verifies the token and returns a GSA access token.
  5. The workload uses the token to access GCP APIs.

The configuration:

  1. Bind the KSA to a GSA:
gcloud iam service-accounts add-iam-policy-binding \
  --role roles/iam.workloadIdentityUser \
  --member "serviceAccount:PROJECT.svc.id.goog[prod/api-sa]" \
  myapp-gsa@PROJECT.iam.gserviceaccount.com
  1. Annotate the KSA with the GSA email:
apiVersion: v1
kind: ServiceAccount
metadata:
  name: api-sa
  namespace: prod
  annotations:
    iam.gke.io/gcp-service-account: myapp-gsa@PROJECT.iam.gserviceaccount.com
  1. Project the token with audience https://iam.googleapis.com/.

The metadata server (in GKE) or the client library handles the exchange.

Azure Workload Identity

Azure Workload Identity is the Azure equivalent:

  1. A Kubernetes SA is federated with an Azure AD application.
  2. A Pod projects an SA token with audience api://AzureADTokenExchange.
  3. The Azure SDK presents the token to the AAD token exchange endpoint.
  4. AAD returns an Azure AD token for the federated identity.

The configuration uses a azure-workload-identity annotation and a federated credential on the Azure AD application.

SPIFFE/SPIRE

For organisations that span multiple cloud providers or need a provider-agnostic workload identity, SPIFFE is the standard. The flow:

  1. SPIRE (the SPIFFE Runtime Environment) issues SVIDs (SPIFFE Verifiable Identity Documents) to workloads.
  2. The SVID is a JWT or X.509 document with a SPIFFE ID (e.g., spiffe://example.com/ns/prod/sa/api-sa).
  3. Workloads present the SVID to consumers; consumers verify against SPIRE’s trust bundle.

SPIFFE is the canonical pattern for zero-trust workload identity. It works across clouds, on premises, and at the edge.

Production patterns

  1. One provider per SA. A SA configured for IRSA should not also be configured for Workload Identity. Each SA has one identity per cloud.
  2. Trust policies scope by SA. The trust policy for an IAM role should restrict the sub to a specific SA in a specific namespace.
  3. Annotate with the role ARN / GSA email. The annotation is the link between the KSA and the cloud identity.
  4. Project the token with the right audience. IRSA uses sts.amazonaws.com; Workload Identity uses https://iam.googleapis.com/; Azure uses api://AzureADTokenExchange.
  5. Use the EKS pod identity webhook or equivalent. The webhook handles the token exchange automatically; the workload sees IAM credentials at the metadata server.

Production failure modes

  1. Wrong audience. The token’s audience is the API server’s; STS rejects. The fix is to set the audience to the provider’s.
  2. Missing trust policy. The IAM role’s trust policy does not include the cluster’s OIDC issuer. STS rejects. The fix is to register the issuer with IAM.
  3. Trust policy too broad. The trust policy accepts any SA in any namespace. A compromised SA in dev can assume the prod role. The fix is to restrict by sub.
  4. No annotation on the SA. The SA is not bound to the IAM role. The token is rejected. The fix is to add the annotation.
  5. Mixed providers. A Pod runs AWS IRSA and GCP Workload Identity in the same container. The providers’ tokens are mixed; one SDK reads the other’s token. The fix is one provider per Pod.

Cross-course references

  • The Linux course covers JWT and JWKS — the primitives that all of these integrations use.
  • The Observability course covers the audit log entries for token exchange operations.

Quiz

Knowledge check · 4 questions

  1. Q1. What audience must a ServiceAccount token have for AWS IRSA to work?

  2. Q2. The IAM role's trust policy for IRSA should accept any SA in any namespace; a tight policy would prevent legitimate use cases.

  3. Q3. Your Pod assumes an IAM role via IRSA. The STS call returns `InvalidIdentityToken: Wrong audience`. Why, and how do you fix it?

    The Pod's projected token has the default audience (`https://kubernetes.default.svc`) instead of `sts.amazonaws.com`. The Pod spec uses the default mount (API server audience) and does not have an explicit projection with the IRSA audience. STS verifies the token's audience against `sts.amazonaws.com` and rejects.

  4. Q4. Name three cloud-provider workload identity integrations and the audience each one requires.

Passing score: 75%. Answers are checked in this browser.

Production discipline

External token issuers are the right primitive for cloud-provider workload identity. AWS IRSA, GCP Workload Identity, and Azure Workload Identity each exchange a Kubernetes-issued SA token for provider-native credentials. The discipline is one provider per SA, tight trust policies, correct audiences, and the right annotations. A cluster that runs multiple providers in the same Pod has a configuration failure; a cluster that runs each provider in its own Pod with the right configuration has a workload identity programme that is auditable across providers. SPIFFE is the canonical pattern for organisations that span providers.