はじめに
API キーやパスワードをコードに直書きしていませんか?
# NG:絶対にやってはいけない
API_KEY = "sk-1234abcd..."
DB_PASSWORD = "P@ssw0rd"
これは Git にコミットした瞬間に情報漏えいのリスクが生まれます。
環境変数に逃がしても、Cloud Run の設定画面やログに平文で表示されることがあります。
Google Cloud には Secret Manager という専用のシークレット管理サービスがあります。
本記事では Secret Manager の基本から Cloud Run との連携、IAM による最小権限設定まで、実践的な使い方を解説します。
Secret Manager とは
Secret Manager は API キー、パスワード、証明書などの機密情報を安全に保存、管理するマネージドサービスです。
主な特徴は以下のとおりです。
| 特徴 | 内容 |
|---|---|
| 暗号化 | 保存時、転送時ともに自動で暗号化 |
| バージョン管理 | シークレットの値を更新しても旧バージョンを保持 |
| IAM 連携 | サービスアカウント単位で細かくアクセス制御 |
| 監査ログ | 誰がいつシークレットにアクセスしたかを記録 |
| Cloud Run 連携 | 環境変数やボリュームマウントとして自動注入 |
料金
無料枠が手厚く、個人開発や小規模利用であればほぼ無料で使えます。
| 項目 | 無料枠 | 超過分 |
|---|---|---|
| アクティブなシークレットバージョン | 6 バージョン | $0.06 / バージョン / 月 |
| アクセス操作 | 10,000 回 / 月 | $0.03 / 10,000 回 |
基本概念:シークレットとバージョン
Secret Manager には「シークレット」と「バージョン」という 2 つの概念があります。
シークレット(my-api-key)
├── バージョン 1:最初の値(無効化済み)
├── バージョン 2:更新後の値(無効化済み)
└── バージョン 3:現在の値(有効)← latest
- シークレット:名前のついた器。設定(ローテーションポリシーなど)を持つ
-
バージョン:実際の値。追加するたびに番号が増える。
latestで最新版を参照できる
値を更新しても古いバージョンが残るため、ロールバックが容易です。
セットアップ
API を有効化する
gcloud services enable secretmanager.googleapis.com
Python ライブラリをインストールする
pip install google-cloud-secret-manager
シークレットを作成する
コンソールから作成する
Cloud Console の「Secret Manager」を開き、「シークレットを作成」ボタンをクリックします。
| 入力項目 | 設定内容 |
|---|---|
| 名前 |
my-api-key(英数字とハイフンのみ) |
| シークレットの値 | 保存したい API キーやパスワード |
| リージョン | 「自動(グローバル)」でOK。データ居住要件がある場合は指定 |
gcloud から作成する
# シークレットを作成(空の器を作る)
gcloud secrets create my-api-key \
--replication-policy="automatic"
# 値を追加(バージョン 1 が作られる)
echo -n "sk-1234abcd..." | gcloud secrets versions add my-api-key --data-file=-
echo -n の -n は末尾の改行を除去するため必須です。
改行が含まれるとトークンが壊れます。
ファイルから読み込む場合は --data-file にパスを指定します。
gcloud secrets versions add my-api-key --data-file=./api_key.txt
値を確認する
gcloud secrets versions access latest --secret="my-api-key"
Python SDK でシークレットにアクセスする
基本的な読み取り
from google.cloud import secretmanager
def get_secret(project_id: str, secret_id: str, version: str = "latest") -> str:
client = secretmanager.SecretManagerServiceClient()
name = f"projects/{project_id}/secrets/{secret_id}/versions/{version}"
response = client.access_secret_version(request={"name": name})
return response.payload.data.decode("UTF-8")
# 使い方
api_key = get_secret("my-project-id", "my-api-key")
アプリ起動時に一括で読み込む
毎回 Secret Manager を呼ぶとレイテンシが増えます。
アプリ起動時に必要なシークレットをまとめて読み込んでキャッシュするのが定番パターンです。
import os
from google.cloud import secretmanager
def load_secrets(project_id: str) -> dict:
client = secretmanager.SecretManagerServiceClient()
secret_ids = ["db-password", "api-key", "jwt-secret"]
secrets = {}
for secret_id in secret_ids:
name = f"projects/{project_id}/secrets/{secret_id}/versions/latest"
response = client.access_secret_version(request={"name": name})
secrets[secret_id] = response.payload.data.decode("UTF-8")
return secrets
# アプリ起動時に一度だけ呼ぶ
PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
secrets = load_secrets(PROJECT_ID)
db_password = secrets["db-password"]
api_key = secrets["api-key"]
Cloud Run との連携
Cloud Run では Secret Manager のシークレットを環境変数またはボリュームマウントとして自動注入できます。
コード内で Secret Manager SDK を呼ぶ必要がなくなります。
方法 A:環境変数として注入する
gcloud run deploy my-service \
--image gcr.io/my-project/my-image \
--set-secrets="API_KEY=my-api-key:latest,DB_PASS=db-password:latest"
アプリ側は通常の環境変数として読めます。
import os
api_key = os.environ["API_KEY"]
db_pass = os.environ["DB_PASS"]
環境変数への注入はデプロイ時に値が解決される点に注意してください。
シークレットを更新しても、再デプロイするまで新しい値は反映されません。
方法 B:ボリュームマウントとして注入する(推奨)
gcloud run deploy my-service \
--image gcr.io/my-project/my-image \
--set-secrets="/secrets/api-key=my-api-key:latest"
アプリ側はファイルとして読みます。
with open("/secrets/api-key") as f:
api_key = f.read().strip()
ボリュームマウントの利点は、シークレットを更新するとファイルの内容が自動で更新されることです(再デプロイ不要)。
ローテーションを頻繁に行うシークレットに向いています。
コンソールから設定する場合
Cloud Run のデプロイ画面の「変数とシークレット」タブから GUI で設定できます。
環境変数の「シークレットを参照」ボタンを使えば、Secret Manager から選ぶだけです。
IAM でアクセスを最小化する
Secret Manager のシークレットには IAM でアクセス制御をかけます。
Cloud Run のサービスアカウントに secretAccessor ロールを付与するのが基本パターンです。
ロールの種類
| ロール | できること |
|---|---|
roles/secretmanager.secretAccessor |
シークレットの値を読む(最小権限) |
roles/secretmanager.viewer |
メタデータを見る(値は読めない) |
roles/secretmanager.secretVersionManager |
バージョンの追加、無効化 |
roles/secretmanager.admin |
すべての操作 |
アプリが必要とするのは値を読むだけなので、secretAccessor のみ付与します。
特定のシークレットにのみアクセスさせる
プロジェクト全体ではなく、特定のシークレットだけにアクセスを許可できます。
# Cloud Run のサービスアカウントを確認
gcloud run services describe my-service \
--format="value(spec.template.spec.serviceAccountName)"
# 特定のシークレットのみ secretAccessor を付与
gcloud secrets add-iam-policy-binding my-api-key \
--member="serviceAccount:my-sa@my-project.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"
こうすることで my-sa は my-api-key だけ読めて、他のシークレットには触れません。
バージョン管理
シークレットの値を更新する
echo -n "new-secret-value" | gcloud secrets versions add my-api-key --data-file=-
新しいバージョンが追加され、latest が新しいバージョンを指すようになります。
古いバージョンは自動的には削除されません。
バージョンを確認する
gcloud secrets versions list my-api-key
NAME: 2
STATE: enabled
CREATED: 2026-06-18T04:40:45
DESTROYED: -
NAME: 1
STATE: enabled
CREATED: 2026-06-18T04:30:34
DESTROYED: -
無効化(disabled)されたバージョンは読めなくなりますが、課金対象のままです。
Secret Manager では Enabled と Disabled のどちらの状態も「アクティブなバージョン」として請求されます。
コストを削減するには削除(destroy)が必要です。
| 操作 | 値は消えるか | 課金は止まるか | 用途 |
|---|---|---|---|
| 無効化(disable) | 残る | 止まらない | 一時的にアクセスを遮断したいとき |
| 削除(destroy) | 消える(復元不可) | 止まる | コスト削減、不要バージョンの整理 |
# 無効化(値は残るが読めなくなる。課金は継続)
gcloud secrets versions disable 1 --secret="my-api-key"
# 削除(値が完全に消える・取り消し不可。課金も止まる)
gcloud secrets versions destroy 1 --secret="my-api-key"
ベストプラクティス
1. 名前付けルールを統一する
シークレットが増えると管理が難しくなります。
命名規則を決めておきましょう。
{環境}-{サービス名}-{用途}
例:
prod-payment-api-key
dev-notification-smtp-password
staging-db-password
2. バージョンを固定してデプロイする
latest は常に最新版を指すため、意図せず新しい値が使われる場合があります。
本番環境ではバージョン番号を固定してデプロイの再現性を高めます。
# NG:本番では latest を使わない
--set-secrets="API_KEY=my-api-key:latest"
# OK:バージョン番号を固定
--set-secrets="API_KEY=my-api-key:3"
3. シークレットをログに出力しない
# NG:ログにシークレットが出る
import logging
logging.info(f"API key: {api_key}")
# OK:マスクして記録する
logging.info("API key loaded: ****")
4. ローテーションを自動化する
重要なシークレット(データベースパスワードなど)は定期的にローテーションします。
Secret Manager の「ローテーション通知」と Cloud Functions を組み合わせると自動化できます。
1. Secret Manager が Pub/Sub に通知
2. Cloud Functions がトリガー
3. 新しいパスワードを生成してデータベースを更新
4. 新しい値を Secret Manager に登録
5. 古いバージョンを無効化
まとめ
Secret Manager の実践的なポイントは 4 つです。
-
作成:
gcloud secrets createでシークレットを作り、versions addで値を追加 - アクセス:Python SDK または Cloud Run の環境変数・ボリュームマウントで読み込む
-
IAM:
secretAccessorを特定のシークレット単位で付与して最小権限を徹底 - 運用:使わないバージョンを削除してコストを管理。本番ではバージョン番号を固定
環境変数への直書きや .env ファイルのコミットは今日から卒業して、Secret Manager で安全に管理しましょう。

