API キーの管理とセキュリティ

1. はじめに

以前は、他の方法が利用できない場合や不便な場合に、Google API キーを使用して Google API にアクセスしていました。一般的なユースケースは、Google Maps API と Firebase によって公開される Google API へのアクセスでした。AI モデル、Gemini などの AI エージェント、AI Studio や Agent Development Kit などのエージェント開発フレームワークの導入により、API キーは Google の大規模言語モデルにアクセスする主な方法になりました。

API キーの保護レベルは低くなります。Google Cloud にはキーの不正使用を防ぐためのいくつかの方法が用意されていますが、有効な API キーを所有していると、追加の認証や認可の検証なしで Google API にアクセスできます。API キーの使用を制限する方法については、ドキュメントをご覧ください。Cloud ブログの Gemini API キーと Google API キーの保護の投稿では、API キーのメンテナンスに関する追加の推奨事項が記載されています。この Codelab では、これらの推奨事項を実践します。

演習内容

  • Google Cloud で新しい API キーを作成する際に適用される制限を確認する
  • すべての API キーをカタログ化し、セキュリティ保護のないキーを見つける
  • 使用状況に基づいて既存の API キーに制限を適用する
  • 異常な使用があった場合にキーを削除する自動化を定義する

必要なもの

  • 最新のウェブブラウザ(Chrome など)。
  • Google アカウント

2. セットアップ

この Codelab の手順では、Google Cloud コンソールの Cloud Shell でコマンドを実行することを前提としています。ローカル環境に gcloud CLI がある場合は、そこでコマンドを実行できます。

手順の操作は Cloud コンソール UI を使用して行うこともできますが、方法は異なります。この Codelab では、コマンドライン インターフェースを使用して操作を簡素化し、最新の AI エージェント(Antigravity CLI など)との統合を容易にします。

Cloud Shell ターミナルを起動する

  1. 新しいブラウザ ウィンドウで https://console.cloud.google.com/ を使用して Google Cloud コンソールを開きます。最高のユーザー エクスペリエンスを得るには、Chrome を使用することをおすすめします。
  2. Google Cloud で Google アカウントにログインします。
  3. Google Cloud コンソールの上部にある [Cloud Shell をアクティブにする ]Cloud Shell をアクティブにするアイコン をクリックします。
    表示されたら、次のウィンドウをクリックします。
    • Cloud Shell 情報ウィンドウで操作を進めます。
    • Cloud Shell が認証情報を使用して Google Cloud API を呼び出すことを承認します。

Google Cloud プロジェクトを選択する

Cloud コンソールを開くと、認証が行われ、通常は作業用のプロジェクトが選択されます。プロジェクト ID は、小文字、数字、ダッシュ記号で構成される 6 ~ 30 文字のシーケンスです(例: qwiklabs-gcp-04-3075fc9fd77f)。Cloud Shell ターミナルは、選択したプロジェクトで gcloud CLI を構成します。出力は次のようになります。

Your Cloud Platform project in this session is set to qwiklabs-gcp-04-3075fc9fd77f

これは、gcloud への以降のコマンドでプロジェクト ID qwiklabs-gcp-04-3075fc9fd77f が使用されることを意味します。

プロジェクト ID を環境変数 PROJECT_ID として設定します。次のコマンドを使用すると、すべてのプロジェクトのリストを表示できます。

gcloud projects list
  • gcloud で構成されているものとは異なるプロジェクト ID を使用する場合は、your-project-id を置き換えてコマンドを実行します。
    export PROJECT_ID="your-project-id"
    
    例:
    export PROJECT_ID="qwiklabs-gcp-04-3075fc9fd77f"
    
  • 選択したプロジェクト ID を使用する場合は、次のコマンドを実行します。
    export PROJECT_ID=$(gcloud config get project)
    

3. 新しい API キーを制限する

以前は、完全に無制限の API キーを作成できました。無制限のキーは、キーが作成されたプロジェクトで有効になっている任意の Google API を呼び出すために使用できました。 Google Cloud コンソールでは、無制限のキーを作成できませんが、gcloud CLI または API の直接呼び出しを使用すると作成できます。

次の手順では、特定の API と指定したウェブサイトでのみ使用できる制限付き API キーを作成する方法について説明します。

  1. Google Map Geolocation API でのみ使用できる新しい API キーを作成するには、シェル ターミナルで次のコマンドを実行します。
    gcloud services api-keys create --key-id=restricted-api-key \
      --display-name="restricted api key" \
      --api-target=service=geolocation.googleapis.com \
      --project=${PROJECT_ID}
    
    このコマンドは、Google Map Geolocation サービスの呼び出しにのみ使用できる新しい API キーを作成します。
  2. アプリケーションの制限を追加して、キーのセキュリティを強化します。キーの使用をウェブサイト example.com 内のすべてのパスにのみ制限します。次のコマンドを実行して、アプリケーションの制限をキーに追加します。
    gcloud services api-keys update restricted-api-key \
      --location=global \
      --allowed-referrers="example.com/*" \
      --project=${PROJECT_ID}
    
    特定のウェブサイトでのキーの使用を許可する代わりに、--allowed-application を使用して許可された Android アプリケーションを定義するか、allowed-ips を使用して許可された IP アドレスを定義できます。 すべてのオプションについては、完全なドキュメントをご覧ください。

クリーンアップ

作成した API キーは、使用する予定がない限り削除してください。

gcloud services api-keys delete --key-id=restricted-api-key \
  --project=${PROJECT_ID}

4. API キーをカタログ化する

このステップでは、gcloud CLI を使用して API キーのインベントリを取得します。結果のリストには、アクセス権のあるすべての有効な(削除されていない)API キーが表示されます。

  1. 次のコマンドを実行して、すべてのキー名、ID、作成日を表示します。
    gcloud services api-keys list --project=${PROJECT_ID} \
      --format='value(displayName,name.basename(),createTime.date())'
    
    出力には、キーの人間が読める名前、キー ID、キーが作成された日付が表示されます。次のようになります。
    api key 1	api-key-1	2024-05-10T07:53:24
    api key 2	api-key-2	2025-06-12T14:47:57
    
  2. キー ID のいずれかを選択し、次のコマンドを貼り付けて、キーに制限があるかどうかを確認します。your-key-id は、選択したキー ID の値に置き換えます。
    gcloud services api-keys describe "your-key-id" --project=${PROJECT_ID}
    

出力(YAML)には、restrictions の下に制限のリストが含まれます。

createTime: '2024-05-10T07:53:24.986528Z'
displayName: api key 1
etag: W/"u1WuY41K2tPKUZd7cfLoKg=="
name: projects/123456789012/locations/global/keys/api-key-1
restrictions:
  apiTargets:
  - service: geolocation.googleapis.com
  browserKeyRestrictions:
    allowedReferrers:
    - https://example.com/*
uid: 1a2b3c4d-1234-abcd-1234-a1b2c3d4e5f6
updateTime: '2024-05-10T07:53:24.071228Z'

キーが更新されていない場合、createTime フィールドと updateTime フィールドのタイムスタンプは同じになります。

  1. すべてのプロジェクトをウォークスルーし、制限のないすべての API キーを出力するスクリプトをダウンロードして実行します。
    curl -fsSL -o unrestricted_api_keys.sh \
      "https://github.com/GoogleCloudPlatform/devrel-demos/blob/main/security/api-key-audit/unrestricted_api_keys.sh"
    chmod +x unrestricted_api_keys.sh
    ./unrestricted_api_keys.sh
    
    スクリプトを実行すると、次のような出力が表示されます。
    DISPLAY NAME    KEY ID    PROJECT ID    CREATION DATE
    Key 1    1a2b3c4d-1234-abcd-1234-a1b2c3d4e5f6    my-project-1    2024-05-10T07:53:24.071228Z
    
    この Codelab で使用されているすべてのスクリプトは、GitHub の devrel-demos リポジトリのSecurity フォルダにあります。

5. API キーの使用状況を検出する

このステップでは、API キーを使用して呼び出された API を特定するのに役立つ Google Cloud 指標をクエリします。この情報を使用して、キーの現在の使用状況を確認し、推測するのではなく実際の情報に基づいてキーに API 制限を適用できます。

  1. 前のステップで使用したキー ID を使用するか、別のキー ID を選択します。次のコマンドで、your-key-id を選択したキー ID に置き換えます。
    export KEY_UID=$(
       gcloud services api-keys describe "your-key-id" \
       --format='value(uid)' \
       --project=${PROJECT_ID})
    
  2. 検索を設定して、1 年間の使用履歴を遡ります。より長い期間または短い期間を検索する場合は、365(日数)を別の正の数に置き換えます。
    export DAYS=365
    
  3. アプリケーションのデフォルト認証情報(ADC)を更新して、Cloud Monitoring API を直接呼び出せるようにします。次のコマンドを実行し、ターミナルの指示に沿って操作します。
    gcloud auth application-default login
    
  4. 次のコマンドを実行して、サービス使用状況の指標データのリクエストを Cloud Monitoring API に送信します。
curl -s -G -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  --data-urlencode "filter=metric.type=\"serviceruntime.googleapis.com/api/request_count\" AND resource.labels.credential_id=\"apikey:${KEY_UID}\"" \
  --data-urlencode "interval.startTime=$(date -u -d "${DAYS} days ago" +%Y-%m-%dT%H:%M:%SZ)" \
  --data-urlencode "interval.endTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  "https://monitoring.googleapis.com/v3/projects/${PROJECT_ID}/timeSeries" \
  | jq -r '.timeSeries[]?.resource.labels.service' | sort -u

このコマンドは、選択した API キーの一意の ID と一致する credential_id ラベルを持つデータポイントについて、serviceruntime/api/request_count 組み込み指標をクエリします。次に、service ラベルの値を取得し、重複を排除しながら値を出力します。

API キーの強化

このステップでは、前のステップで収集した情報を使用して、使用状況の情報に基づいて API キーの制限構成を更新します。

前のステップで使用した API キーを使用します。必要に応じて、前のステップの手順を再度実行して、環境変数 PROJECT_IDKEY_UIDDAYS が設定されていることを確認します。

  1. 次のコマンドを実行して、API キーを使用して呼び出された Google API のリストを取得します。

SERVICES=$(curl -s -G -H "Authorization: Bearer $(gcloud auth application-default print-access-token)"
–data-urlencode "filter=metric.type="serviceruntime.googleapis.com/api/request_count" AND resource.labels.credential_id="apikey:${KEY_UID}""
–data-urlencode "interval.startTime=$(date -u -d "${DAYS} days ago" +%Y-%m-%dT%H:%M:%SZ)"
–data-urlencode "interval.endTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
"https://monitoring.googleapis.com/v3/projects/${PROJECT_ID}/timeSeries"
| jq -r ‘.timeSeries[]?.resource.labels.service' | sort -u)

1. Build the list of arguments to restrict the API usage for the API key based
on the retrieved list.

```shell
API_TARGET_ARGS=()
for SERVICE in $SERVICES; do
  API_TARGET_ARGS+=("--api-target=service=${SERVICE}")
done
  1. 空でないリストの制限付き API のリストを置き換えます。
    if [ ${#API_TARGET_ARGS[@]} -gt 0 ]; then
        gcloud services api-keys update "projects/${PROJECT_ID}/locations/global/keys/${KEY_UID}" \
        ${API_TARGET_ARGS}
    fi
    

6. 異常な使用状況の検出を定義する

前のステップでは、API キーの探索と強化の方法について説明しました。このステップでは、Monitoring アラートを使用して、キーの使用量の予期しないピークに対するレスポンスを自動化する方法について説明します。

次の手順では、API キーを使用する API 呼び出しのレートが過去 5 分間で 10% 以上増加した場合に発生するアラートを作成します。アラートは、Cloud Build スクリプトをトリガーするように構成されています。このスクリプトは、さらなる使用を防ぐために API キーを削除します。キーは次の 30 日以内に復元できます。キーの削除を取り消す方法については、ドキュメントをご覧ください。

この手順では、前のステップで使用した変数 PROJECT_IDKEY_UID を再利用します。別のキーやプロジェクトを選択する場合は、セットアップと API キーの使用状況を検出するの手順で説明されているように、これらの変数に新しい値を設定します。

  1. 次のスクリプトを実行して、アラート ポリシー ファイルを作成します。
    cat <<EOF > alert_policy.json
    {
      "displayName": "Credential API Request Count Increase Alert (Project: ${PROJECT_ID})",
      "combiner": "OR",
      "conditions": [
        {
          "displayName": "API Request Count Increase > 10% in 5m with Min Volume",
          "conditionPrometheusQueryLanguage": {
            "query": "(sum(increase(serviceruntime_googleapis_com:api_request_count{metric_label_credential_id=\\"apikey:${KEY_UID}\\"}[5m])) / (sum(increase(serviceruntime_googleapis_com:api_request_count{metric_label_credential_id=\\"apikey:${KEY_UID}\\"}[5m] offset 5m)) or on() vector(1)) > 1.10) and (sum(increase(serviceruntime_googleapis_com:api_request_count{metric_label_credential_id=\\"apikey:${KEY_UID}\\"}[5m])) > 50)",
            "duration": "0s",
            "evaluationInterval": "60s"
          }
        }
      ],
      "enabled": true
    }
    EOF
    
    アラート ポリシーは、次の PromQL フィルタを使用してアラートをトリガーします。
     (sum(
       increase(
         serviceruntime_googleapis_com:api_request_count{metric_label_credential_id="API_KEY_UID"}[5m])
     ) /
     (sum(
       increase(
         serviceruntime_googleapis_com:api_request_count{metric_label_credential_id="API_KEY_UID"}[5m] offset 5m)
     ) or on() vector(1)) > 1.10)
    and
     (sum(
       increase(
         serviceruntime_googleapis_com:api_request_count{metric_label_credential_id=\"YOUR_CREDENTIAL_ID_HERE\"}[5m])) > 50)
    
    増加率を計算し、前のウィンドウと比較します。10% を超える場合にのみアラートをトリガーします。呼び出しの合計数が無視できる場合にアラートがトリガーされないように、ウィンドウで 50 件を超える API 呼び出しがある場合にトリガーされるように条件を設定します。前の 5 分間のレートが 0 の場合に NaN(ゼロによる削除)計算を回避するため、前のウィンドウのレートが 0 の場合は分母を 1 に置き換えます。ウィンドウの長さ(5m)、最小しきい値(50)、10% の増加しきい値(1.10)など、アラート パラメータを変更できます。追加のポリシー パラメータは、条件に達したらアラートを発生させること(duration)、および 60 秒ごとに条件をプローブすること(evaluationInterval)を定義します。
  2. 次のコマンドを実行して、アラート通知の投稿に使用する Pub/Sub トピックを作成します。
    gcloud pubsub topics create api-key-alert-notifications --project=$PROJECT_ID
    
  3. 次のコマンドを実行して、Pub/Sub を使用するアラートの通知チャンネルを作成します。
    CHANNEL_NAME=$(gcloud beta monitoring channels create \
      --display-name="Pub/Sub Alert Channel" \
      --type="pubsub" \
      --channel-labels="topic=projects/$PROJECT_ID/topics/api-key-alert-notifications" \
      --format='value(name)' \
      --project=$PROJECT_ID)
    
    クリーンアップ ステップで CHANNEL_NAME 環境変数を使用します。
  4. 次のコマンドを実行して、新しいモニタリング アラートを作成します。
    gcloud monitoring policies create --policy-from-file=alert_policy.json \
      --project=$PROJECT_ID
    
  5. 次のコマンドを実行して、プロジェクト内の API キーを削除する権限を Cloud Build サービスに付与します。
    PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
    gcloud projects add-iam-policy-binding $PROJECT_ID \
      --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
      --role="roles/apikeys.admin"
    
    apikeys.admin ロールを制限して、API キーの特定のインスタンスのみを操作できます。詳細については、IAM Conditions をご覧ください。
  6. 次のスクリプトを実行して、API キーを削除する Cloud Build トリガーを作成します。
    cat <<EOF > trigger_config.yaml
    name: "delete-compromised-api-key"
    description: "Triggered by Pub/Sub alert to automatically delete the leaking API Key"
    pubsubConfig:
      topic: "projects/${PROJECT_ID}/topics/api-key-alert-notifications"
    build:
      steps:
      - name: "gcr.io/google.com/cloudsdktool/cloud-sdk:slim"
        args:
        - "gcloud"
        - "services"
        - "api-keys"
        - "delete"
        - "${KEY_UID}"
        - "--quiet"
    EOF
    
  7. 次のコマンドを実行して、新しいモニタリング アラート トリガーを作成します。
    gcloud builds triggers create pubsub \
      --trigger-config=trigger_config.yaml \
      --project=$PROJECT_ID
    

アラート ポリシーと Cloud Build トリガー構成ファイルを削除できます。

rm alert_policy.json trigger_config.yaml

または、Terraform プランを使用してこの自動化を設定することもできます。Google Cloud DevRel リポジトリabnormal-usage-detection フォルダから Terraform ファイルをダウンロードします。このプランでは、プロジェクト ID と API キー UID を入力パラメータとして受け取り、このステップで説明したリソースと構成を設定します。

7. クリーンアップ

Google Cloud アカウントに予期しない料金が発生しないように、この演習で作成した Pub/Sub トピック、Cloud Build ビルドトリガー、アラート ポリシーを削除してください。

次のコマンドを実行して、作成したすべてのリソースを削除します。

gcloud builds triggers delete delete-compromised-api-key \
  --project=$PROJECT_ID
gcloud beta monitoring channels delete $CHANNEL_NAME \
  --project=$PROJECT_ID \
  --quiet
gcloud pubsub topics delete api-key-alert-notifications \
  --project=$PROJECT_ID
gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
  --role="roles/apikeys.admin"

8. まとめ

この Codelab では、Google Cloud API キーの堅牢なエンドツーエンドのセキュリティと自動化フレームワークを実装しました。

  1. デフォルト構成の強化: 必要な API と信頼できるプラットフォーム(特定の HTTP リファラーなど)にのみアクセスを制限するように、API キーを作成して制限しました。
  2. キー インベントリの監査: プロジェクト環境をスキャンして、セキュリティ リスクがすぐに発生する無制限のキーを検出して隔離しました。
  3. 使用状況データの分析: Cloud Monitoring 指標データをプログラムでクエリして、過去のキーの使用状況をプロファイリングし、検証済みの使用状況に基づいてキーを制限できるようにしました。
  4. 脅威の軽減の自動化: Cloud Monitoring アラート ポリシーを Pub/Sub トピックと Cloud Build トリガーに接続して、リアクティブな「サーキット ブレーカー」を確立し、トラフィックが異常に急増したときに侵害されたキーを自動的に削除できるようにしました。

次のステップ

  • すべての API キーに制限を適用する: このラボで学習した内容を使用して、部分的に制限されているか無制限の API キーをすべて検出し、API とクライアントの制限を適用します。
  • API キーに「回路ブレーカー」を設定する: 使用量が急増した場合にキーを自動的に削除するように設定して、API キーを予期しない使用からさらに保護します。ラボで説明した gcloud コマンドまたは Terraform を使用します。IAM Conditions を使用して権限を強化することを検討してください。
  • モニタリング アラートの詳細を確認する: Google Cloud Monitoring サービスを使用してアラートを設定する方法について学習します。
  • Google Cloud で利用可能なアクセス制御の詳細を確認する: アクセス境界ポリシーアクセス変更の伝播を確認します。