GKE の Agent Sandbox で AI コード実行を分離する

Google Kubernetes Engine(GKE)クラスタに Agent Sandbox Python クライアントを使用する開発環境をデプロイできます。この設定により、信頼できないコードをサンドボックス化された Python 環境内に分離することで、AI 生成コードを安全に実行してテストできます。この分離は、AI 生成コードの潜在的な脆弱性からシステムを保護し、開発速度を向上させ、安全なデプロイを確保するために不可欠です。GKE の Agent Sandbox が信頼できない AI 生成コードを分離する方法の概要については、GKE の Agent Sandbox についてをご覧ください。

費用

GKE の Agent Sandbox は追加料金なしで提供されます。作成したリソースには GKE の料金が適用されます。

始める前に

  1. Cloud de Confiance コンソールのプロジェクト セレクタページで、 Cloud de Confiance プロジェクトを選択または作成します。

    プロジェクトの選択または作成に必要なロール

    • プロジェクトを選択する: プロジェクトを選択する際に、特定の IAM ロールは必要ありません。ロールが付与されているプロジェクトを選択できます。
    • プロジェクトを作成する: プロジェクトを作成するには、resourcemanager.projects.create 権限を含むプロジェクト作成者のロール(roles/resourcemanager.projectCreator)が必要です。詳しくは、ロールを付与する方法をご覧ください。

    プロジェクト セレクタに移動

  2. Cloud de Confiance プロジェクトに対して課金が有効になっていることを確認します。

  3. Artifact Registry API と Kubernetes Engine API を有効にします(有効になっていない場合)。

    API を有効にするために必要なロール

    API を有効にするには、serviceusage.services.enable 権限が必要です。プロジェクトを作成した場合は、オーナーロール(roles/owner)を介してこの権限がすでに付与されている可能性があります。それ以外の場合は、Service Usage 管理者ロール(roles/serviceusage.serviceUsageAdmin)を介してこの権限を取得できます。ロールを付与する方法を確認する。

    API を有効にする

  4. Cloud de Confiance コンソールで Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

  5. このドキュメントを完了するために必要な権限があることを確認します。
  6. GKE で Agent Sandbox が有効になっている GKE クラスタが必要です。クラスタがない場合は、GKE で Agent Sandbox を有効にするの手順に沿って、新しいクラスタを作成するか、既存のクラスタを更新します。

必要なロール

サンドボックスの作成と管理に必要な権限を取得するには、プロジェクトに対する Kubernetes Engine 管理者 (roles/container.admin)IAM ロールを付与するよう管理者に依頼してください。ロールの付与については、プロジェクト、フォルダ、組織に対するアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

環境変数を定義する

このドキュメントで実行するコマンドを簡略化するために、Cloud Shell で環境変数を設定できます。Cloud Shell で、次のコマンドを実行して環境変数を定義します。

export PROJECT_ID=$(gcloud config get project)
export CLUSTER_NAME="agent-sandbox-cluster"
export LOCATION="us-central1"
export NODE_POOL_NAME="agent-sandbox-node-pool"
export MACHINE_TYPE="e2-standard-2"

これらの環境変数の説明は次のとおりです。

  • PROJECT_ID: 現在の Cloud de Confiance by S3NS プロジェクトの ID。この変数を定義すると、GKE クラスタなどのすべてのリソースが正しいプロジェクトに作成されます。
  • CLUSTER_NAME: GKE クラスタの名前(例: agent-sandbox-cluster)。
  • LOCATION: GKE クラスタが配置されている Cloud de Confiance by S3NS リージョンまたはゾーン。Autopilot クラスタを使用している場合はリージョン(us-central1 など)に設定し、Standard クラスタを使用している場合はゾーン(us-central1-a など)に設定します。
  • NODE_POOL_NAME: サンドボックス化されたワークロードを実行するノードプールの名前(例: agent-sandbox-node-pool)。
  • MACHINE_TYPE: ノードプール内のノードのマシンタイプ(e2-standard-2 など)。さまざまなマシンシリーズとさまざまなオプションの選択の詳細については、マシン ファミリーのリソースと比較ガイドをご覧ください。

サンドボックス環境をデプロイする

このセクションでは、サンドボックス ブループリント(SandboxTemplate)を作成し、必要なネットワーキング ルーターをデプロイして、サンドボックスの操作に使用する Python クライアントをインストールする方法について説明します。

サンドボックスを作成して操作するには、Agentic Sandbox Python クライアントを使用することをおすすめします。このクライアントは、サンドボックスの作成からクリーンアップまでのライフサイクル全体を簡素化するインターフェースを提供します。これは、サンドボックスの作成、使用、削除をプログラムで行うために使用できる Python ライブラリです。

クライアントは、すべてのトラフィックの中央エントリ ポイントとしてサンドボックス ルーターを使用します。このドキュメントで説明する例では、クライアントは kubectl port-forward コマンドを使用してこのルーターへのトンネルを作成するため、パブリック IP アドレスを公開する必要はありません。kubectl port-forward の使用は安全なソリューションではなく、開発環境での使用に限定する必要があります。

SandboxTemplate と SandboxWarmPool を作成する

SandboxTemplate リソースと SandboxWarmPool リソースを作成して、サンドボックスの構成を定義します。SandboxTemplate は、Agent Sandbox コントローラが使用して、一貫性のある事前構成済みのサンドボックス環境を作成する再利用可能なブループリントとして機能します。SandboxWarmPool リソースは、指定された数の事前にウォームアップされた Pod が常に実行され、要求される準備ができていることを保証します。事前にウォームアップされたサンドボックスは、すでに初期化されている実行中の Pod です。この事前初期化により、新しいサンドボックスを 1 秒以内に作成できるようになり、通常のサンドボックスの起動時のレイテンシを回避できます。

  1. Cloud Shell で、次の内容を含むファイルを sandbox-template-and-pool.yaml という名前で作成します。

    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxTemplate
    metadata:
      name: python-runtime-template
      namespace: default
    spec:
      podTemplate:
        metadata:
          labels:
            sandbox: python-sandbox-example
        spec:
          runtimeClassName: gvisor
          automountServiceAccountToken: false # Required
          securityContext:
            runAsNonRoot: true # Required
          nodeSelector:
            sandbox.gke.io/runtime: gvisor # Required
          tolerations:
          - key: "sandbox.gke.io/runtime"
            value: "gvisor"
            effect: "NoSchedule" # Required
          containers:
          - name: python-runtime
            image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
            ports:
            - containerPort: 8888
            readinessProbe:
              httpGet:
                path: "/"
                port: 8888
              initialDelaySeconds: 0
              periodSeconds: 1
            resources:
              requests:
                cpu: "250m"
                memory: "512Mi"
              limits:
                cpu: "500m"
                memory: "1Gi" # Required
            securityContext:
              capabilities:
                drop: ["ALL"] # Required
          restartPolicy: "OnFailure"
    ---
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxWarmPool
    metadata:
      name: python-sandbox-warmpool
      namespace: default
    spec:
      replicas: 2
      sandboxTemplateRef:
        name: python-runtime-template
    
  2. SandboxTemplate マニフェストと SandboxWarmPool マニフェストを適用します。

    kubectl apply -f sandbox-template-and-pool.yaml
    

サンドボックス ルーターをデプロイする

サンドボックス環境の作成と操作に使用する Python クライアントは、サンドボックス ルーターと呼ばれるコンポーネントを使用してサンドボックスと通信します。

この例では、テストにクライアントのデベロッパー モードを使用します。このモードはローカル開発を目的としており、kubectl port-forward コマンドを使用して、ローカルマシンから、クラスタで実行されているサンドボックス ルーター サービスへの直接トンネルを確立します。このトンネリング アプローチでは、パブリック IP アドレスや複雑な上り(内向き)設定が不要になり、ローカル環境からのサンドボックスの操作が簡素化されます。

サンドボックス ルーターをデプロイする手順は次のとおりです。

  1. Cloud Shell で、次の内容を含むファイルを sandbox-router.yaml という名前で作成します。

    # A ClusterIP Service to provide a stable endpoint for the router pods.
    apiVersion: v1
    kind: Service
    metadata:
      name: sandbox-router-svc
      namespace: default
    spec:
      type: ClusterIP
      selector:
        app: sandbox-router
      ports:
      - name: http
        protocol: TCP
        port: 8080 # The port the service will listen on
        targetPort: 8080 # The port the router container listens on (from the sandbox_router/Dockerfile)
    ---
    # The Deployment to manage and run the router pods.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sandbox-router-deployment
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sandbox-router
      template:
        metadata:
          labels:
            app: sandbox-router
        spec:
          # Ensure pods are spread across different zones for HA
          topologySpreadConstraints:
            - maxSkew: 1
              topologyKey: topology.kubernetes.io/zone
              whenUnsatisfiable: ScheduleAnyway
              labelSelector:
                matchLabels:
                  app: sandbox-router
          containers:
          - name: router
            image: us-central1-docker.pkg.dev/k8s-staging-images/agent-sandbox/sandbox-router:latest-main
            ports:
            - containerPort: 8080
            readinessProbe:
              httpGet:
                path: /healthz
                port: 8080
              initialDelaySeconds: 5
              periodSeconds: 5
            livenessProbe:
              httpGet:
                path: /healthz
                port: 8080
              initialDelaySeconds: 10
              periodSeconds: 10
            resources:
              requests:
                cpu: "100m"
                memory: "512Mi"
              limits:
                cpu: "1000m"
                memory: "1Gi"
          securityContext:
            runAsUser: 1000
            runAsGroup: 1000
    
  2. マニフェストを適用して、ルーターをクラスタにデプロイします。

    kubectl apply -f sandbox-router.yaml
    
  3. Sandbox Router のデプロイが正しく実行されていることを確認します。

    kubectl get deployment sandbox-router-deployment
    

    デプロイの READY 列に 2/2 または 1/1 が表示されるまで待ちます。

Python クライアントをインストールする

サンドボックス ルーターなどのクラスタ内コンポーネントがデプロイされたので、最後の準備手順として、ローカルマシンに Agentic Sandbox Python クライアントをインストールします。このクライアントは、サンドボックスをプログラムで作成、使用、削除できる Python ライブラリです。次のセクションで、環境のテストに使用します。

  1. Python 仮想環境を作成してアクティブにします。

    python3 -m venv .venv
    source .venv/bin/activate
    
  2. クライアント パッケージをインストールします。

    pip install k8s-agent-sandbox
    

サンドボックスをテストする

すべての設定コンポーネントが整ったので、Agentic Sandbox Python クライアントを使用してサンドボックスを作成し、操作できるようになりました。

  1. agent-sandbox ディレクトリに、次の内容の Python スクリプトを test_sandbox.py という名前で作成します。

    from k8s_agent_sandbox import SandboxClient
    from k8s_agent_sandbox.models import SandboxLocalTunnelConnectionConfig
    
    # Automatically tunnels to svc/sandbox-router-svc
    client = SandboxClient(
        connection_config=SandboxLocalTunnelConnectionConfig()
    )
    
    sandbox = client.create_sandbox(template="python-runtime-template", namespace="default")
    try:
        print(sandbox.commands.run("echo 'Hello from the sandboxed environment!'").stdout)
    except Exception as e:
        print(f"An error occurred: {e}")
    
  2. ターミナルから(仮想環境がアクティブな状態で)、テスト スクリプトを実行します。

    python3 test_sandbox.py
    

サンドボックスから出力される「Hello from the sandboxed environment!」というメッセージが表示されます。

これで完了です。安全なサンドボックス内でシェルコマンドが正常に実行されました。sandbox.run() メソッドを使用すると、任意のシェルコマンドを実行できます。GKE の Agent Sandbox は、クラスタのノードや他のワークロードを信頼できないコードから保護する安全なバリア内でコマンドを実行します。これにより、AI エージェントや自動化されたワークフローがタスクを実行するための安全で信頼性の高い方法が提供されます。

スクリプトの実行時に、SandboxClient によってすべての手順が処理されます。SandboxClaim リソースを作成してサンドボックスを起動し、サンドボックスの準備が整うまで待機してから、sandbox.run() メソッドを使用して安全なコンテナ内で bash シェルコマンドを実行します。クライアントは、そのコマンドから stdout をキャプチャして出力します。サンドボックスは、プログラムの実行後に自動的に削除されます。

SandboxClaim リソースが作成されると、使用可能な Pod がウォームプールから Sandbox オブジェクトに割り当てられ、クレームが準備完了とマークされます。その後、SandboxWarmPool は自動的に補充され、構成されたレプリカ数を維持します。

特定のサンドボックスが要求されているか、使用可能かを確認するには、サンドボックス Pod のメタデータの ownerReferences を確認します。kind フィールドの値が Sandbox の場合、Pod は使用中です。kind フィールドの値が SandboxWarmPool の場合、Pod はアイドル状態で、要求されるのを待っています。

本番環境でサンドボックスを実行する

このドキュメントでは、Cloud Shell を使用してクラスタの外部からサンドボックスを操作します。Python クライアントは、ユーザー認証情報を使用してクラスタを認証し、サンドボックス リソースを管理します。また、kubectl port-forward コマンドを使用してサンドボックスとの接続を確立します。これらの手順は、開発シナリオに適しています。

本番環境のシナリオでは、コントローラ アプリケーション(AI オーケストレーターなど)がサンドボックス リソースの作成と管理を担当します。GKE で Agent Sandbox を本番環境で使用する場合は、次の点を考慮してください。

  • 認証: コントローラ アプリケーションは、サンドボックスを実行するためにクラスタ API サーバーに対して認証する必要があります。認証の構成方法は、コントローラ アプリケーションの実行場所によって異なります。

    • コントローラ アプリケーションが同じクラスタ内の Pod として実行されている場合は、Kubernetes RBAC または Workload Identity Federation for GKE と IAM ポリシーを使用して、Pod の Kubernetes ServiceAccount に、サンドボックスの監視やネットワーク エンドポイントの検出に必要な権限を付与します。
    • コントローラ アプリケーションがクラスタの外部で実行されている場合は、Workload Identity 連携または IAM サービス アカウントを使用して、許可ポリシーで参照できる ID をアプリケーションに付与します。
  • ルーティング: コントローラ アプリケーションの Python クライアントからのリクエストは、クラスタ内のサンドボックス ルーターに到達する必要があります。本番環境では、次のいずれかの方法でネットワーク接続を確立します。

    • コントローラ アプリケーションが同じクラスタで実行されている場合は、SandboxDirectConnectionConfig 関数を使用して、Sandbox Router サービスが使用する URL とポートをターゲットにします。
    • コントローラ アプリケーションがクラスタの外部で実行されている場合は、GKE Gateway API を使用して内部または外部のロードバランサを作成します。クライアント コードで、SandboxGatewayConnectionConfig 関数を使用して Gateway を参照します。

    これらのルーティング方法の詳細については、GitHub の使用例とルーターの Gateway デプロイ手順をご覧ください。

  • Cloud de Confiance リソースへのサンドボックス アクセス: サンドボックス コードが Cloud de Confiance API(Cloud Storage など)にリクエストを送信する必要がある場合は、Workload Identity Federation for GKE で IAM ポリシーを使用して、サンドボックス Pod が使用する Kubernetes ServiceAccount に、そのアクセスに必要な権限を付与します。デフォルトのネットワーク ポリシーでは Cloud de Confiance by S3NS メタデータ サーバー(169.254.169.254)へのアクセスがブロックされるため、このトラフィックを許可するようにネットワーク ポリシーをカスタマイズする必要があります。

  • ネットワーク ポリシーの制限: デフォルトでは、GKE の Agent Sandbox は厳格なセキュア バイ デフォルトのネットワーク ポスチャー(networkPolicyManagement: Managed)を適用します。このポスチャーでは、次の制限が適用されます。

    • 上り(内向き)は、指定されたサンドボックス ルーターを除くすべてのソースからブロックされます。
    • 下り(外向き)はパブリック インターネットに許可されますが、プライベート LAN 範囲(RFC 1918)、内部クラスタ DNS(CoreDNS)、Cloud プロバイダ メタデータ サーバー(169.254.0.0/16)への下り(外向き)は明示的にブロックされます。

    Workload Identity Federation for GKE を使用する場合や、他のプライベート リソースにアクセスする場合は、SandboxTemplate でカスタム ネットワーク ポリシーを定義する必要があります。詳細な構成の詳細とカスタマイズ可能なテンプレート(エアギャップ サンドボックスや Workload Identity Federation for GKE 統合など)については、エージェント サンドボックス ネットワーク ポリシー管理をご覧ください。

サンドボックス セキュリティ ポリシー

デフォルトで安全な環境を確保するために、GKE アドオンの Agent Sandbox は Kubernetes 検証アドミッション ポリシー(VAP)を使用して、Sandbox リソースと SandboxTemplate リソースにセキュリティ制約を適用します。これらのポリシーは自動的に適用されます。

このアドオンでは、セキュリティの適用を 2 段階のポリシーモデルに分割することで、柔軟性を高めています。以降のセクションでは、厳格に管理されたコアポリシーとカスタマイズ可能な強化ポリシーについて説明します。

コア セキュリティ ポリシー(sandbox-core-policy)

コア セキュリティ ポリシーは、サンドボックスの整合性を保護する分離要件を適用します。このポリシーには、gVisor の使用、hostNetwork の無効化などのネットワーク分離、hostPath のブロックなどのファイル システム分離を必要とするルールが含まれています。GKE は addonmanager.kubernetes.io/mode: Reconcile 設定を通じてこのポリシーを管理するため、これらのコアルールを変更またはオーバーライドすることはできません。

セキュリティ ポリシーの強化(sandbox-hardening-policy)

セキュリティ強化ポリシーには、セキュリティに関する追加のベスト プラクティスと管理オプションが用意されています。すべての機能の削除、新しい機能の追加の防止、リソース制限付きの非 root としてコンテナを実行する必要があるなどの制約を適用します。GKE は、addonmanager.kubernetes.io/mode: EnsureExists 設定を使用して、このポリシーを EnsureExists モードでデプロイします。この設定は、ポリシーが存在しない場合に GKE がポリシーを作成することを意味しますが、必要に応じてポリシーまたはそのバインディングを変更または削除できます。

強化制約を変更または削除する

強化ポリシーは EnsureExists モードでデプロイされるため、GKE はポリシーが存在しない場合は作成しますが、変更を上書きしません。ワークロードでこれらの強化ルールの免除が必要な場合は、ポリシーを変更して特定の制約を削除するか、ポリシー バインディングを完全に削除できます。

ハードニング ポリシーを変更して特定の制約を削除する(コンテナを root として実行できるようにする、リソース上限を省略するなど)には、ValidatingAdmissionPolicy リソースを編集します。

kubectl edit validatingadmissionpolicy sandbox-hardening-policy

開いたテキスト エディタで、validations セクションを見つけて、ワークロードをブロックする制約式を削除または変更します。

また、クラスタの強化ポリシーを完全に無効にする場合は、ポリシー バインディングを削除します。

kubectl delete validatingadmissionpolicybinding sandbox-hardening-binding

既知の問題

このセクションでは、GKE で Agent Sandbox を使用する際の既知の問題と、その解決方法または回避策について説明します。

サービス メッシュを使用するとセキュリティ ポリシーが機能をブロックする

サービス メッシュ サイドカー(Envoy や Istio など)と統合するサンドボックスをデプロイしようとすると、サンドボックスの作成が強化されたセキュリティ ポリシーによってブロックされ、次のようなエラーが発生することがあります。

sandbox create error: sandboxes.agents.x-k8s.io "claude-cli-claim-managed" is forbidden:
ValidatingAdmissionPolicy 'sandbox-hardening-policy' with binding 'sandbox-hardening-binding'
denied request: Security Violation: Capabilities.add must be empty. You cannot add capabilities.
  • 原因: サービス メッシュ サイドカーは、istio-init や proxy-init などの init コンテナを使用することがよくあります。これらの初期コンテナでは、透過的な下り(外向き)ルーティングの iptables ルールを構成するために、NET_ADMIN や NET_RAW などの機能が必要です。デフォルトでは、GKE sandbox-hardening-policy はすべてのコンテナタイプですべての機能の追加をブロックします。
  • 回避策: GKE 強化ポリシーは EnsureExists モードでデプロイされるため、ValidatingAdmissionPolicy を変更して、特定の信頼できる init コンテナが NET_ADMIN 機能と NET_RAW 機能をリクエストできるようにします。これらの強化制約を変更または削除する手順については、強化制約を変更または削除するをご覧ください。たとえば、ポリシーの検証式または変数を更新して、信頼できるコンテナ名を機能ルールから除外できます。

IPv6 経由で Google API に接続する際の下り(外向き)レイテンシまたはタイムアウト

サンドボックス内のワークロードが外部リソースまたは Google API(Vertex AI や Cloud Storage など)に接続しようとすると、接続タイムアウトやレイテンシの増加(最大 2 分)が発生する可能性があります。

  • 原因: GKE クラスタでデュアルスタック IPv6 が有効になっている場合、Google API の DNS の解決は IPv4(A)アドレスと IPv6(AAAA)アドレスの両方を返します。Node.js などのランタイム エンジンのアルゴリズムの中には、最初に IPv6 経由で接続を試みるものがあります。GKE VPC に有効な IPv6 下り(外向き)ルート(Cloud NAT や IPv6 用のインターネット ゲートウェイなど)がない場合、TCP SYN タイムアウトが期限切れになるまで TCP 接続は応答を停止します。その後、TCP 接続は IPv4 にフォールバックします。
  • 解決策: この問題を解決するには、次のいずれかを行います。

    • IPv6 下り(外向き)を構成する: 送信 IPv6 トラフィックがクラスタに戻るようにするには、VPC ネットワークで有効な IPv6 Cloud NAT またはインターネット ゲートウェイを構成します。
    • ワークロードで IPv4 を優先する: IPv4 DNS の解決を優先するには、ワークロードのランタイムを構成します。たとえば、Node.js アプリケーションでは、SandboxTemplate 定義で次の環境変数を設定できます。

      env:
      - name: NODE_OPTIONS
        value: "--dns-result-order=ipv4first --no-network-family-autoselection"
      

リソースのクリーンアップ

Cloud de Confiance by S3NS アカウントに課金されないようにするには、作成した GKE クラスタを削除する必要があります。

gcloud container clusters delete $CLUSTER_NAME --location=$LOCATION --quiet

次のステップ