---
title: Использование WIF со SPIFFE
url: https://platform.claude.com/docs/ru/manage-claude/wif-providers/spiffe
description: Аутентифицируйте рабочие нагрузки SPIFFE в Claude API с помощью JWT-SVID от SPIRE или любого другого SPIFFE-совместимого издателя.
---

[SPIFFE](https://spiffe.io/) — это стандарт CNCF для выдачи идентичности рабочим нагрузкам. [SPIRE](https://spiffe.io/docs/latest/spire-about/) — его эталонная реализация с открытым исходным кодом, и несколько коммерческих продуктов также выдают SPIFFE-совместимые идентичности. Anthropic поддерживает федерацию с любой реализацией SPIFFE, которая выпускает OIDC-совместимые JWT-SVID. Актуальный список реализаций см. в разделе [Commercial software that implements SPIFFE](https://spiffe.io/docs/latest/spiffe-about/overview/#commercial-software-that-implements-spiffe) на сайте проекта SPIFFE.

Федерация работает либо через документ обнаружения OIDC по публичному HTTPS URL (режим `discovery`, с учётом [ограничений на URL](https://platform.claude.com/docs/ru/manage-claude/wif-reference#url-fields)), либо путём прямой регистрации JWKS (режим `inline`).

Спецификация JWT-SVID определяет `sub` как SPIFFE ID рабочей нагрузки, а SPIFFE Workload API требует, чтобы вызывающая сторона указывала `aud` в момент получения, поэтому эти утверждения (claims) одинаковы во всех реализациях. Anthropic дополнительно требует `iss` и `iat`, ни одно из которых спецификация JWT-SVID не делает обязательным, поэтому настройте вашу реализацию так, чтобы она заполняла оба (в SPIRE `iss` — это серверная настройка `jwt_issuer`, а `iat` устанавливается автоматически). Когда они настроены, разделы [Настройка Anthropic](https://platform.claude.com/docs/ru/manage-claude/wif-providers/spiffe#configure-anthropic), [Получение и использование токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/spiffe#acquire-and-use-the-token) и [Ограничение области действия правила](https://platform.claude.com/docs/ru/manage-claude/wif-providers/spiffe#scope-your-rule) этого руководства применимы к любой реализации SPIFFE.

SPIFFE присваивает каждой рабочей нагрузке стабильный URI идентичности вида `spiffe://<trust-domain>/<path>`, а SPIRE выдаёт эту идентичность в виде JWT-SVID по запросу через Workload API. JWT-SVID — это обычный подписанный JWT, утверждение `sub` которого является SPIFFE ID рабочей нагрузки, а утверждение `aud` указывается рабочей нагрузкой в момент получения.

Мостом от домена доверия (trust domain) SPIRE к стандартному OIDC служит [SPIRE OIDC Discovery Provider](https://github.com/spiffe/spire/blob/main/support/oidc-discovery-provider/README.md) — отдельный вспомогательный компонент, который публикует `/.well-known/openid-configuration` и конечную точку JWKS для ключей подписи JWT домена доверия. При работающем провайдере обнаружения JWT-SVID проверяется как любой другой токен OIDC: зарегистрируйте URL обнаружения как издателя федерации (federation issuer), напишите правило федерации (federation rule), соответствующее SPIFFE ID рабочей нагрузки, и настройте рабочую нагрузку так, чтобы она предъявляла свой JWT-SVID конечной точке обмена токенов Anthropic.

Примеры на этой странице используют SPIRE и применимы везде, где работает SPIRE Agent: поды Kubernetes, виртуальные машины и физические серверы (bare-metal).

<Note>
  Если в вашем кластере Kubernetes не работает SPIRE и вы хотите вместо этого аутентифицироваться с помощью нативных проецируемых токенов сервисных аккаунтов кластера, см. [Использование WIF с Kubernetes](https://platform.claude.com/docs/ru/manage-claude/wif-providers/kubernetes).
</Note>

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

* Знакомство с [концепциями WIF](https://platform.claude.com/docs/ru/manage-claude/workload-identity-federation#concepts): сервисные аккаунты, издатели федерации и правила федерации.
* Развёртывание SPIFFE с выданными идентичностями рабочих нагрузок (примеры на этой странице используют SPIRE Server и Agent) и регистрационные записи для рабочих нагрузок, которым нужно вызывать Claude API.
* Конечная точка обнаружения OIDC для домена доверия (в SPIRE — [OIDC Discovery Provider](https://github.com/spiffe/spire/blob/main/support/oidc-discovery-provider/README.md)), работающая с публично доступной конечной точкой HTTPS, либо JWKS, экспортированный для регистрации в режиме `inline`.
* Ваш издатель SPIFFE, настроенный так, чтобы устанавливать утверждение `iss` в JWT-SVID в значение, которое вы зарегистрируете как `issuer_url` издателя федерации. Для режима `discovery` это публичный URL конечной точки обнаружения (в SPIRE — серверная настройка `jwt_issuer`).
* JWT-SVID, доступные вашим рабочим нагрузкам. WIF принимает только JWT-SVID, а не X.509-SVID.
* Разрешение на создание сервисных аккаунтов, издателей федерации и правил федерации в Claude Console для вашей организации Anthropic.

Значение аудитории (audience), которое нужно запрашивать при получении JWT-SVID, всегда `https://api.anthropic.com`. Используйте это значение в `jwt_audience` spiffe-helper, в вызове `FetchJWTSVID` Workload API и в сопоставителе `audience` правила федерации.

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

Инструкции в этом разделе специфичны для SPIRE. Если вы используете другого издателя SPIFFE, настройте его конечную точку обнаружения OIDC и получение JWT-SVID согласно его собственной документации, затем продолжайте с раздела [Настройка Anthropic](https://platform.claude.com/docs/ru/manage-claude/wif-providers/spiffe#configure-anthropic).

Если вы уже используете SPIRE с OIDC Discovery Provider, для федерации с Anthropic на стороне SPIRE требуются три вещи: `jwt_issuer`, совпадающий с URL обнаружения, регистрационная запись для рабочей нагрузки, которая будет вызывать Claude API, и способ для этой рабочей нагрузки получить JWT-SVID с аудиторией Anthropic. Следующие подразделы описывают каждую из них. Фрагменты конфигурации показывают только настройки, относящиеся к федерации с Anthropic, а не полные конфигурации развёртывания SPIRE.

<Tip>
  Настраиваете SPIRE впервые? Разверните SPIRE Server и Agent, следуя [руководству по быстрому старту SPIRE](https://spiffe.io/docs/latest/try/), затем добавьте [OIDC Discovery Provider](https://github.com/spiffe/spire/blob/main/support/oidc-discovery-provider/README.md) как отдельный сервис рядом со SPIRE Server. Федерация в режиме обнаружения зависит от того, что провайдер развёрнут и публично доступен. Провайдер не входит в стандартную установку SPIRE.
</Tip>

### Проверка издателя JWT

Anthropic проверяет JWT-SVID, сопоставляя его утверждение `iss` с зарегистрированным издателем федерации и получая JWKS из документа обнаружения этого издателя. Две настройки SPIRE должны указывать на один и тот же URL: `jwt_issuer` SPIRE Server (который становится утверждением `iss` в каждом выпущенном JWT-SVID) и список `domains` OIDC Discovery Provider (который определяет хост, с которого отдаются документ обнаружения и JWKS). Этот общий URL — то, что вы регистрируете в Anthropic.

Домен доверия и URL издателя независимы. Домен доверия (`spiffe://prod.example.com`) задаёт область утверждения `sub`. URL издателя (`https://oidc-discovery.prod.example.com`) — это место, откуда Anthropic получает ключи подписи. Им не обязательно иметь общее имя хоста.

Убедитесь, что `jwt_issuer` задан в конфигурации SPIRE Server и указывает на публичный URL провайдера обнаружения. Следующий пример также показывает время жизни JWT-SVID по умолчанию. Встроенное значение по умолчанию в SPIRE — 5 минут, что достаточно мало, чтобы требовалась непрерывная ротация (см. [Запуск spiffe-helper](https://platform.claude.com/docs/ru/manage-claude/wif-providers/spiffe#run-spiffe-helper)). Конечная точка обмена токенов Anthropic отклоняет любой токен идентичности, время жизни которого превышает настроенный максимум издателя федерации, по умолчанию равный 1 часу (см. [Правила валидации](https://platform.claude.com/docs/ru/manage-claude/wif-reference#validation-rules)). Эта проверка применяется к каждой реализации SPIFFE, а не только к SPIRE, поэтому держите `default_jwt_svid_ttl` (или любое переопределение для отдельной записи) на уровне этого максимума или ниже.

```text server.conf
server {
    trust_domain         = "prod.example.com"
    jwt_issuer           = "https://oidc-discovery.prod.example.com"
    default_jwt_svid_ttl = "5m"
    # ...
}
```

В конфигурации OIDC Discovery Provider то же имя хоста должно присутствовать в `domains`, и провайдер должен иметь доступ к сокету API SPIRE Server. Провайдер отдаёт документ обнаружения и JWKS по HTTPS. Терминируйте TLS с помощью его встроенной поддержки ACME или разместите перед ним балансировщик нагрузки, который это делает.

```text oidc-discovery-provider.conf
domains = ["oidc-discovery.prod.example.com"]

server_api {
    address = "unix:///run/spire/sockets/private/api.sock"
}

acme {
    email        = "platform@example.com"
    tos_accepted = true
}
```

<Note>
  В примере используется `server_api`, который подключает провайдер обнаружения к привилегированному сокету API SPIRE Server. Провайдер также принимает блок `workload_api` (с `socket_path` и `trust_domain`), который вместо этого получает бандл через Workload API SPIRE Agent. Используйте его, когда провайдер обнаружения не должен иметь доступа к Server API или работает на узле, который не может достичь сервера.
</Note>

### Регистрация рабочей нагрузки

Каждой рабочей нагрузке, вызывающей Claude API, нужна регистрационная запись SPIRE, которая сопоставляет её селекторы времени выполнения со SPIFFE ID. Если рабочая нагрузка уже зарегистрирована, запишите её SPIFFE ID, который вы используете в `subject_prefix` правила федерации. Если нет, зарегистрируйте её. Для пода Kubernetes селекторами обычно являются пространство имён и сервисный аккаунт Kubernetes:

```bash CLI
# Замените NODE_UID на UID узла:
#   kubectl get node <node-name> -o jsonpath='{.metadata.uid}'
spire-server entry create \
    -spiffeID spiffe://prod.example.com/ns/inference/sa/worker \
    -parentID spiffe://prod.example.com/spire/agent/k8s_psat/prod-cluster/NODE_UID \
    -selector k8s:ns:inference \
    -selector k8s:sa:worker
```

<Note>
  Показанный `parentID` — это автоматически сгенерированный ID агента одного узла. Для регистрации в масштабе кластера сделайте родителем записи [псевдоним узла (node alias)](https://spiffe.io/docs/latest/deploying/registering/#mapping-workloads-to-multiple-nodes), чтобы она соответствовала рабочим нагрузкам на каждом узле, как это делает [руководство по быстрому старту SPIRE для Kubernetes](https://spiffe.io/docs/latest/try/getting-started-k8s/).
</Note>

Рабочие нагрузки вне Kubernetes используют селекторы уровня хоста, такие как `unix:uid:1000` (`unix:path` также доступен, но требует `discover_workload_path = true` в конфигурации unix-аттестатора рабочих нагрузок агента). Кластеры, в которых работает [spire-controller-manager](https://github.com/spiffe/spire-controller-manager), могут объявлять записи с помощью пользовательского ресурса `ClusterSPIFFEID` вместо прямого вызова `spire-server entry create`.

### Запуск spiffe-helper

[spiffe-helper](https://github.com/spiffe/spiffe-helper) — это sidecar-утилита, которая подключается к сокету SPIRE Agent, получает JWT-SVID для заданной аудитории, записывает его в файл и повторно получает его до истечения срока действия. По умолчанию helper работает в режиме демона. Следующий пример явно задаёт `daemon_mode = true`.

```text helper.conf
agent_address = "/run/spire/sockets/agent.sock"
# The JWT-SVID file is written under cert_dir
cert_dir      = "/var/run/secrets/anthropic.com"
daemon_mode   = true

jwt_svids = [{
    jwt_audience       = "https://api.anthropic.com"
    jwt_svid_file_name = "token"
}]
```

В Kubernetes запускайте spiffe-helper как sidecar-контейнер, разделяющий том `emptyDir` в памяти (`medium: Memory`) с контейнером вашего приложения, чтобы bearer-SVID никогда не попадал на диск узла. Смонтируйте сокет SPIRE Agent с хоста в sidecar, смонтируйте общий том в `/var/run/secrets/anthropic.com` в обоих контейнерах и задайте `ANTHROPIC_IDENTITY_TOKEN_FILE=/var/run/secrets/anthropic.com/token` в контейнере приложения. На виртуальных машинах и физических серверах запускайте spiffe-helper как системный сервис рядом с рабочей нагрузкой и направьте оба на общий каталог.

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

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

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

**Издатель федерации:** Зарегистрируйте публичный URL OIDC Discovery Provider в режиме `discovery`. Anthropic получает `/.well-known/openid-configuration` по этому URL и следует по возвращённому `jwks_uri`, чтобы получить ключи подписи домена доверия.

```json
{
  "name": "spire-prod",
  "issuer_url": "https://oidc-discovery.prod.example.com",
  "jwks": { "type": "discovery" }
}
```

Если провайдер обнаружения недоступен из публичного интернета, получите JWKS самостоятельно (`curl https://oidc-discovery.prod.example.com/keys`) и зарегистрируйте издателя с `"jwks": {"type": "inline", "keys": [...]}`, используя содержимое возвращённого массива `keys`. В режиме `inline` `issuer_url` только сравнивается с утверждением `iss` JWT-SVID. Anthropic никогда не пытается к нему обратиться.

<Warning>
  SPIRE часто ротирует ключи подписи JWT, по умолчанию с той же периодичностью, что и CA (`ca_ttl`, 24 часа). Если вы регистрируете издателя со встроенным (inline) JWKS вместо URL обнаружения, вы должны обновлять JWKS при каждой ротации SPIRE: добавлять новый ключ до того, как рабочие нагрузки начнут его предъявлять, и **удалять устаревшие ключи**, как только истечёт срок действия подписанных ими токенов. Устаревшие ключи, оставленные во встроенном JWKS, остаются доверенными бессрочно.
</Warning>

Чтобы автоматизировать обновления JWKS без публикации публичной конечной точки обнаружения, настройте плагин SPIRE Server [BundlePublisher](https://spiffe.io/docs/latest/deploying/spire_server/#built-in-plugins) (`aws_s3`, `gcp_cloudstorage` или `k8s_configmap`) с `format = "jwks"`, чтобы отправлять ключи подписи JWT во внешнее хранилище при каждой ротации, а затем обновляйте встроенные ключи издателя через [Admin API](https://platform.claude.com/docs/ru/manage-claude/wif-admin-api#federation-issuers).

**Правило федерации:** Сопоставляйте `sub` JWT-SVID (SPIFFE ID) и `aud`, который вы настроили запрашивать в spiffe-helper. SPIFFE ID — это строки URI, и `subject_prefix` сопоставляет их как непрозрачный текст, поэтому с ними работают как точное значение, так и префиксное совпадение с завершающим `*`. Для более сложных шаблонов используйте CEL-условие `condition`.

```json
{
  "name": "spire-inference-worker",
  "issuer_id": "fdis_...",
  "match": {
    "subject_prefix": "spiffe://prod.example.com/ns/inference/sa/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
}
```

`token_lifetime_seconds` — это время жизни токена доступа Anthropic, возвращаемого обменом, а не JWT-SVID. SDK обновляет токен доступа автоматически.

Будьте настолько конкретны, насколько позволяет рабочая нагрузка. Ослабляйте `subject_prefix` до `spiffe://prod.example.com/ns/inference/*` только в том случае, если каждая рабочая нагрузка, зарегистрированная под этим путём, должна сопоставляться с одним и тем же сервисным аккаунтом Anthropic. Добавьте ID правила `fdrl_...` в переменную окружения `ANTHROPIC_FEDERATION_RULE_ID` рабочей нагрузки.

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

Claude SDK может читать JWT-SVID из файла, который обновляет spiffe-helper, или (кроме Java) напрямую вызывать SPIFFE Workload API через поставщика токенов. Вариант с файлом — самая простая интеграция, работающая во всех языках SDK. Вариант с поставщиком токенов избавляет от sidecar, но требует клиента SPIFFE Workload API на языке вашего приложения.

<Tabs>
  <Tab title="На основе файла со spiffe-helper">
    spiffe-helper записывает свежий JWT-SVID в `/var/run/secrets/anthropic.com/token`. Задайте `ANTHROPIC_IDENTITY_TOKEN_FILE` равным этому пути, а также задайте `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID` и `ANTHROPIC_WORKSPACE_ID`. SDK читает файл при каждом обмене токенов и поэтому всегда использует последний выпущенный SVID. SDK автоматически обновляет токен доступа Anthropic до истечения его срока действия. Откуда берётся каждое значение, см. в разделе [Переменные окружения](https://platform.claude.com/docs/ru/manage-claude/wif-reference#environment-variables).

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

      ```bash CLI
      # Считывает JWT-SVID, который spiffe-helper записывает в
      # ANTHROPIC_IDENTITY_TOKEN_FILE, а также ANTHROPIC_FEDERATION_RULE_ID,
      # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID и ANTHROPIC_WORKSPACE_ID.
      ant messages create \
        --model claude-opus-5-5 \
        --max-tokens 1024 \
        --message '{role: user, content: "Hello, Claude"}'
      ```

      ```python Python
      import anthropic

      # Считывает JWT-SVID, который spiffe-helper записывает в
      # 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";

      // Читает JWT-SVID, который spiffe-helper записывает в
      // 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);
        }
      }
      ```

      ```csharp C#
      // Считывает JWT-SVID, который spiffe-helper записывает в
      // 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);
          }
      }
      ```

      ```go Go
      // Читает JWT-SVID, который spiffe-helper записывает в
      // 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
      // Читает JWT-SVID, который spiffe-helper записывает в
      // ANTHROPIC_IDENTITY_TOKEN_FILE, а также ANTHROPIC_FEDERATION_RULE_ID,
      // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID и ANTHROPIC_WORKSPACE_ID.
      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());
      ```

      ```php PHP
      use Anthropic\Client;

      // Читает JWT-SVID, который spiffe-helper записывает в
      // ANTHROPIC_IDENTITY_TOKEN_FILE, а также ANTHROPIC_FEDERATION_RULE_ID,
      // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID и ANTHROPIC_WORKSPACE_ID.
      $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"

      # Считывает JWT-SVID, который spiffe-helper записывает в
      # ANTHROPIC_IDENTITY_TOKEN_FILE, а также ANTHROPIC_FEDERATION_RULE_ID,
      # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID и ANTHROPIC_WORKSPACE_ID.
      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>
  </Tab>

  <Tab title="Поставщик токенов через SPIFFE Workload API">
    Если рабочая нагрузка напрямую использует клиент SPIFFE Workload API, spiffe-helper не нужен (кроме Java). Передайте SDK поставщика токенов, который получает свежий JWT-SVID из сокета агента. SDK вызывает поставщика перед каждым обменом токенов, поэтому рабочая нагрузка всегда предъявляет действующий SVID. Зрелые клиенты Workload API есть для Python ([py-spiffe](https://github.com/HewlettPackard/py-spiffe)) и Go ([go-spiffe](https://github.com/spiffe/go-spiffe)).

    <CodeGroup exclude="shell, typescript, java, csharp, php, ruby">
      ```python Python
      import os
      import anthropic
      from anthropic import WorkloadIdentityCredentials
      from spiffe import JwtSource

      AUDIENCE = "https://api.anthropic.com"

      # Подключается к сокету SPIRE Agent по адресу SPIFFE_ENDPOINT_SOCKET.
      jwt_source = JwtSource()


      def fetch_jwt_svid() -> str:
          svid = jwt_source.fetch_svid(audience={AUDIENCE})  # audience is a set of strings
          return svid.token


      client = anthropic.Anthropic(
          credentials=WorkloadIdentityCredentials(
              identity_token_provider=fetch_jwt_svid,
              federation_rule_id=os.environ["ANTHROPIC_FEDERATION_RULE_ID"],
              organization_id=os.environ["ANTHROPIC_ORGANIZATION_ID"],
              service_account_id=os.environ["ANTHROPIC_SERVICE_ACCOUNT_ID"],
              workspace_id=os.environ.get("ANTHROPIC_WORKSPACE_ID"),
          ),
      )

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

      ```go Go
      import (
      	"context"
      	"fmt"
      	"os"

      	"github.com/anthropics/anthropic-sdk-go"
      	"github.com/anthropics/anthropic-sdk-go/option"
      	"github.com/spiffe/go-spiffe/v2/svid/jwtsvid"
      	"github.com/spiffe/go-spiffe/v2/workloadapi"
      )
      // ...
      	const audience = "https://api.anthropic.com"

      	ctx := context.Background()
      	source, err := workloadapi.NewJWTSource(ctx)
      	if err != nil {
      		panic(err)
      	}
      	defer source.Close()

      	fetchJWTSVID := func(ctx context.Context) (string, error) {
      		svid, err := source.FetchJWTSVID(ctx, jwtsvid.Params{Audience: audience})
      		if err != nil {
      			return "", err
      		}
      		return svid.Marshal(), nil
      	}

      	client := anthropic.NewClient(
      		option.WithFederationTokenProvider(fetchJWTSVID, option.FederationOptions{
      			FederationRuleID: os.Getenv("ANTHROPIC_FEDERATION_RULE_ID"),
      			OrganizationID:   os.Getenv("ANTHROPIC_ORGANIZATION_ID"),
      			ServiceAccountID: os.Getenv("ANTHROPIC_SERVICE_ACCOUNT_ID"),
      			WorkspaceID:      os.Getenv("ANTHROPIC_WORKSPACE_ID"),
      		}),
      	)

      	message, err := client.Messages.New(ctx, 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
      		}
      	}
      ```
    </CodeGroup>

    <Note>
      Для других языков получите JWT-SVID с помощью клиента SPIFFE Workload API для вашей среды выполнения (или вызовите `spire-agent api fetch jwt` из оболочки). Запишите токен в файл и задайте `ANTHROPIC_IDENTITY_TOKEN_FILE` равным пути к нему, как на вкладке с файлом.
    </Note>
  </Tab>
</Tabs>

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

Прежде чем подключать SDK, получите JWT-SVID напрямую от SPIRE Agent и убедитесь, что утверждения соответствуют тому, что ожидает ваше правило федерации. Если вы используете другую реализацию SPIFFE, получите JWT-SVID с помощью её CLI или клиента Workload API и декодируйте полезную нагрузку тем же способом.

<Note>
  Workload API аттестует вызывающий процесс. Для регистрационной записи Kubernetes выполните эту команду внутри пода, который удовлетворяет селекторам записи и имеет смонтированный сокет агента (например, с помощью `kubectl exec`). На виртуальных машинах и физических серверах выполните её от имени пользователя или процесса, соответствующего селекторам `unix:` записи. Запуск из неаттестованной оболочки хоста возвращает `no identity issued`, что является самой распространённой ошибкой на этапе проверки.
</Note>

```bash CLI
spire-agent api fetch jwt \
    -audience https://api.anthropic.com \
    -socketPath /run/spire/sockets/agent.sock \
    -output json \
  | jq -r '.[0].svids[0].svid' \
  | jq -rR 'split(".")[1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson'
```

Флаг `-output json` возвращает ответ SVID и ответ бандла в виде JSON-массива из двух элементов, поэтому `jq -r '.[0].svids[0].svid'` извлекает сам токен. В более старых версиях SPIRE без `-output` команда вместо этого выводит блок с метками. В этом случае пропустите вывод по умолчанию через `awk '/^[[:space:]]*eyJ/{print $1; exit}'`, чтобы извлечь строку с токеном. Убедитесь, что `iss` — это зарегистрированный вами URL OIDC Discovery Provider, `sub` — SPIFFE ID рабочей нагрузки, а `aud` содержит `https://api.anthropic.com`. Затем выполните пример cURL из раздела [Получение и использование токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/spiffe#acquire-and-use-the-token). Успешный обмен возвращает `access_token`, начинающийся с `sk-ant-oat01-`. Если обмен завершается непрозрачным ответом `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). Самая распространённая причина на стороне SPIRE — несоответствие между `jwt_issuer` в SPIRE Server и URL, зарегистрированным как издатель федерации.

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

Соглашения о путях SPIFFE ID определяются оператором, поэтому сопоставитель `subject_prefix` правила федерации должен отражать схему путей, которую используют ваши регистрационные записи. Распространённые схемы включают `spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>` (значение по умолчанию, выдаваемое ресурсом `ClusterSPIFFEID` в spire-controller-manager) и `spiffe://<trust-domain>/host/<hostname>/<service>` для рабочих нагрузок на виртуальных машинах и физических серверах.

<Warning>
  `subject_prefix` со значением `spiffe://prod.example.com/*` соответствует каждой рабочей нагрузке в домене доверия. Без сопоставителя `audience` правило также принимает JWT-SVID, выпущенные для любой аудитории, включая те, которые рабочая нагрузка запросила для не связанных с этим доверяющих сторон.
</Warning>

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

* **Привязка к одной рабочей нагрузке:** Задайте `subject_prefix` равным полному SPIFFE ID без завершающего `*`.
* **Всегда задавайте аудиторию:** Требуйте `audience` в правиле и настройте spiffe-helper (или вызов Workload API) с тем же значением, чтобы SVID, выпущенные для других доверяющих сторон, отклонялись.
* **Ограничение по сегменту пути:** Используйте `spiffe://prod.example.com/ns/inference/*`, чтобы предоставить доступ каждой рабочей нагрузке, зарегистрированной в пространстве имён, и создавайте отдельное правило и сервисный аккаунт Anthropic для каждого пространства имён вместо расширения одного правила.
* **Один издатель на домен доверия:** У каждого домена доверия SPIRE свои ключи подписи и свой OIDC Discovery Provider. Регистрируйте каждый как отдельного издателя федерации и привязывайте правила к издателю, которому принадлежат сопоставляемые ими SPIFFE ID.

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

<CardGroup cols={2}>
  <Card title="Использование WIF с Okta" icon="lock" href="https://platform.claude.com/docs/ru/manage-claude/wif-providers/okta">
    Федерируйте идентичности сервисных приложений Okta с Claude API с помощью Workload Identity Federation.
  </Card>

  <Card title="Workload Identity Federation" icon="cloud" href="https://platform.claude.com/docs/ru/manage-claude/workload-identity-federation">
    Аутентифицируйте рабочие нагрузки в Claude API с помощью короткоживущих токенов идентичности от вашего собственного поставщика идентичности вместо долгоживущих статических ключей API.
  </Card>

  <Card title="Справочник WIF" icon="book" href="https://platform.claude.com/docs/ru/manage-claude/wif-reference">
    Переменные окружения, правила валидации, конфигурация профилей и справочник ошибок для Workload Identity Federation.
  </Card>

  <Card title="Использование WIF с Kubernetes" icon="cube" href="https://platform.claude.com/docs/ru/manage-claude/wif-providers/kubernetes">
    Аутентифицируйтесь в Claude API из самостоятельно управляемых кластеров Kubernetes с помощью проецируемых токенов сервисных аккаунтов.
  </Card>
</CardGroup>
