Loading...
    • Messages
    • Managed Agents
    • Admin
    Search...
    ⌘K
    Organization
    Admin API overviewWorkspaces
    Authentication
    OverviewWorkload Identity FederationWIF reference
    AWSGoogle CloudMicrosoft AzureGitHub ActionsKubernetesOkta
    Monitoring
    Usage and Cost APIRate Limits APIClaude Code Analytics API
    Data & compliance
    Data residencyAPI and data retention
    Log in
    Kubernetes
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...

    Solutions

    • AI agents
    • Code modernization
    • Coding
    • Customer support
    • Education
    • Financial services
    • Government
    • Life sciences

    Partners

    • Amazon Bedrock
    • Google Cloud's Vertex AI

    Learn

    • Blog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Company

    • Anthropic
    • Careers
    • Economic Futures
    • Research
    • News
    • Responsible Scaling Policy
    • Security and compliance
    • Transparency

    Learn

    • Blog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Help and security

    • Availability
    • Status
    • Support
    • Discord

    Terms and policies

    • Privacy policy
    • Responsible disclosure policy
    • Terms of service: Commercial
    • Terms of service: Consumer
    • Usage policy
    Admin/Identity providers

    Use WIF with Kubernetes

    Authenticate to the Claude API from self-managed Kubernetes clusters using projected service account tokens.

    Self-managed Kubernetes clusters (kubeadm, k3s, OpenShift, and on-premises distributions) sign OIDC JSON Web Tokens (JWTs) for every pod through projected service account tokens. The cluster's API server acts as the OIDC issuer, and each token's sub claim follows the form system:serviceaccount:<namespace>:<service-account>. You can find your cluster's issuer URL by reading its discovery document:

    cURL
    kubectl get --raw /.well-known/openid-configuration | jq -r .issuer

    The mechanism on this page (projected service-account token, cluster API server as the OIDC issuer) is native to Kubernetes itself, so it underlies every Kubernetes distribution. If you run on a managed Kubernetes service, the cloud provider guides walk through where to find the provider-managed issuer URL: AWS (EKS), Google Cloud (GKE), or Azure (AKS). For any other distribution or a managed provider not listed there, follow this guide and use the issuer URL your cluster reports.

    Prerequisites

    • Familiarity with WIF concepts: service accounts, federation issuers, and federation rules.
    • A Kubernetes cluster with the --service-account-issuer flag configured on the API server. Most distributions set this by default; kubeadm clusters typically use https://kubernetes.default.svc.cluster.local. Your platform team can confirm the value if you don't have direct access to the API server configuration.
    • One of the following so Anthropic can validate token signatures:
      • The issuer's JWKS endpoint is reachable from the public internet over HTTPS on port 443, or
      • You can fetch the JWKS from inside the cluster and register it in inline mode (covered in Configure Anthropic).
    • Permission to create service accounts, federation issuers, and federation rules in the Claude Console for your Anthropic organization.

    Configure Kubernetes

    Project a service account token into your pod with the audience and lifetime that your federation rule expects. The serviceAccountToken projection writes a fresh JWT to the mount path and rotates it before expirationSeconds elapses.

    Pod
    apiVersion: v1
    kind: Pod
    metadata:
      name: inference-worker
      namespace: inference
    spec:
      serviceAccountName: inference-worker
      volumes:
        - name: anthropic-token
          projected:
            sources:
              - serviceAccountToken:
                  audience: https://api.anthropic.com
                  expirationSeconds: 3600
                  path: token
      containers:
        - name: app
          image: your-registry/inference-worker:latest
          env:
            - name: ANTHROPIC_IDENTITY_TOKEN_FILE
              value: /var/run/secrets/anthropic.com/token
            - name: ANTHROPIC_FEDERATION_RULE_ID
              value: fdrl_...
            - name: ANTHROPIC_ORGANIZATION_ID
              value: 00000000-0000-0000-0000-000000000000
            - name: ANTHROPIC_SERVICE_ACCOUNT_ID
              value: svac_...
          volumeMounts:
            - name: anthropic-token
              mountPath: /var/run/secrets/anthropic.com
              readOnly: true

    The token issued for this pod carries sub: "system:serviceaccount:inference:inference-worker" and aud: ["https://api.anthropic.com"].

    Configure Anthropic

    Follow the setup walkthrough to register a federation issuer, create an Anthropic service account, and create a federation rule in the Claude Console. Use these Kubernetes-specific values.

    Federation issuer: Many self-managed clusters use an issuer URL such as https://kubernetes.default.svc.cluster.local that is not reachable from the public internet. If that applies to your cluster, choose the inline JWKS source and paste the cluster's keys. Fetch them from inside the cluster:

    cURL
    kubectl get --raw /openid/v1/jwks

    Then configure the issuer with the contents of the returned keys array (not the surrounding {"keys": [...]} wrapper):

    {
      "name": "onprem-k8s",
      "issuer_url": "https://kubernetes.default.svc.cluster.local",
      "jwks_source": "inline",
      "jwks_keys": [{ "kty": "RSA", "kid": "...", "n": "...", "e": "AQAB" }]
    }

    In inline mode the issuer_url is only compared against the JWT's iss claim; Anthropic never attempts to reach it. If your issuer is publicly reachable, use "jwks_source": "discovery" instead and omit jwks_keys.

    With inline keys you are responsible for updating the issuer when the cluster rotates its service account signing key. Rotation is rare (typically only during cluster upgrades), but token exchanges fail with a signature error until you push the new JWKS.

    Federation rule: Match the service account's sub claim and the audience you set on the projected token.

    {
      "name": "onprem-inference",
      "issuer_id": "fdis_...",
      "match": {
        "subject_prefix": "system:serviceaccount:inference:inference-worker",
        "audience": "https://api.anthropic.com"
      },
      "target": {
        "type": "service_account",
        "service_account_id": "svac_..."
      },
      "workspace_id": "wrkspc_...",
      "oauth_scope": "workspace:developer",
      "token_lifetime_seconds": 600
    }

    Be as specific as the workload allows. Loosen subject_prefix to system:serviceaccount:inference:* (the trailing * makes it a prefix match) only if every service account in the namespace should map to the same Anthropic service account. Add the rule's fdrl_... ID to your pod's ANTHROPIC_FEDERATION_RULE_ID environment variable.

    Acquire and use the token

    The pod spec in Configure Kubernetes sets ANTHROPIC_IDENTITY_TOKEN_FILE to the projected mount path, along with ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID, and ANTHROPIC_SERVICE_ACCOUNT_ID. With those in place, the SDK reads the token from disk on every exchange and refreshes the Anthropic access token automatically.

    import anthropic
    
    # Reads ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
    # ANTHROPIC_ORGANIZATION_ID, and ANTHROPIC_SERVICE_ACCOUNT_ID
    # from the pod's environment.
    client = anthropic.Anthropic()
    
    message = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello, Claude"}],
    )
    print(message.content[0].text)

    Verify the setup

    A successful exchange returns an access_token beginning with sk-ant-oat01- and an expires_in value in seconds. On 400 invalid_grant, see Troubleshoot a failed exchange; the most common Kubernetes-side cause is a JWKS key mismatch (for inline mode, re-fetch with kubectl get --raw /openid/v1/jwks and update the issuer).

    Scope your rule

    A subject_prefix of system:serviceaccount:* matches every service account in the cluster, so any pod can obtain a federated Anthropic token. Without an audience matcher, the rule also matches the cluster's default-audience tokens, which every pod already has projected.

    Lock the rule's match block to the narrowest scope that fits your use case:

    • Pin namespace and service-account name: Use the full system:serviceaccount:<namespace>:<name> value with no trailing *.
    • Always set an audience: Require audience on the rule and set the same value on the pod's serviceAccountToken projection so default-audience tokens are rejected.
    • Use a separate rule per namespace: Create a distinct rule and Anthropic service account for each namespace rather than widening one rule.
    • Scope inline-JWKS issuers to one cluster: When several clusters share an issuer URL, register each cluster's JWKS as its own federation issuer and bind rules to that issuer only.

    Next steps

    • Workload Identity Federation: concepts, the token-exchange flow, and SDK configuration options.
    • WIF reference: environment variables, JWKS source modes, and rule match modes.

    Was this page helpful?

    • Prerequisites
    • Configure Kubernetes
    • Configure Anthropic
    • Acquire and use the token
    • Verify the setup
    • Scope your rule
    • Next steps