---
title: WIF mit Kubernetes verwenden
url: https://platform.claude.com/docs/de/manage-claude/wif-providers/kubernetes
description: Authentifiziere dich gegenüber der Claude API aus selbstverwalteten Kubernetes-Clustern mithilfe projizierter Service-Account-Token.
---

Selbstverwaltete Kubernetes-Cluster (kubeadm, k3s, OpenShift und On-Premise-Distributionen) signieren OIDC JSON Web Tokens (JWTs) für jeden Pod über [projizierte Service-Account-Tokens](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#serviceaccount-token-volume-projection). Der API-Server des Clusters fungiert als OIDC-Issuer, und der `sub`-Claim jedes Tokens hat die Form `system:serviceaccount:<namespace>:<service-account>`. Du findest die Issuer-URL deines Clusters, indem du sein Discovery-Dokument ausliest:

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

<Note>
  Der Mechanismus auf dieser Seite (projiziertes Service-Account-Token, Cluster-API-Server als OIDC-Issuer) ist nativ in Kubernetes selbst verankert und liegt daher jeder Kubernetes-Distribution zugrunde. Wenn du einen verwalteten Kubernetes-Dienst nutzt, zeigen dir die Leitfäden der Cloud-Anbieter, wo du die vom Anbieter verwaltete Issuer-URL findest: [AWS (EKS)](https://platform.claude.com/docs/de/manage-claude/wif-providers/aws#use-eks-projected-service-account-tokens), [Google Cloud (GKE)](https://platform.claude.com/docs/de/manage-claude/wif-providers/gcp) oder [Azure (AKS)](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure). Wenn dein Cluster SPIRE ausführt, ist der SPIRE OIDC Discovery Provider der Issuer und nicht der Cluster-API-Server; siehe [SPIFFE](https://platform.claude.com/docs/de/manage-claude/wif-providers/spiffe). Für jede andere Distribution oder einen dort nicht aufgeführten verwalteten Anbieter folge diesem Leitfaden und verwende die Issuer-URL, die dein Cluster meldet.
</Note>

## Voraussetzungen

* Vertrautheit mit den [WIF-Konzepten](https://platform.claude.com/docs/de/manage-claude/workload-identity-federation#concepts): Service-Accounts, Federation-Issuer und Federation-Regeln.

* Ein Kubernetes-Cluster, bei dem das Flag [`--service-account-issuer`](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/) auf dem API-Server konfiguriert ist. Die meisten Distributionen setzen dies standardmäßig; kubeadm-Cluster verwenden typischerweise `https://kubernetes.default.svc.cluster.local`. Dein Plattform-Team kann den Wert bestätigen, falls du keinen direkten Zugriff auf die API-Server-Konfiguration hast.

* Eine der folgenden Optionen, damit Anthropic Token-Signaturen validieren kann:

  * Der JWKS-Endpunkt des Issuers ist aus dem öffentlichen Internet über HTTPS auf Port 443 erreichbar, oder
  * Du kannst das JWKS aus dem Cluster heraus abrufen und es im `inline`-Modus registrieren (behandelt in [Anthropic konfigurieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/kubernetes#configure-anthropic)).

* Berechtigung zum Erstellen von Service-Accounts, Federation-Issuern und Federation-Regeln in der Claude Console für deine Anthropic-Organisation.

## Kubernetes konfigurieren

Projiziere ein Service-Account-Token in deinen Pod mit der Audience und Lebensdauer, die deine Federation-Regel erwartet. Die `serviceAccountToken`-Projektion schreibt ein frisches JWT in den Mount-Pfad und rotiert es, bevor `expirationSeconds` abläuft.

```yaml 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_...
        - name: ANTHROPIC_WORKSPACE_ID  # required when the rule covers multiple workspaces
          value: wrkspc_...
      volumeMounts:
        - name: anthropic-token
          mountPath: /var/run/secrets/anthropic.com
          readOnly: true
```

Das für diesen Pod ausgestellte Token trägt `sub: "system:serviceaccount:inference:inference-worker"` und `aud: ["https://api.anthropic.com"]`.

## Anthropic konfigurieren

Gehe in der Claude Console zur Seite [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), klicke auf **Connect workload** und wähle die Kachel **Kubernetes**. Der Assistent führt dich durch die Registrierung des Issuers, das Erstellen eines Service-Accounts und das Erstellen einer Federation-Regel.

Der Assistent erstellt diese Ressourcen für dich. Verwende die folgenden Werte, unabhängig davon, ob du sie im Assistenten eingibst oder an die [Admin API](https://platform.claude.com/docs/de/manage-claude/wif-admin-api) sendest:

**Federation-Issuer:** Viele selbstverwaltete Cluster verwenden eine Issuer-URL wie `https://kubernetes.default.svc.cluster.local`, die aus dem öffentlichen Internet nicht erreichbar ist. Wenn das auf deinen Cluster zutrifft, wähle die JWKS-Quelle **inline** und füge die Schlüssel des Clusters ein. Rufe sie aus dem Cluster heraus ab:

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

Konfiguriere dann den Issuer mit dem Inhalt des zurückgegebenen `keys`-Arrays (nicht mit dem umgebenden `{"keys": [...]}`-Wrapper):

```json
{
  "name": "onprem-k8s",
  "issuer_url": "https://kubernetes.default.svc.cluster.local",
  "jwks": {
    "type": "inline",
    "keys": [{ "kty": "RSA", "kid": "...", "n": "...", "e": "AQAB" }]
  }
}
```

Im `inline`-Modus wird die `issuer_url` nur mit dem `iss`-Claim des JWT verglichen; Anthropic versucht nie, sie zu erreichen. Wenn dein Issuer öffentlich erreichbar ist, verwende stattdessen `"jwks": {"type": "discovery"}`.

<Warning>
  Bei `inline`-Schlüsseln bist du dafür verantwortlich, den Issuer zu aktualisieren, wenn der Cluster seinen Service-Account-Signaturschlüssel rotiert. Eine Rotation ist selten (typischerweise nur bei Cluster-Upgrades), aber Token-Austausche schlagen mit einem Signaturfehler fehl, bis du das neue JWKS überträgst.
</Warning>

**Federation-Regel:** Gleiche den `sub`-Claim des Service-Accounts und die Audience ab, die du auf dem projizierten Token gesetzt hast.

```json
{
  "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
}
```

Sei so spezifisch, wie es der Workload erlaubt. Lockere `subject_prefix` nur dann auf `system:serviceaccount:inference:*` (das abschließende `*` macht daraus einen Präfix-Abgleich), wenn jeder Service-Account im Namespace auf denselben Anthropic-Service-Account abgebildet werden soll. Füge die `fdrl_...`-ID der Regel zur Umgebungsvariable `ANTHROPIC_FEDERATION_RULE_ID` deines Pods hinzu.

## Token abrufen und verwenden

Die Pod-Spezifikation in [Kubernetes konfigurieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/kubernetes#configure-kubernetes) setzt `ANTHROPIC_IDENTITY_TOKEN_FILE` auf den projizierten Mount-Pfad, zusammen mit `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID` und `ANTHROPIC_WORKSPACE_ID`. Sind diese gesetzt, liest das SDK das Token bei jedem Austausch von der Festplatte und erneuert das Anthropic-Zugriffstoken automatisch.

<CodeGroup>
  ```bash cURL
  JWT=$(cat "$ANTHROPIC_IDENTITY_TOKEN_FILE")

  ACCESS_TOKEN=$(curl -sS https://api.anthropic.com/v1/oauth/token \
    -H "content-type: application/json" \
    --data @- <<JSON | jq -r .access_token
  {
    "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
    "assertion": "$JWT",
    "federation_rule_id": "$ANTHROPIC_FEDERATION_RULE_ID",
    "organization_id": "$ANTHROPIC_ORGANIZATION_ID",
    "service_account_id": "$ANTHROPIC_SERVICE_ACCOUNT_ID",
    "workspace_id": "$ANTHROPIC_WORKSPACE_ID"
  }
  JSON
  )

  curl https://api.anthropic.com/v1/messages \
    -H "authorization: Bearer $ACCESS_TOKEN" \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "messages": [{"role": "user", "content": "Hello, Claude"}]
    }' | jq -r '.content[] | select(.type == "text") | .text'
  ```

  ```python Python
  import anthropic

  # Liest ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID und ANTHROPIC_WORKSPACE_ID
  # aus der Umgebung des Pods.
  client = anthropic.Anthropic()

  message = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      messages=[{"role": "user", "content": "Hello, Claude"}],
  )
  print(next(block.text for block in message.content if block.type == "text"))
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";

  // Liest ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID und ANTHROPIC_WORKSPACE_ID
  // aus der Umgebung des Pods.
  const client = new Anthropic();

  const message = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello, Claude" }]
  });
  for (const block of message.content) {
    if (block.type === "text") {
      console.log(block.text);
    }
  }
  ```

  ```go Go
  // Liest ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID und ANTHROPIC_WORKSPACE_ID
  // aus der Umgebung des Pods.
  client := anthropic.NewClient()

  message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Hello, Claude")),
  	},
  })
  if err != nil {
  	panic(err)
  }
  for _, block := range message.Content {
  	if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  		fmt.Println(textBlock.Text)
  		break
  	}
  }
  ```

  ```java Java
  AnthropicClient client = AnthropicOkHttpClient.fromEnv();

  var message = client.messages().create(MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(1024)
          .addUserMessage("Hello, Claude")
          .build());

  IO.println(message.content());
  ```

  ```csharp C#
  // Liest ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID und ANTHROPIC_WORKSPACE_ID
  // aus der Umgebung des Pods.
  using var client = new AnthropicClient();

  var message = await client.Messages.Create(new()
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Messages = [new() { Role = Role.User, Content = "Hello, Claude" }],
  });
  foreach (var block in message.Content)
  {
      if (block.Value is TextBlock textBlock)
      {
          Console.WriteLine(textBlock.Text);
      }
  }
  ```

  ```bash CLI
  # Liest ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID und ANTHROPIC_IDENTITY_TOKEN_FILE
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello, Claude"}'
  ```

  ```php PHP
  use Anthropic\Client;

  // Liest ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  // ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID und ANTHROPIC_IDENTITY_TOKEN_FILE
  $client = new Client();

  $message = $client->messages->create(
      model: 'claude-opus-5-5',
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Hello, Claude']],
  );
  $textBlock = array_find($message->content, static fn ($block): bool => $block->type === 'text');
  echo $textBlock->text, PHP_EOL;
  ```

  ```ruby Ruby
  require "anthropic"

  # Liest ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID und ANTHROPIC_IDENTITY_TOKEN_FILE
  client = Anthropic::Client.new

  message = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello, Claude"}]
  )
  puts message.content.find { it.type == :text }.text
  ```
</CodeGroup>

## Einrichtung überprüfen

Ein erfolgreicher Austausch gibt ein `access_token`, das mit `sk-ant-oat01-` beginnt, und einen `expires_in`-Wert in Sekunden zurück. Wenn der Austausch mit der undurchsichtigen `401`-`authentication_error`-Antwort (Meldung `Authentication failed`) fehlschlägt, prüfe die [Seite mit dem Authentifizierungsverlauf](https://platform.claude.com/settings/workload-identity-federation?tab=history) in der Claude Console auf den Ablehnungsgrund und siehe [Einen fehlgeschlagenen Austausch beheben](https://platform.claude.com/docs/de/manage-claude/wif-reference#troubleshoot-a-failed-exchange); die häufigste Ursache auf Kubernetes-Seite ist eine Nichtübereinstimmung der JWKS-Schlüssel (rufe sie im `inline`-Modus erneut mit `kubectl get --raw /openid/v1/jwks` ab und aktualisiere den Issuer).

## Geltungsbereich deiner Regel festlegen

<Warning>
  Ein `subject_prefix` von `system:serviceaccount:*` passt auf jeden Service-Account im Cluster, sodass jeder Pod ein föderiertes Anthropic-Token erhalten kann. Ohne einen `audience`-Matcher passt die Regel außerdem auf die Default-Audience-Token des Clusters, die bereits in jeden Pod projiziert sind.
</Warning>

Beschränke den `match`-Block der Regel auf den engsten Geltungsbereich, der zu deinem Anwendungsfall passt:

* **Namespace und Service-Account-Namen festlegen:** Verwende den vollständigen Wert `system:serviceaccount:<namespace>:<name>` ohne abschließendes `*`.
* **Immer eine Audience setzen:** Verlange `audience` in der Regel und setze denselben Wert in der `serviceAccountToken`-Projektion des Pods, damit Default-Audience-Token abgelehnt werden.
* **Eine separate Regel pro Namespace verwenden:** Erstelle für jeden Namespace eine eigene Regel und einen eigenen Anthropic-Service-Account, anstatt eine Regel auszuweiten.
* **Inline-JWKS-Issuer auf einen Cluster beschränken:** Wenn mehrere Cluster eine Issuer-URL teilen, registriere das JWKS jedes Clusters als eigenen Federation-Issuer und binde Regeln nur an diesen Issuer.

## Nächste Schritte

* [Workload Identity Federation](https://platform.claude.com/docs/de/manage-claude/workload-identity-federation): Konzepte, der Token-Austausch-Ablauf und SDK-Konfigurationsoptionen.
* [WIF-Referenz](https://platform.claude.com/docs/de/manage-claude/wif-reference): Umgebungsvariablen, JWKS-Quellmodi und Regel-Abgleichsmodi.
