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 APIs にアクセスできます。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 の位置情報 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 マップのジオロケーション サービスの呼び出しにのみ使用できる新しい 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_ID、KEY_UID、DAYS が設定されていることを確認します。

  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 キーを探索して強化する方法について説明しました。このステップでは、モニタリング アラートを使用して、鍵の使用量の予期しないピークに対するレスポンスを自動化する方法について説明します。

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

この手順では、前の手順で使用した変数 PROJECT_ID と KEY_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% を超える場合にのみアラートをトリガーします。呼び出しの合計数が無視できる場合にアラートがトリガーされないように、ウィンドウ内の API 呼び出し数が 50 を超える場合にトリガーされるように条件を設定します。前の 5 分間のレートが 0 の場合に NaN(ゼロによる削除)計算を回避するため、前のウィンドウのレートがゼロの場合は、分母を 1 に置き換えます。ウィンドウ長(5m)、最小しきい値(50)、10% 増加しきい値(1.10)などのアラート パラメータを変更できます。追加のポリシー パラメータは、条件が満たされたらアラートをトリガーすること(duration)、条件を 60 秒ごとにプローブすること(evaluationInterval)を定義します。
  2. 次のコマンドを実行して、アラート通知の投稿に使用する PubSub トピックを作成します。
    gcloud pubsub topics create api-key-alert-notifications --project=$PROJECT_ID
    
  3. 次のコマンドを実行して、PubSub を使用するアラートの通知チャンネルを作成します。
    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 条件をご覧ください。
  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 キーに「回路ブレーカー」を設定する: 突然使用量が増加した場合にキーを自動的に削除するように設定することで、API キーを予期しない使用からさらに保護します。ラボで示されている gcloud コマンドまたは Terraform を使用します。IAM 条件を使用して権限を強化することを検討する
  • モニタリング アラートの詳細: Google Cloud Monitoring サービスを使用してアラートを設定する方法について説明します。
  • Google Cloud で利用可能なアクセス制御の詳細: アクセス境界ポリシーとアクセス変更の伝播を確認します。