---
title: Использование WIF с Kubernetes
url: https://platform.claude.com/docs/ru/manage-claude/wif-providers/kubernetes
description: Аутентификация в Claude API из самостоятельно управляемых кластеров Kubernetes с помощью проецируемых токенов сервисных аккаунтов.
---

Самостоятельно управляемые кластеры Kubernetes (kubeadm, k3s, OpenShift и локальные дистрибутивы) подписывают OIDC «JSON Web Tokens» (веб-токены JSON), или JWT, для каждого пода с помощью [проецируемых токенов сервисных аккаунтов](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#serviceaccount-token-volume-projection). API-сервер кластера выступает в роли издателя OIDC, а claim `sub` каждого токена имеет вид `system:serviceaccount:<namespace>:<service-account>`. URL издателя вашего кластера можно узнать, прочитав его документ обнаружения:

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

<Note>
  Механизм, описанный на этой странице (проецируемый токен сервисного аккаунта, API-сервер кластера в роли издателя OIDC), является встроенным в сам Kubernetes, поэтому он лежит в основе каждого дистрибутива Kubernetes. Если вы работаете на управляемом сервисе Kubernetes, руководства по облачным провайдерам объясняют, где найти URL издателя, управляемого провайдером: [AWS (EKS)](https://platform.claude.com/docs/ru/manage-claude/wif-providers/aws#use-eks-projected-service-account-tokens), [Google Cloud (GKE)](https://platform.claude.com/docs/ru/manage-claude/wif-providers/gcp) или [Azure (AKS)](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure). Если в вашем кластере работает SPIRE, издателем является SPIRE OIDC Discovery Provider, а не API-сервер кластера; см. [SPIFFE](https://platform.claude.com/docs/ru/manage-claude/wif-providers/spiffe). Для любого другого дистрибутива или управляемого провайдера, не указанного там, следуйте этому руководству и используйте URL издателя, который сообщает ваш кластер.
</Note>

## Предварительные требования

* Знакомство с [концепциями WIF](https://platform.claude.com/docs/ru/manage-claude/workload-identity-federation#concepts): сервисные аккаунты, издатели федерации и правила федерации.

* Кластер Kubernetes с настроенным на API-сервере флагом [`--service-account-issuer`](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/). Большинство дистрибутивов устанавливают его по умолчанию; кластеры kubeadm обычно используют `https://kubernetes.default.svc.cluster.local`. Ваша платформенная команда может подтвердить это значение, если у вас нет прямого доступа к конфигурации API-сервера.

* Одно из следующих условий, чтобы Anthropic мог проверять подписи токенов:

  * Конечная точка JWKS издателя доступна из публичного интернета по HTTPS на порту 443, или
  * Вы можете получить JWKS изнутри кластера и зарегистрировать его в режиме `inline` (описано в разделе [Настройка Anthropic](https://platform.claude.com/docs/ru/manage-claude/wif-providers/kubernetes#configure-anthropic)).

* Разрешение на создание сервисных аккаунтов, издателей федерации и правил федерации в Claude Console для вашей организации Anthropic.

## Настройка Kubernetes

Спроецируйте токен сервисного аккаунта в ваш под с аудиторией (audience) и временем жизни, которые ожидает ваше правило федерации. Проекция `serviceAccountToken` записывает свежий JWT по пути монтирования и обновляет его до истечения `expirationSeconds`.

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

Токен, выданный для этого пода, содержит `sub: "system:serviceaccount:inference:inference-worker"` и `aud: ["https://api.anthropic.com"]`.

## Настройка Anthropic

В Claude Console перейдите на страницу [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), нажмите **Connect workload** и выберите плитку **Kubernetes**. Мастер проведёт вас через регистрацию издателя, создание сервисного аккаунта и создание правила федерации.

Мастер создаёт эти ресурсы за вас. Используйте следующие значения независимо от того, вводите ли вы их в мастере или отправляете в [Admin API](https://platform.claude.com/docs/ru/manage-claude/wif-admin-api):

**Издатель федерации:** Многие самостоятельно управляемые кластеры используют URL издателя, например `https://kubernetes.default.svc.cluster.local`, который недоступен из публичного интернета. Если это относится к вашему кластеру, выберите источник JWKS **inline** и вставьте ключи кластера. Получите их изнутри кластера:

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

Затем настройте издателя, используя содержимое возвращённого массива `keys` (а не окружающую обёртку `{"keys": [...]}`):

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

В режиме `inline` значение `issuer_url` только сравнивается с claim `iss` в JWT; Anthropic никогда не пытается к нему обратиться. Если ваш издатель публично доступен, используйте вместо этого `"jwks": {"type": "discovery"}`.

<Warning>
  При использовании ключей `inline` вы несёте ответственность за обновление издателя, когда кластер ротирует свой ключ подписи сервисных аккаунтов. Ротация происходит редко (обычно только при обновлении кластера), но обмены токенов будут завершаться ошибкой подписи, пока вы не загрузите новый JWKS.
</Warning>

**Правило федерации:** Сопоставьте claim `sub` сервисного аккаунта и аудиторию, которую вы задали для проецируемого токена.

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

Будьте настолько конкретны, насколько позволяет рабочая нагрузка. Ослабляйте `subject_prefix` до `system:serviceaccount:inference:*` (завершающий `*` превращает его в сопоставление по префиксу) только в том случае, если каждый сервисный аккаунт в пространстве имён должен отображаться на один и тот же сервисный аккаунт Anthropic. Добавьте идентификатор правила `fdrl_...` в переменную окружения `ANTHROPIC_FEDERATION_RULE_ID` вашего пода.

## Получение и использование токена

Спецификация пода в разделе [Настройка Kubernetes](https://platform.claude.com/docs/ru/manage-claude/wif-providers/kubernetes#configure-kubernetes) устанавливает `ANTHROPIC_IDENTITY_TOKEN_FILE` в путь проецируемого монтирования, а также `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID` и `ANTHROPIC_WORKSPACE_ID`. Когда они заданы, SDK считывает токен с диска при каждом обмене и автоматически обновляет токен доступа 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

  # Считывает ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID и ANTHROPIC_WORKSPACE_ID
  # из переменных окружения пода.
  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";

  // Считывает ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID и ANTHROPIC_WORKSPACE_ID
  // из окружения пода.
  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
  // Считывает ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID и ANTHROPIC_WORKSPACE_ID
  // из окружения пода.
  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#
  // Считывает ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID,
  // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID и ANTHROPIC_WORKSPACE_ID
  // из окружения пода.
  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
  # Считывает ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID и 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;

  // Считывает ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  // ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID и 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"

  # Считывает ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID и 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>

## Проверка настройки

Успешный обмен возвращает `access_token`, начинающийся с `sk-ant-oat01-`, и значение `expires_in` в секундах. Если обмен завершается непрозрачным ответом `401` `authentication_error` (сообщение `Authentication failed`), проверьте причину отказа на [странице истории аутентификации](https://platform.claude.com/settings/workload-identity-federation?tab=history) в Claude Console и см. раздел [Устранение неполадок при неудачном обмене](https://platform.claude.com/docs/ru/manage-claude/wif-reference#troubleshoot-a-failed-exchange); наиболее распространённая причина на стороне Kubernetes — несоответствие ключей JWKS (для режима `inline` повторно получите ключи с помощью `kubectl get --raw /openid/v1/jwks` и обновите издателя).

## Ограничение области действия правила

<Warning>
  Значение `subject_prefix`, равное `system:serviceaccount:*`, соответствует каждому сервисному аккаунту в кластере, поэтому любой под может получить федеративный токен Anthropic. Без сопоставителя `audience` правило также соответствует токенам кластера с аудиторией по умолчанию, которые уже спроецированы в каждый под.
</Warning>

Ограничьте блок `match` правила самой узкой областью, подходящей для вашего сценария использования:

* **Зафиксируйте пространство имён и имя сервисного аккаунта:** Используйте полное значение `system:serviceaccount:<namespace>:<name>` без завершающего `*`.
* **Всегда задавайте аудиторию:** Требуйте `audience` в правиле и задайте то же значение в проекции `serviceAccountToken` пода, чтобы токены с аудиторией по умолчанию отклонялись.
* **Используйте отдельное правило для каждого пространства имён:** Создавайте отдельное правило и сервисный аккаунт Anthropic для каждого пространства имён вместо расширения одного правила.
* **Ограничивайте издателей с inline-JWKS одним кластером:** Когда несколько кластеров используют один URL издателя, зарегистрируйте JWKS каждого кластера как отдельного издателя федерации и привязывайте правила только к этому издателю.

## Следующие шаги

* [Workload Identity Federation](https://platform.claude.com/docs/ru/manage-claude/workload-identity-federation): концепции, процесс обмена токенов и параметры конфигурации SDK.
* [Справочник по WIF](https://platform.claude.com/docs/ru/manage-claude/wif-reference): переменные окружения, режимы источников JWKS и режимы сопоставления правил.
