エージェント ID を持つ Google Kubernetes Engine(GKE)エージェントは、その ID を使用して Google Cloud API と外部ツールおよびサービスに対して認証できます。エージェントは、自分の ID を使用することも、エンドユーザーの代理として行動することもできます。このドキュメントでは、エージェント アプリケーション デベロッパーがさまざまなリソースに対して認証を行うようにアプリケーションを構成する方法について説明します。GKE エージェントのエージェント ID をリクエストする方法をすでに理解していることを前提としています。
エージェントがアクセスする必要があるリソースに応じて、プラットフォーム管理者は追加のワークフローを実行するように認証マネージャーの認証情報コンテナを構成する必要がある場合があります。たとえば、エージェントがエンドユーザーに代わって GitHub に対して認証を行うには、Auth Manager の 3-legged OAuth 認証プロバイダがユーザーのログイン、認可、リダイレクトを処理する必要があります。デベロッパーは、正しい認証プロバイダを呼び出し、エンドユーザーの会話の再開を処理するようにエージェントを変更します。
制限事項
- エージェント ID の制限事項をご覧ください。
- Google 認証ライブラリを使用して、Python 用のバインドされたアクセス トークンと ID トークンのみを取得できます。認証ライブラリは、他の言語のバインド トークンを取得できない場合があります。別の言語を使用している場合は、
GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN環境変数をfalseに設定して、バインドされていないトークンに切り替えます。
始める前に
作業を始める前に、次のタスクが完了していることを確認してください。
- Google Kubernetes Engine API を有効にする。 Google Kubernetes Engine API を有効化
- このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化します。gcloud CLI をインストール済みの場合は、
gcloud components updateコマンドを実行して最新のバージョンを取得します。以前のバージョンの gcloud CLI では、このドキュメントのコマンドを実行できない場合があります。
- エージェント ID を使用するワークロードが実行されている既存のクラスタに接続します。ワークロードのエージェント ID をリクエストするには、GKE エージェントのエージェント ID をリクエストするをご覧ください。
- 認証マネージャーを使用して外部ツールやサービスに対する認証を行うには、プラットフォーム管理者に次の操作を依頼してください。
- 認証ワークフローの認証プロバイダを設定します。
- エージェントに認証プロバイダへのアクセス権を付与します。
必要なロール
GKE クラスタにデプロイされたエージェントを構成するために必要な権限を取得するには、プロジェクトに対する Kubernetes Engine デベロッパー (roles/container.developer)IAM ロールを付与するよう管理者に依頼してください。ロールの付与については、プロジェクト、フォルダ、組織に対するアクセス権の管理をご覧ください。
必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。
Google Cloud APIs に対する認証
エージェント自身の ID として Google Cloud APIs に対する認証を行うために、エージェントはノードのメタデータ サーバーからエージェント ID アクセス トークンを使用できます。コードに加える必要のある変更は、次のように Google Cloud API の呼び出し方法によって異なります。
Cloud クライアント ライブラリを使用する
google-auth ライブラリのバージョン 2.61.0 以降を含むバージョンの Cloud クライアント ライブラリを使用している場合、アプリケーションのデフォルト認証情報(ADC)はエージェント ID アクセス トークンを自動的に取得します。コードに追加の変更を加える必要はありません。iam.gke.io/inject-podcertificates: "true" アノテーションを設定して Pod の証明書インジェクションを有効にすると、バインドされたトークンを無効にしない限り、アクセス トークンはデフォルトで X.509 証明書にバインドされます。
Cloud クライアント ライブラリを使用するときにバインドされていないアクセス トークンを取得するには、次のいずれかを行います。
- Pod で証明書の挿入を有効にし、
GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN環境変数をfalseに設定します。 - Pod で証明書の挿入を有効にしないでください。
Google Cloud API エンドポイントへの直接呼び出しを使用する
Cloud クライアント ライブラリを使用してサービスとやり取りしない場合は、次の操作を行って、エージェントの ID を使用して Google Cloud API に対する認証を行うことができます。
ノードのメタデータ サーバーからアクセス トークンを取得します。トークンは、次のいずれかの方法で取得できます。
バインドされたアクセス トークン:
google-authPython ライブラリを使用します。このライブラリは、Pod の X.509 証明書を検出し、デフォルトでバインドされたアクセス トークンを自動的に取得します。他のプログラミング言語では、バインドされていないトークンを使用します。バインドされていないアクセス トークン: Pod にエージェント ID 認証情報バンドルがない場合は、プログラミング言語用の Google 認証ライブラリを使用します。認証ライブラリは、バインドされていないアクセス トークンを自動的に取得し、期限切れのトークンを更新します。認証情報バンドルを含む Pod の Python アプリケーションの場合は、次の例のように、Pod 仕様で
GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN環境変数をfalseに設定します。# Multiple lines are omitted here. spec: containers: - name: example-agent image: example-image env: - name: GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN value: "false" # Multiple lines are omitted here.この環境変数を設定すると、ライブラリがバインドされたアクセス トークンと ID トークンを取得できなくなります。
バインドされたアクセス トークンの場合は、API の mTLS エンドポイントにリクエストを送信し、HTTP トランスポートにエージェント ID の X.509 証明書チェーンを含めます。Python 用の Google 認証ライブラリを使用する場合、ライブラリが HTTP トランスポート構成を処理します。
次の例は、Python 用の Google 認証ライブラリを使用してバインドされたアクセス トークンを取得し、Cloud Storage mTLS エンドポイントにリクエストを行う方法を示しています。
import google.auth
from google.auth.transport.requests import AuthorizedSession
def call_storage_api_mtls(bucket_name: str) -> None:
# Discover the Pod's X.509 certificate chain by using the auth library
credentials, project = google.auth.default(
scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
# Configure the mTLS session by using the Pod's certificate chain
session = AuthorizedSession(credentials)
session.configure_mtls_channel()
# Call the Google Cloud mTLS endpoint
mtls_url = f"https://storage.mtls.googleapis.com/storage/v1/b/{bucket_name}/o"
response = session.get(mtls_url)
response.raise_for_status()
print(response.json())
外部ツールとサービスに対して認証する
外部ツールやサービスに対して認証を行うには、必要な認証情報を Agent Identity Auth Manager から取得するようにエージェントを構成します。プラットフォーム管理者は、認証マネージャーでさまざまな認証プロバイダを構成します。各プロバイダは、特定の認証ワークフローと認証情報を管理します。特定の認証プロバイダを呼び出し、認証ワークフローに応じてユーザーの同意と会話の再開を処理するように、アプリケーション コードを変更します。エージェントに加える具体的な変更は、アクセスする必要があるものによって異なります。
- エンドユーザーに代わって外部サービスにアクセスするには、次の操作を行います。
- 3-legged OAuth 認証プロバイダを呼び出すようにエージェントを変更します。
- クライアントサイド アプリケーションを変更して、ユーザーのログインとリダイレクトを処理します。
- エージェント自身の権限を使用して外部サービスにアクセスするには、2-legged OAuth 認証プロバイダを呼び出すようにエージェントを変更します。
- API キーを使用して外部 API にアクセスするには、API キー認証プロバイダを呼び出すようにエージェントを変更します。
認証マネージャーは対応する認証ワークフローを処理し、エージェントに暗号化された認証情報へのアクセス権を付与します。これにより、エージェントは外部サービスへのリクエストに認証情報を含めることができます。プラットフォーム管理者がこれらの認証プロバイダを構成し、エージェント ID にアクセス権を付与するために行う必要がある操作の詳細については、エージェントの認証ワークフローをご覧ください。
他のエージェントに対して認証を行う
マルチエージェント アーキテクチャでは、エージェントはピア エージェントまたはダウンストリーム サービスを直接呼び出すことで頻繁に連携します。ID トークンを使用すると、エージェント ワークロード間の直接通信を確立できます。GKE メタデータ サーバーからバインドされた ID トークンまたはバインドされていない ID トークンを取得し、そのトークンを使用して他のエージェントに対して直接認証を行うことができます。
ID トークンを取得して HTTP リクエストでトークンを使用するには、Python 用の Google 認証ライブラリを使用します。ライブラリは、証明書の検出と ID トークンの取得を自動的に処理します。別のプログラミング言語を使用している場合、Google 認証ライブラリはバインドされた ID トークンを取得できない可能性があります。代わりに、バインドされていない ID トークンに切り替えます。
ID トークンを取得する
エージェント コードで ID トークンをリクエストするには、ご使用のプログラミング言語の Google 認証ライブラリを使用します。ライブラリを使用して、次のようにバインドされた ID トークンまたはバインドされていない ID トークンをリクエストできます。
- バインドされた ID トークン:
iam.gke.io/inject-podcertificates: "true"アノテーションを使用して、Pod の証明書挿入を有効にします。Python 用の認証ライブラリは、GKE メタデータ サーバーから証明書バインド ID トークンを自動的にリクエストします。 Google Cloud で実行されているエージェント間で mTLS を使用して認証を行う場合は、バインドされた ID トークンを使用します。 バインドされていない ID トークン:
- Pod の証明書挿入を有効にして、次のいずれかを行います。
- アプリケーション コードの
id_token.fetch_id_token関数で、bind_id_token引数をFalseの値に設定します。この引数を指定すると、認証ライブラリはバインドされていない ID トークンをリクエストします。アクセス トークン リクエストは影響を受けません。 - Pod 仕様で、
GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN環境変数をfalseの値に設定します。この環境変数を設定すると、ライブラリがバインドされたアクセス トークンと ID トークンをリクエストしなくなります。
- アプリケーション コードの
- Pod の証明書挿入を有効にしないでください。Pod に認証情報バンドルがないため、認証ライブラリはバインドされていない ID トークンを取得します。
非 mTLS 接続を使用して Google Cloud API、外部サービス、その他のエージェントに対する認証を行う場合は、バインドされていない ID トークンを使用します。
- Pod の証明書挿入を有効にして、次のいずれかを行います。
次の例は、認証情報の挿入が有効になっているエージェントのバインドされた ID トークンまたはバインドされていない ID トークンをリクエストする方法を示しています。
バインドされた ID トークンをリクエストします。
import google.auth.transport.requests from google.oauth2 import id_token # Application Default Credentials automatically requests a certificate-bound # ID token. def get_bound_id_token(target_audience: str) -> str: auth_req = google.auth.transport.requests.Request() return id_token.fetch_id_token(auth_req, audience=target_audience)バインドされた ID トークンには、Pod の X.509 証明書チェーンの SHA-256 証明書フィンガープリントが
cnf.x5t#S256パラメータに含まれています。バインドされていない ID トークンをリクエストします。
import google.auth.transport.requests from google.oauth2 import id_token def get_unbound_id_token(target_audience: str) -> str: auth_req = google.auth.transport.requests.Request() return id_token.fetch_id_token( auth_req, audience=target_audience, # Always get an unbound ID token, even if the Pod has a credential # bundle. bind_id_token=False, )
別のエージェントへのリクエストで ID トークンを使用する
エージェントの ID トークンを取得したら、そのトークンを使用して別のエージェントに直接認証できます。接続の認証方法は、バインドされた ID トークンを使用するかどうかによって異なります。
- バインドされた ID トークンの場合、受信エージェントとの mTLS 接続を確立し、Pod の
/var/run/secrets/workload-spiffe-credentials/ディレクトリにある次の両方の認証情報を使用して接続を認証します。x509.credential-bundle.private-key.pemファイル内のエージェント ID 認証情報バンドル。Pod のリーフ証明書チェーンが含まれています。TRUST_DOMAIN.spiffe-trust-bundle.pemファイルにあるクラスタ信頼バンドル。このファイルには、受信エージェントのルート CA 証明書が含まれており、mTLS ハンドシェイク中に受信エージェントの証明書チェーンを検証するために使用されます。呼び出し元と受信側のエージェントは、同じエージェント ID プールに存在する必要があります。
- バインドされていない ID トークンの場合は、受信エージェントとの非 mTLS 接続を確立します。
次の例は、バインドされた ID トークンまたはバインドされていない ID トークンを使用して別のエージェントにリクエストを送信する方法を示しています。
バインドされた ID トークン: 受信エージェントの mTLS エンドポイントに送信するリクエストの
Authorization: Bearerヘッダーに、バインドされた ID トークンを含めます。Pod の X.509 証明書と秘密鍵を使用して TLS 接続を認証します。import ssl import urllib3 BUNDLE_PATH = "/var/run/secrets/workload-spiffe-credentials/x509.credential-bundle.private-key.pem" TRUST_BUNDLE_PATH = "/var/run/secrets/workload-spiffe-credentials/TRUST_DOMAIN.spiffe-trust-bundle.pem" def call_peer_agent_bound_mtls(target_mtls_url: str, target_audience: str) -> None: # Configure the mTLS context by using the certificate chain and trust # bundle from the Pod. ctx = ssl.create_default_context(cafile=TRUST_BUNDLE_PATH) ctx.load_cert_chain(BUNDLE_PATH) http = urllib3.PoolManager(ssl_context=ctx, assert_hostname=False) # Call a peer agent's mTLS endpoint by using the bound ID token and Pod # certificate chain. bound_id_token = get_bound_id_token(target_audience) response = http.request( "POST", target_mtls_url, headers={"Authorization": f"Bearer {bound_id_token}"}, json={"task": "analyze_data"}, timeout=10, ) print(response.json())TRUST_DOMAINは、エージェント ID プールの信頼ドメインに置き換えます。バインドされていない ID トークン: ピア エージェントに対するリクエストの
Authorization: Bearerヘッダーにトークンを含めます。import requests def call_peer_agent_unbound(target_url: str, target_audience: str) -> None: unbound_id_token = get_unbound_id_token(target_audience) # Send the request by using a standard TLS connection or plain HTTP. response = requests.post( target_url, headers={"Authorization": f"Bearer {unbound_id_token}"}, json={"task": "analyze_data"}, timeout=10, ) response.raise_for_status() print(response.json())
受信側エージェントでリクエストを検証する
受信側エージェントで、次の手順で受信リクエスト内の ID トークンを検証します。カスタムコードを記述する代わりに、Tink などの暗号ライブラリを使用して、これらの検証手順を実行できます。
- リクエストの
Authorization: Bearerヘッダーから ID トークンを抽出します。 - ID トークンの
iss(発行者)クレームが、呼び出し元エージェントのエージェント ID プールであることを確認します。呼び出し元エージェントが組織内のプロジェクトに属しているかどうかに応じて、発行者は次のいずれかになります。- 組織内のプロジェクト:
https://sts.googleapis.com/v1/organizations/ORGANIZATION_ID/locations/global/workloadIdentityPools/agents.global.org-ORGANIZATION_ID.system.id.goog。ここで、ORGANIZATION_IDは呼び出し元エージェントのプロジェクトを含む組織の組織 ID です。 - 組織に属していないプロジェクト:
https://sts.googleapis.com/v1/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/agents.global.proj-PROJECT_NUMBER.system.id.goog。ここで、PROJECT_NUMBERは呼び出し元エージェントの GKE クラスタのプロジェクト番号です。
- 組織内のプロジェクト:
- 発行者の JSON Web Key Set(JWKS)の URI を検出し、公開 JSON Web Key(JWK)をキャッシュに保存します。JWKS のエンドポイントの形式は
ISSUER_URL/openid/jwksです。ここで、ISSUER_URLは発行者の URL です。 - ID トークンの JOSE ヘッダーから次の情報を使用して、トークン署名を検証します。
kidヘッダー パラメータと一致する公開 JWK。algヘッダー パラメータと一致する暗号アルゴリズム(RS256など)。
cnf.x5t#S256パラメータにある SHA-256 証明書フィンガープリントが、呼び出し元エージェントが mTLS 接続の認証に使用した X.509 証明書のフィンガープリントと一致することを確認します。- ID トークンの次のクレームを確認します。
expクレームの有効期限が将来の日付になっています。audクレームのオーディエンスは受信エージェントです。
- トークンの
sub(サブジェクト)クレームにある SPIFFE ID に基づいてリクエストを承認します。