---
title: 搭配 SPIFFE 使用 WIF
url: https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/spiffe
description: 使用來自 SPIRE 或任何其他符合 SPIFFE 規範之簽發者的 JWT-SVID，向 Claude API 驗證 SPIFFE 工作負載的身分。
---

[SPIFFE](https://spiffe.io/) 是 CNCF 為工作負載簽發身分的標準。[SPIRE](https://spiffe.io/docs/latest/spire-about/) 是其開源參考實作，此外也有數個商業產品會簽發符合 SPIFFE 規範的身分。Anthropic 可與任何能發出 OIDC 相容 JWT-SVID 的 SPIFFE 實作進行聯合。如需目前的實作清單，請參閱 SPIFFE 專案網站上的 [Commercial software that implements SPIFFE](https://spiffe.io/docs/latest/spiffe-about/overview/#commercial-software-that-implements-spiffe)。

聯合可透過位於公開 HTTPS URL 的 OIDC 探索文件運作（`discovery` 模式，須遵守 [URL 限制](https://platform.claude.com/docs/zh-TW/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/zh-TW/manage-claude/wif-providers/spiffe#configure-anthropic)、[取得並使用權杖](https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/spiffe#acquire-and-use-the-token)以及[限定規則範圍](https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/spiffe#scope-your-rule)等章節適用於任何 SPIFFE 實作。

SPIFFE 會為每個工作負載指派一個格式為 `spiffe://<trust-domain>/<path>` 的穩定身分 URI，而 SPIRE 會透過 Workload API 依需求將該身分簽發為 JWT-SVID。JWT-SVID 是一個普通的已簽署 JWT，其 `sub` 宣告為工作負載的 SPIFFE ID，而其 `aud` 宣告則由工作負載在擷取時提供。

將 SPIRE 信任網域橋接至標準 OIDC 的元件是 [SPIRE OIDC Discovery Provider](https://github.com/spiffe/spire/blob/main/support/oidc-discovery-provider/README.md)，這是一個獨立的輔助程式，會為信任網域的 JWT 簽署金鑰發布 `/.well-known/openid-configuration` 與 JWKS 端點。在探索提供者執行的情況下，JWT-SVID 的驗證方式與任何其他 OIDC 權杖相同：將探索 URL 註冊為聯合簽發者（federation issuer），撰寫一條符合工作負載 SPIFFE ID 的聯合規則（federation rule），並讓工作負載將其 JWT-SVID 提交至 Anthropic 的權杖交換端點。

本頁的範例使用 SPIRE，並適用於任何執行 SPIRE Agent 的環境：Kubernetes pod、虛擬機器以及裸機主機。

<Note>
  如果您的 Kubernetes 叢集未執行 SPIRE，而您想改用叢集原生的投射服務帳戶權杖（projected service-account tokens）進行驗證，請參閱[搭配 Kubernetes 使用 WIF](https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/kubernetes)。
</Note>

## 先決條件

* 熟悉 [WIF 概念](https://platform.claude.com/docs/zh-TW/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 簽發者已設定為將 JWT-SVID 上的 `iss` 宣告設為您將註冊為聯合簽發者 `issuer_url` 的值。對於 `discovery` 模式，這是探索端點的公開 URL（在 SPIRE 中為 `jwt_issuer` 伺服器設定）。
* 您的工作負載可取得 JWT-SVID。WIF 僅接受 JWT-SVID，不接受 X.509-SVID。
* 在 Claude Console 中為您的 Anthropic 組織建立服務帳戶、聯合簽發者與聯合規則的權限。

擷取 JWT-SVID 時要請求的 audience 值一律為 `https://api.anthropic.com`。請在 spiffe-helper 的 `jwt_audience`、Workload API 的 `FetchJWTSVID` 呼叫，以及聯合規則的 `audience` 比對器中使用此值。

## 設定 SPIRE

本節的說明為 SPIRE 專屬。如果您使用不同的 SPIFFE 簽發者，請依照其本身的文件設定其 OIDC 探索端點與 JWT-SVID 擷取方式，然後從[設定 Anthropic](https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/spiffe#configure-anthropic) 繼續。

如果您已經搭配 OIDC Discovery Provider 執行 SPIRE，與 Anthropic 聯合在 SPIRE 端需要三件事：一個與探索 URL 相符的 `jwt_issuer`、一個將呼叫 Claude API 之工作負載的註冊項目，以及讓該工作負載能以 Anthropic audience 擷取 JWT-SVID 的方式。以下各小節將逐一說明。設定片段僅顯示與 Anthropic 聯合相關的設定，而非完整的 SPIRE 部署設定。

<Tip>
  第一次設定 SPIRE 嗎？請依照 [SPIRE 快速入門](https://spiffe.io/docs/latest/try/)部署 SPIRE Server 與 Agent，然後將 [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：SPIRE Server 的 `jwt_issuer`（它會成為每個簽發之 JWT-SVID 中的 `iss` 宣告），以及 OIDC Discovery Provider 的 `domains` 清單（它決定探索文件與 JWKS 由哪個主機提供）。這個共用的 URL 就是您向 Anthropic 註冊的值。

信任網域與簽發者 URL 彼此獨立。信任網域（`spiffe://prod.example.com`）限定 `sub` 宣告的範圍。簽發者 URL（`https://oidc-discovery.prod.example.com`）是 Anthropic 擷取簽署金鑰的位置。兩者不需要共用主機名稱。

請確認 SPIRE Server 的設定中已設定 `jwt_issuer`，且指向探索提供者的公開 URL。以下範例也顯示了預設的 JWT-SVID 存留時間。SPIRE 的內建預設值為 5 分鐘，這短到必須持續輪替（請參閱[執行 spiffe-helper](https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/spiffe#run-spiffe-helper)）。Anthropic 的權杖交換端點會拒絕任何存留時間超過聯合簽發者所設定上限的身分權杖，該上限預設為 1 小時（請參閱[驗證規則](https://platform.claude.com/docs/zh-TW/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` 之下，且該提供者必須能夠連線至 SPIRE Server 的 API socket。該提供者透過 HTTPS 提供探索文件與 JWKS。請使用其內建的 ACME 支援終止 TLS，或在其前方放置能終止 TLS 的負載平衡器。

```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`，它將探索提供者連接至 SPIRE Server 的特權 API socket。該提供者也接受 `workload_api` 區塊（包含 `socket_path` 與 `trust_domain`），改為透過 SPIRE Agent 的 Workload API 取得 bundle。當探索提供者不應存取 Server API，或執行於無法連線至 Server 的節點上時，請使用此方式。
</Note>

### 註冊工作負載

每個呼叫 Claude API 的工作負載都需要一個 SPIRE 註冊項目，將其執行階段選擇器（selectors）對應至 SPIFFE ID。如果工作負載已經註冊，請記下其 SPIFFE ID，您會在聯合規則的 `subject_prefix` 中使用它。如果尚未註冊，請進行註冊。對於 Kubernetes pod，選擇器通常是命名空間與 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` 是單一節點自動產生的 agent ID。若要進行全叢集註冊，請將該項目的父項設為[節點別名](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` 也可使用，但需要在 agent 的 unix workload attestor 設定中設定 `discover_workload_path = true`）。執行 [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 socket、為指定的 audience 擷取 JWT-SVID、將其寫入檔案，並在到期前重新擷取。該輔助程式預設以 daemon 模式執行。以下範例明確設定 `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 socket 從主機掛載至 sidecar，在兩個容器中將共用磁碟區掛載於 `/var/run/secrets/anthropic.com`，並在應用程式容器上設定 `ANTHROPIC_IDENTITY_TOKEN_FILE=/var/run/secrets/anthropic.com/token`。在 VM 與裸機上，請將 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/zh-TW/manage-claude/wif-admin-api)，請使用下列值：

**聯合簽發者：**&#x4EE5; `discovery` 模式註冊 OIDC Discovery Provider 的公開 URL。Anthropic 會從此 URL 擷取 `/.well-known/openid-configuration`，並依循回傳的 `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`），並使用回傳之 `keys` 陣列的內容，以 `"jwks": {"type": "inline", "keys": [...]}` 註冊簽發者。在 `inline` 模式下，`issuer_url` 僅會與 JWT-SVID 的 `iss` 宣告進行比對。Anthropic 永遠不會嘗試連線至該 URL。

<Warning>
  SPIRE 會頻繁輪替 JWT 簽署金鑰，預設與 CA 的週期相同（`ca_ttl`，24 小時）。如果您以 inline JWKS 而非探索 URL 註冊簽發者，則每次 SPIRE 輪替時您都必須更新 JWKS：在工作負載開始提交新金鑰之前新增新金鑰，並在以舊金鑰簽署的權杖到期後**移除已被取代的金鑰**。留在 inline 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/zh-TW/manage-claude/wif-admin-api#federation-issuers) 更新簽發者的 inline 金鑰。

**聯合規則：**&#x6BD4;對 JWT-SVID 的 `sub`（SPIFFE ID）以及您設定 spiffe-helper 請求的 `aud`。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 會自動重新整理存取權杖。

請盡可能依工作負載所允許的程度具體設定。僅當註冊於該路徑下的每個工作負載都應對應至同一個 Anthropic 服務帳戶時，才將 `subject_prefix` 放寬為 `spiffe://prod.example.com/ns/inference/*`。將規則的 `fdrl_...` ID 新增至工作負載的 `ANTHROPIC_FEDERATION_RULE_ID` 環境變數。

## 取得並使用權杖

Claude SDK 可以從 spiffe-helper 維護的檔案讀取 JWT-SVID，或者（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，並在 Anthropic 存取權杖到期前自動重新整理。請參閱[環境變數](https://platform.claude.com/docs/zh-TW/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
      # 讀取 spiffe-helper 寫入的 JWT-SVID，其寫入位置為
      # 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

      # 讀取 spiffe-helper 寫入的 JWT-SVID，寫入位置為
      # 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";

      // 讀取 spiffe-helper 寫入的 JWT-SVID，寫入位置為
      // 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#
      // 讀取 spiffe-helper 寫入
      // ANTHROPIC_IDENTITY_TOKEN_FILE 的 JWT-SVID，以及 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
      // 讀取 spiffe-helper 寫入
      // ANTHROPIC_IDENTITY_TOKEN_FILE 的 JWT-SVID，以及 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
      // 讀取 spiffe-helper 寫入至
      // ANTHROPIC_IDENTITY_TOKEN_FILE 的 JWT-SVID，以及 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;

      // 讀取 spiffe-helper 寫入的 JWT-SVID（寫入位置為
      //  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"

      # 讀取 spiffe-helper 寫入的 JWT-SVID（寫入位置為
      #  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 的權杖提供者">
    除了 Java 之外，直接連結 SPIFFE Workload API 用戶端的工作負載可以略過 spiffe-helper，並向 SDK 傳遞一個從 agent socket 擷取新 JWT-SVID 的權杖提供者。SDK 會在每次權杖交換前呼叫該提供者，因此工作負載總是會提交未到期的 SVID。Python（[py-spiffe](https://github.com/HewlettPackard/py-spiffe)）與 Go（[go-spiffe](https://github.com/spiffe/go-spiffe)）擁有成熟的 Workload API 用戶端。

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

      # 連線至位於 SPIFFE_ENDPOINT_SOCKET 的 SPIRE Agent 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>
      對於其他語言，請使用您執行環境的 SPIFFE Workload API 用戶端擷取 JWT-SVID（或以 shell 呼叫 `spire-agent api fetch jwt`），將其寫入檔案，並如檔案式分頁所述將 `ANTHROPIC_IDENTITY_TOKEN_FILE` 設為該路徑。
    </Note>
  </Tab>
</Tabs>

## 驗證設定

在接入 SDK 之前，請直接從 SPIRE Agent 擷取 JWT-SVID，並確認其宣告符合您的聯合規則所預期的內容。如果您使用不同的 SPIFFE 實作，請使用其 CLI 或 Workload API 用戶端擷取 JWT-SVID，並以相同方式解碼 payload。

<Note>
  Workload API 會對呼叫的程序進行證明（attest）。對於 Kubernetes 註冊項目，請在符合該項目選擇器且已掛載 agent socket 的 pod 內執行此命令（例如使用 `kubectl exec`）。在 VM 與裸機上，請以符合該項目 `unix:` 選擇器的使用者或程序執行。從未經證明的主機 shell 執行會回傳 `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` 旗標會以包含兩個元素的 JSON 陣列回傳 SVID 回應和 bundle 回應，因此 `jq -r '.[0].svids[0].svid'` 可擷取純權杖。在沒有 `-output` 的舊版 SPIRE 上，該命令會改為輸出帶有標籤的區塊。在這種情況下，請將預設輸出透過管線傳給 `awk '/^[[:space:]]*eyJ/{print $1; exit}'` 以擷取權杖行。請檢查 `iss` 是否為您註冊的 OIDC Discovery Provider URL、`sub` 是否為工作負載的 SPIFFE ID，以及 `aud` 是否包含 `https://api.anthropic.com`。接著執行[取得並使用權杖](https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/spiffe#acquire-and-use-the-token)中的 cURL 範例。成功的交換會回傳以 `sk-ant-oat01-` 開頭的 `access_token`。如果交換失敗並回傳不透明的 `401` `authentication_error` 回應（訊息為 `Authentication failed`），請在 Claude Console 中查看[驗證歷史記錄頁面](https://platform.claude.com/settings/workload-identity-federation?tab=history)以了解拒絕原因，並參閱[疑難排解失敗的交換](https://platform.claude.com/docs/zh-TW/manage-claude/wif-reference#troubleshoot-a-failed-exchange)。SPIRE 端最常見的原因是 SPIRE Server 的 `jwt_issuer` 與註冊為聯合簽發者的 URL 不相符。

## 限定規則範圍

SPIFFE ID 路徑慣例由操作者定義，因此聯合規則的 `subject_prefix` 比對器應反映您的註冊項目所使用的路徑結構。常見的結構包括 `spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>`（spire-controller-manager 中 `ClusterSPIFFEID` 資源發出的預設值），以及用於 VM 與裸機工作負載的 `spiffe://<trust-domain>/host/<hostname>/<service>`。

<Warning>
  `subject_prefix` 為 `spiffe://prod.example.com/*` 會符合信任網域中的每個工作負載。若沒有 `audience` 比對器，該規則也會接受為任何 audience 簽發的 JWT-SVID，包括工作負載為不相關的依賴方（relying parties）所請求的 JWT-SVID。
</Warning>

請將規則的 `match` 區塊鎖定在符合您使用情境的最窄範圍：

* **固定至單一工作負載：**&#x5C07; `subject_prefix` 設為完整的 SPIFFE ID，結尾不加 `*`。
* **一律設定 audience：**&#x5728;規則上要求 `audience`，並以相同的值設定 spiffe-helper（或 Workload API 呼叫），使為其他依賴方簽發的 SVID 遭到拒絕。
* **依路徑區段限定範圍：**&#x4F7F;用 `spiffe://prod.example.com/ns/inference/*` 授權註冊於某命名空間下的每個工作負載，並為每個命名空間建立個別的規則與 Anthropic 服務帳戶，而非放寬單一規則。
* **每個信任網域一個簽發者：**&#x6BCF;個 SPIRE 信任網域都有自己的簽署金鑰與 OIDC Discovery Provider。請將每個信任網域註冊為個別的聯合簽發者，並將規則繫結至擁有其所比對之 SPIFFE ID 的簽發者。

## 後續步驟

<CardGroup cols={2}>
  <Card title="搭配 Okta 使用 WIF" icon="lock" href="https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/okta">
    使用 Workload Identity Federation 將 Okta 服務應用程式身分聯合至 Claude API。
  </Card>

  <Card title="Workload Identity Federation" icon="cloud" href="https://platform.claude.com/docs/zh-TW/manage-claude/workload-identity-federation">
    使用來自您自己身分提供者的短期身分權杖向 Claude API 驗證工作負載，而非使用長期靜態 API 金鑰。
  </Card>

  <Card title="WIF 參考" icon="book" href="https://platform.claude.com/docs/zh-TW/manage-claude/wif-reference">
    Workload Identity Federation 的環境變數、驗證規則、設定檔設定與錯誤參考。
  </Card>

  <Card title="搭配 Kubernetes 使用 WIF" icon="cube" href="https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/kubernetes">
    使用投射服務帳戶權杖，從自行管理的 Kubernetes 叢集向 Claude API 進行驗證。
  </Card>
</CardGroup>
