---
title: Google Cloud에서 WIF 사용하기
url: https://platform.claude.com/docs/ko/manage-claude/wif-providers/gcp
description: 정적 API 키 대신 Google이 서명한 ID 토큰을 사용하여 Google Cloud 워크로드(Cloud Run, Cloud Functions, App Engine, GCE, GKE)를 Claude API에 페더레이션합니다.
---

인스턴스 메타데이터 서버에 접근할 수 있는 모든 Google Cloud 컴퓨팅 환경(Cloud Run, Cloud Functions, App Engine, Compute Engine(GCE), Workload Identity가 적용된 GKE)은 연결된 서비스 계정에 대해 Google이 서명한 "identity token"(ID 토큰)을 요청할 수 있습니다. 토큰의 발급자(issuer)는 `https://accounts.google.com`이며, Anthropic은 추가적인 Google Cloud 구성 없이 표준 OIDC 디스커버리를 통해 이를 직접 검증할 수 있습니다.

이 가이드에서는 Google 발급자를 Anthropic에 등록하고, Google 서비스 계정을 Anthropic 서비스 계정에 바인딩하며, 워크로드가 자신의 ID 토큰을 수명이 짧은 Claude API 액세스 토큰으로 교환하도록 하는 방법을 보여줍니다.

## 사전 요구 사항

* [WIF 개념](https://platform.claude.com/docs/ko/manage-claude/workload-identity-federation#concepts)에 대한 이해: 서비스 계정, 페더레이션 발급자, 페더레이션 규칙.
* Cloud Run, Cloud Functions, App Engine, Compute Engine 또는 GKE에서 실행 중인 워크로드가 있는 Google Cloud 프로젝트.
* 해당 워크로드에 연결된 사용자 관리형 Google 서비스 계정(Compute Engine 기본 서비스 계정이 아님).
* Anthropic 조직의 Claude Console에서 서비스 계정, 페더레이션 발급자, 페더레이션 규칙을 생성할 수 있는 권한.

## Google Cloud 구성

Google은 서비스 계정이 연결된 모든 워크로드에 ID 토큰을 자동으로 발급합니다. Google 측에서는 올바른 서비스 계정을 연결하는 것 외에 활성화할 것이 없지만, 표준 컴퓨팅 환경과 GKE 간에는 단계가 약간 다릅니다.

<Tabs>
  <Tab title="Cloud Run, Cloud Functions, App Engine, GCE">
    서비스 또는 인스턴스에 전용 서비스 계정을 연결하세요:

    ```bash CLI
    gcloud run deploy my-service \
      --service-account inference-worker@my-project.iam.gserviceaccount.com
    ```

    워크로드 내부에서 메타데이터 서버는 요청 시 서명된 ID 토큰을 반환합니다. Anthropic 측에 등록하려는 `audience`로 토큰을 요청하고, 응답에 `email` 클레임이 포함되도록 `format=full`을 포함하세요:

    ```text wrap
    GET http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full
    Metadata-Flavor: Google
    ```

    또는 gcloud CLI를 사용하는 경우:

    ```bash CLI
    gcloud auth print-identity-token \
      --audiences="https://api.anthropic.com" \
      --include-email
    ```

    SDK에서의 동등한 방법은 [토큰 획득 및 사용](https://platform.claude.com/docs/ko/manage-claude/wif-providers/gcp#acquire-and-use-the-token)에 나와 있습니다.

    디코딩된 토큰 페이로드는 다음과 같습니다:

    ```json
    {
      "iss": "https://accounts.google.com",
      "aud": "https://api.anthropic.com",
      "sub": "104892...",
      "azp": "104892...",
      "email": "inference-worker@my-project.iam.gserviceaccount.com",
      "email_verified": true,
      "exp": 1775527120
    }
    ```

    `sub` 클레임은 Google 서비스 계정의 불투명한 숫자형 고유 ID입니다. `email` 클레임은 사람이 읽을 수 있는 서비스 계정 주소입니다. 페더레이션 규칙에서 `sub`와 `email` 모두에 대해 매칭하세요.
  </Tab>

  <Tab title="Workload Identity가 적용된 GKE">
    클러스터에서 [Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)를 활성화하고, `iam.gke.io/gcp-service-account` 어노테이션을 사용하여 Kubernetes 서비스 계정을 Google 서비스 계정에 바인딩하세요:

    ```yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: inference-worker
      namespace: prod
      annotations:
        iam.gke.io/gcp-service-account: inference-worker@my-project.iam.gserviceaccount.com
    ```

    이 바인딩이 설정되면 GKE 메타데이터 서버는 Cloud Run 및 GCE의 경우와 동일한 Google 서명 토큰을 반환합니다. 동일한 `https://accounts.google.com` 발급자, 동일한 `email` 클레임, 동일한 가져오기 URL을 사용합니다. 다음 섹션과 정확히 동일하게 Anthropic을 구성하세요.

    GKE의 `format=full` 토큰에는 추가로 `google.compute_engine.project_id`, `google.compute_engine.zone`, `google.compute_engine.instance_name` 클레임이 포함되며, 페더레이션 규칙의 `condition` 매처(`claims.google.compute_engine.project_id == "my-project"`와 같은 CEL 표현식)에서 이를 참조하여 특정 클러스터나 노드 풀로 접근 범위를 제한할 수 있습니다.

    <Note>
      Kubernetes 서비스 계정을 Google 서비스 계정에 바인딩하고 싶지 않다면, GKE 파드는 대신 프로젝션된 `serviceAccountToken` 볼륨과 함께 클러스터 자체의 OIDC 발급자(`https://container.googleapis.com/v1/projects/PROJECT/locations/REGION/clusters/CLUSTER`)를 사용할 수 있습니다. 이 경로는 `accounts.google.com` 대신 클러스터별 발급자를 사용합니다. 해당 패턴은 [Kubernetes에서 WIF 사용하기](https://platform.claude.com/docs/ko/manage-claude/wif-providers/kubernetes)를 참조하세요.
    </Note>
  </Tab>
</Tabs>

## Anthropic 구성

Claude Console에서 [Workload identity](https://platform.claude.com/settings/workload-identity-federation) 페이지(`platform.claude.com/settings/workload-identity-federation`)로 이동하여 **Connect workload**를 클릭하고 **Google Cloud** 타일을 선택하세요. 마법사가 발급자 등록, 서비스 계정 생성, 페더레이션 규칙 생성 과정을 안내합니다.

마법사가 이러한 리소스를 대신 생성해 줍니다. 마법사에 입력하든 [Admin API](https://platform.claude.com/docs/ko/manage-claude/wif-admin-api)로 전송하든 다음 값을 사용하세요:

**페더레이션 발급자:** Google은 OIDC 디스커버리 문서를 공개적으로 게시하므로 디스커버리 모드를 사용하세요. 이 단일 발급자는 모든 Google Cloud 환경(Cloud Run, GCE, Cloud Functions, App Engine, Workload Identity가 적용된 GKE)을 포괄합니다. 워크로드는 발급자가 아닌 규칙으로 구분하세요.

```json
{
  "name": "gcp",
  "issuer_url": "https://accounts.google.com",
  "jwks": { "type": "discovery" }
}
```

**페더레이션 규칙:** `sub`와 `email` 클레임 모두에 대해 매칭하세요. `email`은 읽을 수 있는 서비스 계정 주소이고, `sub`는 Google이 절대 재사용하지 않는 서비스 계정의 숫자형 고유 ID이므로, 이를 고정하면 서비스 계정이 삭제된 후 나중에 동일한 이메일로 새 계정이 생성되더라도 규칙이 보호됩니다. 고유 ID는 `gcloud iam service-accounts describe SA_EMAIL --format='value(uniqueId)'`로 확인할 수 있습니다.

```json
{
  "name": "gcp-inference-worker",
  "issuer_id": "fdis_...",
  "match": {
    "audience": "https://api.anthropic.com",
    "claims": {
      "sub": "104892101234567890123",
      "email": "inference-worker@my-project.iam.gserviceaccount.com"
    }
  },
  "target": {
    "type": "service_account",
    "service_account_id": "svac_..."
  },
  "workspace_id": "wrkspc_...",
  "oauth_scope": "workspace:developer",
  "token_lifetime_seconds": 600
}
```

## 토큰 획득 및 사용

Google Cloud 워크로드 내부에서 메타데이터 서버로부터 ID 토큰을 가져와 `POST /v1/oauth/token`에서 교환한 다음, 반환된 bearer 토큰을 사용하여 Claude API를 호출하세요. 다음 예제와 같이 `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`)를 제공하면 Claude SDK가 교환 및 갱신 루프를 대신 처리합니다. Java를 제외하고(해당 예제의 주석 참조), 이 옵션은 메타데이터 서버에서 새 ID 토큰을 반환하는 토큰 제공자를 받습니다.

<CodeGroup>
  ```bash cURL
  # 메타데이터 서버에서 Google이 서명한 ID 토큰을 가져옵니다
  JWT=$(curl -sS -H "Metadata-Flavor: Google" \
    "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full")

  # 이 토큰을 Anthropic 액세스 토큰으로 교환합니다
  RESPONSE=$(curl -sS https://api.anthropic.com/v1/oauth/token \
    -H "content-type: application/json" \
    --data @- <<JSON
  {
    "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
  )
  ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r .access_token)

  # Claude API를 호출합니다
  curl -sS 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 from Cloud Run"}]
    }' | jq -r '.content[] | select(.type == "text") | .text'
  ```

  ```python Python
  import os
  import anthropic
  import google.auth.transport.requests
  import google.oauth2.id_token
  from anthropic import WorkloadIdentityCredentials

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


  def fetch_google_identity_token() -> str:
      request = google.auth.transport.requests.Request()
      return google.oauth2.id_token.fetch_id_token(request, AUDIENCE)


  client = anthropic.Anthropic(
      credentials=WorkloadIdentityCredentials(
          identity_token_provider=fetch_google_identity_token,
          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 from Cloud Run"}],
  )
  print(next(block.text for block in message.content if block.type == "text"))
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";
  import { oidcFederationProvider } from "@anthropic-ai/sdk/lib/credentials/oidc-federation";

  const METADATA_URL =
    "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full";

  async function fetchGoogleIdentityToken(): Promise<string> {
    const response = await fetch(METADATA_URL, {
      headers: { "Metadata-Flavor": "Google" }
    });
    return response.text();
  }

  const client = new Anthropic({
    credentials: oidcFederationProvider({
      identityTokenProvider: fetchGoogleIdentityToken,
      federationRuleId: process.env.ANTHROPIC_FEDERATION_RULE_ID!,
      organizationId: process.env.ANTHROPIC_ORGANIZATION_ID!,
      serviceAccountId: process.env.ANTHROPIC_SERVICE_ACCOUNT_ID,
      workspaceId: process.env.ANTHROPIC_WORKSPACE_ID,
      baseURL: "https://api.anthropic.com",
      fetch
    })
  });

  const message = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello from Cloud Run" }]
  });
  for (const block of message.content) {
    if (block.type === "text") {
      console.log(block.text);
    }
  }
  ```

  ```go Go
  const audience = "https://api.anthropic.com"

  googleIDToken := func(ctx context.Context) (string, error) {
  	creds, err := idtoken.NewCredentials(&idtoken.Options{Audience: audience})
  	if err != nil {
  		return "", err
  	}
  	tok, err := creds.Token(ctx)
  	if err != nil {
  		return "", err
  	}
  	return tok.Value, nil
  }

  client := anthropic.NewClient(
  	option.WithFederationTokenProvider(googleIDToken, 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(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Hello from Cloud Run")),
  	},
  })
  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
  import com.anthropic.config.AuthenticationConfig;
  import com.anthropic.config.AuthenticationType;
  import com.anthropic.config.IdentityTokenConfig;
  import com.anthropic.config.InMemoryProfileConfigProvider;
  import com.anthropic.config.ProfileConfig;
  // ...
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  void main() throws Exception {
      HttpClient http = HttpClient.newHttpClient();
      HttpRequest metadataRequest = HttpRequest.newBuilder()
              .uri(URI.create("http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full"))
              .header("Metadata-Flavor", "Google")
              .build();

      // Java SDK는 함수가 아니라 토큰 자체 또는 파일 경로를 받습니다.
      // source("value")를 사용하면 path(...)에 토큰이 담깁니다. SDK는 Anthropic 액세스 토큰을
      // 갱신할 때마다 동일한 토큰을 전송하므로, 토큰이 만료되었거나
      // jti 클레임이 있는 경우 이미 사용되었다면 실패합니다. 장시간 실행되는
      // 프로세스에서는 source("file")을 전달하고 매 갱신 전에
      // 파일에 새 토큰을 기록하세요.
      String googleIdentityToken = http.send(metadataRequest, HttpResponse.BodyHandlers.ofString()).body();

      AnthropicClient client = AnthropicOkHttpClient.builder()
              .configurationProvider(InMemoryProfileConfigProvider.of(ProfileConfig.builder()
                      .organizationId(System.getenv("ANTHROPIC_ORGANIZATION_ID"))
                      .workspaceId(System.getenv("ANTHROPIC_WORKSPACE_ID"))
                      .authentication(AuthenticationConfig.builder()
                              .type(AuthenticationType.OIDC_FEDERATION)
                              .federationRuleId(System.getenv("ANTHROPIC_FEDERATION_RULE_ID"))
                              .serviceAccountId(System.getenv("ANTHROPIC_SERVICE_ACCOUNT_ID"))
                              .identityToken(IdentityTokenConfig.builder()
                                      .source("value")
                                      .path(googleIdentityToken)
                                      .build())
                              .build())
                      .build()))
              .build();

      var message = client.messages().create(MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024)
              .addUserMessage("Hello from Cloud Run")
              .build());

      IO.println(message.content());
  }
  ```

  ```csharp C#
  using Anthropic.Credentials;
  // ...

  var credentials = new WorkloadIdentityCredentials(new WorkloadIdentityOptions
  {
      FederationRuleId = Environment.GetEnvironmentVariable("ANTHROPIC_FEDERATION_RULE_ID")!,
      OrganizationId = Environment.GetEnvironmentVariable("ANTHROPIC_ORGANIZATION_ID"),
      ServiceAccountId = Environment.GetEnvironmentVariable("ANTHROPIC_SERVICE_ACCOUNT_ID"),
      WorkspaceId = Environment.GetEnvironmentVariable("ANTHROPIC_WORKSPACE_ID"),
      IdentityTokenProvider = new MetadataTokenProvider(),
  });
  using var client = new AnthropicClient(new ClientOptions { Credentials = credentials });

  var message = await client.Messages.Create(new()
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Messages = [new() { Role = Role.User, Content = "Hello from Cloud Run" }],
  });
  foreach (var block in message.Content)
  {
      if (block.Value is TextBlock textBlock)
      {
          Console.WriteLine(textBlock.Text);
      }
  }

  class MetadataTokenProvider : IIdentityTokenProvider
  {
      private const string METADATA_URL =
          "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full";

      private static readonly HttpClient httpClient = new()
      {
          DefaultRequestHeaders = { { "Metadata-Flavor", "Google" } },
      };

      public async Task<string> GetIdentityTokenAsync(CancellationToken ct = default)
      {
          return await httpClient.GetStringAsync(METADATA_URL, ct);
      }
  }
  ```

  ```bash CLI
  # CLI가 읽을 수 있는 파일에 Google이 서명한 ID 토큰을 기록합니다
  ANTHROPIC_IDENTITY_TOKEN_FILE=$(mktemp)
  curl -sS -H "Metadata-Flavor: Google" \
    "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full" \
    > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
  export 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 from Cloud Run"}'
  ```

  ```php PHP
  use Anthropic\Client;
  use Anthropic\Lib\Credentials\CredentialResult;
  use Anthropic\Lib\Credentials\IdentityTokenProvider;
  use Anthropic\Lib\Credentials\TokenCache;
  use Anthropic\Lib\Credentials\WorkloadIdentityCredentials;

  const METADATA_URL = 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full';

  class GoogleIdentityToken implements IdentityTokenProvider
  {
      public function getIdentityToken(): string
      {
          $context = stream_context_create([
              'http' => ['header' => "Metadata-Flavor: Google\r\n"],
          ]);

          return file_get_contents(METADATA_URL, false, $context);
      }
  }

  $credentials = new CredentialResult(
      provider: new TokenCache(new WorkloadIdentityCredentials(
          identityProvider: new GoogleIdentityToken(),
          federationRuleId: getenv('ANTHROPIC_FEDERATION_RULE_ID'),
          organizationId: getenv('ANTHROPIC_ORGANIZATION_ID'),
          serviceAccountId: getenv('ANTHROPIC_SERVICE_ACCOUNT_ID'),
          workspaceId: getenv('ANTHROPIC_WORKSPACE_ID') ?: null,
      )),
  );
  $client = new Client(credentials: $credentials);

  $message = $client->messages->create(
      model: 'claude-opus-5-5',
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Hello from Cloud Run']],
  );
  $textBlock = array_find($message->content, static fn ($block): bool => $block->type === 'text');
  echo $textBlock->text, PHP_EOL;
  ```

  ```ruby Ruby
  require "anthropic"
  require "net/http"

  METADATA_URL = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full"

  credentials = Anthropic::WorkloadIdentityCredentials.new(
    identity_token_provider: -> { Net::HTTP.get(URI(METADATA_URL), {"Metadata-Flavor" => "Google"}) },
    federation_rule_id: ENV.fetch("ANTHROPIC_FEDERATION_RULE_ID"),
    organization_id: ENV.fetch("ANTHROPIC_ORGANIZATION_ID"),
    service_account_id: ENV.fetch("ANTHROPIC_SERVICE_ACCOUNT_ID"),
    workspace_id: ENV["ANTHROPIC_WORKSPACE_ID"]
  )
  client = Anthropic::Client.new(credentials: credentials)

  message = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello from Cloud Run"}]
  )
  puts message.content.find { it.type == :text }.text
  ```
</CodeGroup>

Google ID 토큰은 약 1시간 후에 만료됩니다. Java를 제외하고(해당 예제의 주석 참조), SDK는 만료 전에 토큰 제공자를 다시 호출하고 자동으로 재교환합니다. 액세스 토큰의 `expires_in`보다 오래 실행되는 셸 스크립트의 경우, 타이머로 갱신하고 교환을 반복하세요.

## 설정 확인

워크로드 내부에서 ID 토큰을 디코딩하고 클레임이 규칙과 일치하는지 확인하세요:

```bash cURL
curl -sS -H "Metadata-Flavor: Google" \
  "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full" \
  | jq -rR 'split(".")[1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson'
```

`iss`가 `https://accounts.google.com`이고, `aud`가 `https://api.anthropic.com`이며, `email`이 페더레이션 규칙의 값과 일치하는지 확인하세요. 그런 다음 이전 섹션의 교환을 실행하세요. 교환에 성공하면 `sk-ant-oat01-`로 시작하는 `access_token`과 초 단위의 `expires_in` 값이 반환됩니다. 교환이 불투명한 `401` `authentication_error` 응답(메시지 `Authentication failed`)으로 실패하면, Claude Console의 [인증 기록 페이지](https://platform.claude.com/settings/workload-identity-federation?tab=history)에서 거부 사유를 확인하고 [실패한 교환 문제 해결](https://platform.claude.com/docs/ko/manage-claude/wif-reference#troubleshoot-a-failed-exchange)을 참조하세요. Google Cloud 측에서 가장 흔한 원인은 `email` 클레임 누락입니다(`email` 클레임이 포함되도록 `format=full`로 토큰을 요청하세요).

## 규칙 범위 지정

<Warning>
  Google `sub` 클레임은 서비스 계정의 불투명한 숫자형 고유 ID이며 안정적인 접두사가 없습니다. 끝에 `*`가 붙은 `subject_prefix`는 모든 Google Cloud 프로젝트에 걸쳐 임의의 서비스 계정과 매칭되며, 그중 어느 것이든 페더레이션된 Anthropic 토큰을 획득할 수 있습니다.
</Warning>

규칙의 `match` 블록을 사용 사례에 맞는 가장 좁은 범위로 제한하세요:

* **`sub`를 정확히 매칭:** `claims.sub`에 전체 숫자형 고유 ID를 설정하고, Google 토큰에는 절대 `subject_prefix`를 사용하지 마세요.
* **`email` 클레임 고정:** `sub`와 함께 `claims.email`을 추가하여 안정적인 ID와 읽을 수 있는 주소가 모두 일치해야 하도록 하세요.
* **audience 고정:** `audience`를 메타데이터 서버에 요청하는 정확한 값으로 설정하여 다른 소비자를 위해 발급된 토큰이 거부되도록 하세요.
* **GKE에서 프로젝트 고정:** `format=full` 토큰의 경우, `claims.google.compute_engine.project_id == "my-project"`와 같은 `condition`을 추가하여 규칙을 한 프로젝트의 노드로 제한하세요.

## 다음 단계

* 전체 리소스 모델과 SDK 자격 증명 우선순위에 대해서는 [Workload Identity Federation](https://platform.claude.com/docs/ko/manage-claude/workload-identity-federation) 페이지를 읽어보세요.
* 환경(프로덕션, 스테이징)별로 별도의 페더레이션 규칙을 추가하여 다른 환경에 영향을 주지 않고 하나를 취소할 수 있도록 하세요.
