---
title: Usar WIF com Kubernetes
url: https://platform.claude.com/docs/pt-BR/manage-claude/wif-providers/kubernetes
description: Autentique-se na Claude API a partir de clusters Kubernetes autogerenciados usando tokens de conta de serviço projetados.
---

Clusters Kubernetes autogerenciados (kubeadm, k3s, OpenShift e distribuições on-premise) assinam JSON Web Tokens (JWTs) OIDC para cada pod por meio de [projected service account tokens](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#serviceaccount-token-volume-projection) (tokens de conta de serviço projetados). O servidor de API do cluster atua como o emissor OIDC, e a claim `sub` de cada token segue o formato `system:serviceaccount:<namespace>:<service-account>`. Você pode encontrar a URL do emissor do seu cluster lendo seu documento de descoberta:

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

<Note>
  O mecanismo desta página (token de conta de serviço projetado, servidor de API do cluster como emissor OIDC) é nativo do próprio Kubernetes, portanto está na base de toda distribuição Kubernetes. Se você executa em um serviço Kubernetes gerenciado, os guias dos provedores de nuvem mostram onde encontrar a URL do emissor gerenciada pelo provedor: [AWS (EKS)](https://platform.claude.com/docs/pt-BR/manage-claude/wif-providers/aws#use-eks-projected-service-account-tokens), [Google Cloud (GKE)](https://platform.claude.com/docs/pt-BR/manage-claude/wif-providers/gcp) ou [Azure (AKS)](https://platform.claude.com/docs/pt-BR/manage-claude/wif-providers/azure). Se o seu cluster executa SPIRE, o SPIRE OIDC Discovery Provider é o emissor em vez do servidor de API do cluster; consulte [SPIFFE](https://platform.claude.com/docs/pt-BR/manage-claude/wif-providers/spiffe). Para qualquer outra distribuição ou um provedor gerenciado não listado ali, siga este guia e use a URL do emissor que o seu cluster informa.
</Note>

## Pré-requisitos

* Familiaridade com os [conceitos de WIF](https://platform.claude.com/docs/pt-BR/manage-claude/workload-identity-federation#concepts): contas de serviço, emissores de federação e regras de federação.

* Um cluster Kubernetes com a flag [`--service-account-issuer`](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/) configurada no servidor de API. A maioria das distribuições define isso por padrão; clusters kubeadm normalmente usam `https://kubernetes.default.svc.cluster.local`. Sua equipe de plataforma pode confirmar o valor se você não tiver acesso direto à configuração do servidor de API.

* Uma das seguintes opções para que a Anthropic possa validar as assinaturas dos tokens:

  * O endpoint JWKS do emissor é acessível a partir da internet pública via HTTPS na porta 443, ou
  * Você pode obter o JWKS de dentro do cluster e registrá-lo no modo `inline` (abordado em [Configurar a Anthropic](https://platform.claude.com/docs/pt-BR/manage-claude/wif-providers/kubernetes#configure-anthropic)).

* Permissão para criar contas de serviço, emissores de federação e regras de federação no Claude Console para a sua organização Anthropic.

## Configurar o Kubernetes

Projete um token de conta de serviço no seu pod com a audiência e o tempo de vida que a sua regra de federação espera. A projeção `serviceAccountToken` grava um JWT novo no caminho de montagem e o rotaciona antes que `expirationSeconds` expire.

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

O token emitido para este pod carrega `sub: "system:serviceaccount:inference:inference-worker"` e `aud: ["https://api.anthropic.com"]`.

## Configurar a Anthropic

No Claude Console, acesse a página [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), clique em **Connect workload** e selecione o bloco **Kubernetes**. O assistente orienta você no registro do emissor, na criação de uma conta de serviço e na criação de uma regra de federação.

O assistente cria esses recursos para você. Use os seguintes valores, seja inserindo-os no assistente ou enviando-os para a [Admin API](https://platform.claude.com/docs/pt-BR/manage-claude/wif-admin-api):

**Emissor de federação:** Muitos clusters autogerenciados usam uma URL de emissor como `https://kubernetes.default.svc.cluster.local`, que não é acessível a partir da internet pública. Se isso se aplica ao seu cluster, escolha a origem de JWKS **inline** e cole as chaves do cluster. Obtenha-as de dentro do cluster:

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

Em seguida, configure o emissor com o conteúdo do array `keys` retornado (não o wrapper `{"keys": [...]}` ao redor):

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

No modo `inline`, a `issuer_url` é apenas comparada com a claim `iss` do JWT; a Anthropic nunca tenta acessá-la. Se o seu emissor for acessível publicamente, use `"jwks": {"type": "discovery"}` em vez disso.

<Warning>
  Com chaves `inline`, você é responsável por atualizar o emissor quando o cluster rotacionar sua chave de assinatura de conta de serviço. A rotação é rara (normalmente apenas durante atualizações do cluster), mas as trocas de token falham com um erro de assinatura até que você envie o novo JWKS.
</Warning>

**Regra de federação:** Faça a correspondência com a claim `sub` da conta de serviço e com a audiência que você definiu no token projetado.

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

Seja tão específico quanto a carga de trabalho permitir. Afrouxe `subject_prefix` para `system:serviceaccount:inference:*` (o `*` final o torna uma correspondência por prefixo) somente se todas as contas de serviço no namespace devem ser mapeadas para a mesma conta de serviço Anthropic. Adicione o ID `fdrl_...` da regra à variável de ambiente `ANTHROPIC_FEDERATION_RULE_ID` do seu pod.

## Obter e usar o token

A especificação do pod em [Configurar o Kubernetes](https://platform.claude.com/docs/pt-BR/manage-claude/wif-providers/kubernetes#configure-kubernetes) define `ANTHROPIC_IDENTITY_TOKEN_FILE` como o caminho de montagem projetado, junto com `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID` e `ANTHROPIC_WORKSPACE_ID`. Com isso configurado, o SDK lê o token do disco em cada troca e renova o token de acesso da Anthropic automaticamente.

<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

  # Lê ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID e ANTHROPIC_WORKSPACE_ID
  # do ambiente do 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";

  // Lê ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID e ANTHROPIC_WORKSPACE_ID
  // do ambiente do 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
  // Lê ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID e ANTHROPIC_WORKSPACE_ID
  // do ambiente do 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#
  // Lê ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID e ANTHROPIC_WORKSPACE_ID
  // do ambiente do 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
  # Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e 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;

  // Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  // ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e 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"

  # Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e 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>

## Verificar a configuração

Uma troca bem-sucedida retorna um `access_token` começando com `sk-ant-oat01-` e um valor `expires_in` em segundos. Se a troca falhar com a resposta opaca `401` `authentication_error` (mensagem `Authentication failed`), verifique a [página de histórico de autenticação](https://platform.claude.com/settings/workload-identity-federation?tab=history) no Claude Console para ver o motivo da negação e consulte [Solucionar problemas de uma troca com falha](https://platform.claude.com/docs/pt-BR/manage-claude/wif-reference#troubleshoot-a-failed-exchange); a causa mais comum do lado do Kubernetes é uma incompatibilidade de chave JWKS (no modo `inline`, busque novamente com `kubectl get --raw /openid/v1/jwks` e atualize o emissor).

## Delimitar o escopo da sua regra

<Warning>
  Um `subject_prefix` de `system:serviceaccount:*` corresponde a todas as contas de serviço no cluster, portanto qualquer pod pode obter um token federado da Anthropic. Sem um matcher `audience`, a regra também corresponde aos tokens de audiência padrão do cluster, que todo pod já tem projetados.
</Warning>

Restrinja o bloco `match` da regra ao escopo mais estreito que atenda ao seu caso de uso:

* **Fixe o namespace e o nome da conta de serviço:** Use o valor completo `system:serviceaccount:<namespace>:<name>` sem `*` final.
* **Sempre defina uma audiência:** Exija `audience` na regra e defina o mesmo valor na projeção `serviceAccountToken` do pod para que tokens de audiência padrão sejam rejeitados.
* **Use uma regra separada por namespace:** Crie uma regra e uma conta de serviço Anthropic distintas para cada namespace em vez de ampliar uma única regra.
* **Delimite emissores com JWKS inline a um único cluster:** Quando vários clusters compartilham uma URL de emissor, registre o JWKS de cada cluster como seu próprio emissor de federação e vincule regras somente a esse emissor.

## Próximos passos

* [Workload Identity Federation](https://platform.claude.com/docs/pt-BR/manage-claude/workload-identity-federation): conceitos, o fluxo de troca de tokens e opções de configuração do SDK.
* [Referência de WIF](https://platform.claude.com/docs/pt-BR/manage-claude/wif-reference): variáveis de ambiente, modos de origem de JWKS e modos de correspondência de regras.
