---
title: Utiliser WIF avec Kubernetes
url: https://platform.claude.com/docs/fr/manage-claude/wif-providers/kubernetes
description: Authentifiez-vous auprès de l'API Claude depuis des clusters Kubernetes autogérés à l'aide de jetons de compte de service projetés.
---

Les clusters Kubernetes autogérés (kubeadm, k3s, OpenShift et distributions sur site) signent des « JSON Web Tokens » (jetons web JSON), ou JWT, OIDC pour chaque pod via les [projected service account tokens](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#serviceaccount-token-volume-projection) (jetons de compte de service projetés). Le serveur d'API du cluster agit en tant qu'émetteur OIDC, et la revendication `sub` de chaque jeton suit la forme `system:serviceaccount:<namespace>:<service-account>`. Vous pouvez trouver l'URL de l'émetteur de votre cluster en lisant son document de découverte :

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

<Note>
  Le mécanisme décrit sur cette page (jeton de compte de service projeté, serveur d'API du cluster en tant qu'émetteur OIDC) est natif de Kubernetes lui-même, il sous-tend donc toutes les distributions Kubernetes. Si vous utilisez un service Kubernetes managé, les guides des fournisseurs cloud indiquent où trouver l'URL de l'émetteur géré par le fournisseur : [AWS (EKS)](https://platform.claude.com/docs/fr/manage-claude/wif-providers/aws#use-eks-projected-service-account-tokens), [Google Cloud (GKE)](https://platform.claude.com/docs/fr/manage-claude/wif-providers/gcp) ou [Azure (AKS)](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure). Si votre cluster exécute SPIRE, le SPIRE OIDC Discovery Provider est l'émetteur plutôt que le serveur d'API du cluster ; consultez [SPIFFE](https://platform.claude.com/docs/fr/manage-claude/wif-providers/spiffe). Pour toute autre distribution ou tout fournisseur managé non répertorié ici, suivez ce guide et utilisez l'URL de l'émetteur indiquée par votre cluster.
</Note>

## Prérequis

* Une familiarité avec les [concepts WIF](https://platform.claude.com/docs/fr/manage-claude/workload-identity-federation#concepts) : comptes de service, émetteurs de fédération et règles de fédération.

* Un cluster Kubernetes avec l'indicateur [`--service-account-issuer`](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/) configuré sur le serveur d'API. La plupart des distributions le définissent par défaut ; les clusters kubeadm utilisent généralement `https://kubernetes.default.svc.cluster.local`. Votre équipe plateforme peut confirmer la valeur si vous n'avez pas d'accès direct à la configuration du serveur d'API.

* L'un des éléments suivants afin qu'Anthropic puisse valider les signatures des jetons :

  * Le point de terminaison JWKS de l'émetteur est accessible depuis l'internet public via HTTPS sur le port 443, ou
  * Vous pouvez récupérer le JWKS depuis l'intérieur du cluster et l'enregistrer en mode `inline` (traité dans [Configurer Anthropic](https://platform.claude.com/docs/fr/manage-claude/wif-providers/kubernetes#configure-anthropic)).

* L'autorisation de créer des comptes de service, des émetteurs de fédération et des règles de fédération dans la Claude Console pour votre organisation Anthropic.

## Configurer Kubernetes

Projetez un jeton de compte de service dans votre pod avec l'audience et la durée de vie attendues par votre règle de fédération. La projection `serviceAccountToken` écrit un nouveau JWT dans le chemin de montage et le renouvelle avant que `expirationSeconds` ne soit écoulé.

```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
```

Le jeton émis pour ce pod contient `sub: "system:serviceaccount:inference:inference-worker"` et `aud: ["https://api.anthropic.com"]`.

## Configurer Anthropic

Dans la Claude Console, accédez à la page [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), cliquez sur **Connect workload** et sélectionnez la tuile **Kubernetes**. L'assistant vous guide dans l'enregistrement de l'émetteur, la création d'un compte de service et la création d'une règle de fédération.

L'assistant crée ces ressources pour vous. Utilisez les valeurs suivantes, que vous les saisissiez dans l'assistant ou que vous les envoyiez à l'[Admin API](https://platform.claude.com/docs/fr/manage-claude/wif-admin-api) :

**Émetteur de fédération :** de nombreux clusters autogérés utilisent une URL d'émetteur telle que `https://kubernetes.default.svc.cluster.local` qui n'est pas accessible depuis l'internet public. Si c'est le cas de votre cluster, choisissez la source JWKS **inline** et collez les clés du cluster. Récupérez-les depuis l'intérieur du cluster :

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

Configurez ensuite l'émetteur avec le contenu du tableau `keys` renvoyé (et non l'enveloppe `{"keys": [...]}` qui l'entoure) :

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

En mode `inline`, l'`issuer_url` est uniquement comparée à la revendication `iss` du JWT ; Anthropic ne tente jamais de la joindre. Si votre émetteur est accessible publiquement, utilisez plutôt `"jwks": {"type": "discovery"}`.

<Warning>
  Avec des clés `inline`, vous êtes responsable de la mise à jour de l'émetteur lorsque le cluster renouvelle sa clé de signature des comptes de service. Le renouvellement est rare (généralement uniquement lors des mises à niveau du cluster), mais les échanges de jetons échouent avec une erreur de signature jusqu'à ce que vous transmettiez le nouveau JWKS.
</Warning>

**Règle de fédération :** faites correspondre la revendication `sub` du compte de service et l'audience que vous avez définie sur le jeton projeté.

```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
}
```

Soyez aussi précis que la charge de travail le permet. N'élargissez `subject_prefix` à `system:serviceaccount:inference:*` (le `*` final en fait une correspondance par préfixe) que si tous les comptes de service de l'espace de noms doivent être associés au même compte de service Anthropic. Ajoutez l'ID `fdrl_...` de la règle à la variable d'environnement `ANTHROPIC_FEDERATION_RULE_ID` de votre pod.

## Obtenir et utiliser le jeton

La spécification de pod dans [Configurer Kubernetes](https://platform.claude.com/docs/fr/manage-claude/wif-providers/kubernetes#configure-kubernetes) définit `ANTHROPIC_IDENTITY_TOKEN_FILE` sur le chemin de montage projeté, ainsi que `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID` et `ANTHROPIC_WORKSPACE_ID`. Une fois ces éléments en place, le SDK lit le jeton depuis le disque à chaque échange et actualise automatiquement le jeton d'accès Anthropic.

<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

  # Lit ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID et ANTHROPIC_WORKSPACE_ID
  # depuis l'environnement du pod.
  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";

  // Lit ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID et ANTHROPIC_WORKSPACE_ID
  // depuis l'environnement du pod.
  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
  // Lit ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID et ANTHROPIC_WORKSPACE_ID
  // depuis l'environnement du pod.
  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#
  // Lit ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID et ANTHROPIC_WORKSPACE_ID
  // depuis l'environnement du pod.
  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
  # Lit ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID et 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;

  // Lit ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  // ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID et 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"

  # Lit ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID et 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>

## Vérifier la configuration

Un échange réussi renvoie un `access_token` commençant par `sk-ant-oat01-` et une valeur `expires_in` en secondes. Si l'échange échoue avec la réponse opaque `401` `authentication_error` (message `Authentication failed`), consultez la [page d'historique d'authentification](https://platform.claude.com/settings/workload-identity-federation?tab=history) dans la Claude Console pour connaître le motif du refus et reportez-vous à [Dépanner un échange échoué](https://platform.claude.com/docs/fr/manage-claude/wif-reference#troubleshoot-a-failed-exchange) ; la cause la plus fréquente côté Kubernetes est une non-concordance des clés JWKS (en mode `inline`, récupérez-les à nouveau avec `kubectl get --raw /openid/v1/jwks` et mettez à jour l'émetteur).

## Restreindre la portée de votre règle

<Warning>
  Un `subject_prefix` de `system:serviceaccount:*` correspond à tous les comptes de service du cluster, de sorte que n'importe quel pod peut obtenir un jeton Anthropic fédéré. Sans critère de correspondance `audience`, la règle correspond également aux jetons à audience par défaut du cluster, que chaque pod possède déjà sous forme projetée.
</Warning>

Verrouillez le bloc `match` de la règle sur la portée la plus étroite adaptée à votre cas d'utilisation :

* **Fixez l'espace de noms et le nom du compte de service :** utilisez la valeur complète `system:serviceaccount:<namespace>:<name>` sans `*` final.
* **Définissez toujours une audience :** exigez `audience` sur la règle et définissez la même valeur sur la projection `serviceAccountToken` du pod afin que les jetons à audience par défaut soient rejetés.
* **Utilisez une règle distincte par espace de noms :** créez une règle et un compte de service Anthropic distincts pour chaque espace de noms plutôt que d'élargir une seule règle.
* **Limitez les émetteurs à JWKS inline à un seul cluster :** lorsque plusieurs clusters partagent une URL d'émetteur, enregistrez le JWKS de chaque cluster comme son propre émetteur de fédération et liez les règles uniquement à cet émetteur.

## Étapes suivantes

* [Workload Identity Federation](https://platform.claude.com/docs/fr/manage-claude/workload-identity-federation) : concepts, flux d'échange de jetons et options de configuration du SDK.
* [Référence WIF](https://platform.claude.com/docs/fr/manage-claude/wif-reference) : variables d'environnement, modes de source JWKS et modes de correspondance des règles.
