この文書では、値を削除するだけでなく、見つかったシークレットの種類とサービスの運用方法に応じて実施できる対処方法を説明します。
1. 最初に確認すること
シークレットが見つかったら、まず次の点を確認してください。
| 確認項目 | 確認する内容 | 次の対応 |
|---|---|---|
| 実際のシークレットか | テスト用のダミー値か、本番の認証情報か。 | 本番の値なら、直ちに失効手続きを始めます。 |
| 露出範囲 | ローカルブランチだけにあるか、リモートリポジトリにpushされたか。 | リモートに反映されていれば、認証情報のローテーションと履歴の整理が必要です。 |
| シークレットの種類 | DBパスワード、APIキー、JWT署名鍵、SSH鍵、証明書の秘密鍵などのどれか。 | 種類に応じて失効・再発行の手続きを選びます。 |
| 使用場所 | アプリケーションコード、CI/CD、Kubernetes、Dockerイメージ、設定ファイルのどこで使うか。 | 環境に応じた移行方法を選びます。 |
| 移行先 | 環境変数、Vault、AWS Secrets Manager、Kubernetes Secretなど、利用できる仕組みがあるか。 | 運用環境に合う保存先を決めます。 |
2. 共通の対応手順
露出した認証情報は、まず失効または無効化し、新しい値に置き換えてください。コードやGit履歴の整理が終わるまで待たないでください。
2.1 コードと履歴からシークレットを削除する
- コードからシークレットの値を直ちに削除してください。
- リモートリポジトリに反映されていた場合は、現在のファイルだけでなくGit履歴からも削除してください。
- 共同作業中のリポジトリでは、force-pushの影響範囲を周知し、必要に応じて再クローンを案内してください。
# git-filter-repoの例
git filter-repo --replace-text passwords.txt
2.2 露出したシークレットを失効・再発行する
- 露出したシークレットは漏えいしたものとして扱ってください。
- 値を削除するだけでなく、既存のシークレットを直ちに失効または無効化してください。
- 元の権限をそのまま引き継ぐのではなく、必要最小限の権限で新しい値を発行してください。
2.3 悪用の有無を調べる
- シークレットの使用履歴、ログイン履歴、API呼び出しログ、クラウドの監査ログを確認してください。
- 外部に露出した可能性が高ければ、短期間でも使用された形跡を調べてください。
3. コードにシークレットがある場合
3.1 アプリケーションのソースコード
対処の原則
- コードに値を直接埋め込まず、実行時に注入する形に変更してください。
- ローカル開発では、
.envまたは開発用のシークレットストアを使ってください。 - 本番では、環境変数だけを管理する方法よりも、シークレット管理サービスやオーケストレーターの注入機能を優先してください。
例:ハードコードした値を環境変数に置き換える
// 脆弱なコード
const client = createClient({
apiKey: "sk-prod-123456",
});
// 改善したコード
if (!process.env.API_KEY) {
throw new Error("API_KEY is not configured");
}
const client = createClient({
apiKey: process.env.API_KEY,
});
担当者への案内例
- 「コードからシークレットの値を削除し、環境変数またはシークレット管理サービスから注入するように変更してください。」
- 「シークレットを必要とする設定コードは残し、実際の値はリポジトリではなくデプロイ環境から供給してください。」
3.2 設定ファイル(application.yml、config.json、コミット済みの.envなど)
対処の原則
- Gitで管理する設定ファイルに、シークレットの実際の値を保存しないでください。
- 設定ファイルにはシークレット名や参照だけを残し、値は外部から注入してください。
.envを使う場合も、実ファイルがコミットされないように.gitignoreとテンプレートファイルを管理してください。- 環境変数への置き換えが難しい場合はファイル形式を維持し、安全な供給元から実行時に実ファイルを生成またはマウントしてください。
例
# 脆弱な設定
spring:
datasource:
username: app_user
password: super-secret-password
# 改善した設定
spring:
datasource:
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
担当者への案内例
- 「設定ファイルに実際のパスワードを保存せず、
${ENV_NAME}のような参照に変更してください。」 - 「リポジトリには
.env.exampleだけを置き、実際の.envはコミットしないでください。」 - 「
config.yamlが必要なサービスでは、リポジトリにはサンプルだけを置き、実ファイルを実行時にマウントするか、デプロイ時に安全に生成してください。」
4. デプロイ・運用環境別の推奨対応
4.1 Kubernetesを使うサービス
Kubernetesを使う場合は、コードから値を削除し、Kubernetes Secretまたは外部シークレット連携に移行することを明示してください。
推奨方法
- シークレットの値をコードやConfigMapに保存しないでください。
- Kubernetes Secret、External Secrets Operator、Sealed Secrets、Vault連携から、運用方針に合う方法を選んでください。
- Podには
env.valueFrom.secretKeyRefまたはSecretボリュームのマウントで注入してください。
例
次の抜粋はシークレットの注入部分だけを示しています。DeploymentのセレクターやPodラベルなど、残りの設定は別途用意してください。${REAL_SECRET_VALUE} はデプロイツールが安全に供給する値のプレースホルダーであり、Kubernetesが環境変数の値に自動置換するものではありません。
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
stringData:
API_KEY: ${REAL_SECRET_VALUE}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
template:
spec:
containers:
- name: app
image: my-app:latest
env:
- name: API_KEY
valueFrom:
secretKeyRef:
name: app-secret
key: API_KEY
担当者への案内例
- 「ハードコードしたシークレットを削除し、Kubernetes SecretまたはExternalSecretに移行して、
secretKeyRefで注入してください。」 - 「ConfigMapにシークレットを入れず、Secretリソースまたは外部シークレットストアとの連携を使ってください。」
4.2 Vaultやクラウドのシークレット管理サービスを使う場合
組織でVault、AWS Secrets Manager、Google Secret Manager、Azure Key Vaultを利用している場合は、対処の案内でもそのサービスを具体的に示してください。
推奨方法
- コードにはシークレットのパスまたは参照名だけを残してください。
- アプリケーションの起動時に、SDK、サイドカー、CSIドライバー、initコンテナーなど、組織の標準の方法でシークレットを取得してください。
- ローテーション方針とアクセス権限を併せて確認してください。
担当者への案内例
- 「コードに保存したシークレットを削除し、新たに発行した値をVaultやシークレット管理サービスに登録して、実行時に取得するように変更してください。」
- 「露出した値を再登録せず、新しい値にローテーションし、アクセス権限も必要最小限にしてください。」
4.3 CI/CDで使うシークレット
コードに埋め込まれた値は、GitHub Actions、GitLab CI、Jenkinsのパイプラインでも使われることがあります。その場合、アプリケーションコードの修正だけでは不十分です。
推奨方法
- リポジトリのファイルやスクリプトに値を直接埋め込まないでください。
- CI/CDプラットフォームのシークレット保存機能を使ってください。
- ビルドログに値が出力されないよう、マスキングを確認してください。
担当者への案内例
- 「デプロイスクリプトに直接記載したトークンを削除し、GitHub Actions Secrets、GitLab CI Variables、Jenkins Credentialsを使ってください。」
- 「パイプラインのログにシークレットの値が出力されないことも確認してください。」
4.4 Dockerイメージのビルド時に露出したシークレット
Dockerfileの ENV、ARG、イメージレイヤー、ビルドスクリプトにシークレットが残る場合は、ビルド工程への対処も必要です。
推奨方法
- Dockerfileにシークレットの実際の値を直接記載しないでください。
- BuildKitのシークレットマウントまたは実行時の注入を使ってください。
- イメージを再ビルドし、既存のレジストリタグの使用を終了してください。
担当者への案内例
- 「Dockerfileの
ENV、ARGに保存したシークレットを削除し、ビルド時のシークレットマウントまたは実行時の注入に変更してください。」 - 「シークレットを含む古いイメージタグの使用を停止し、新しいイメージに置き換えてください。」
5. シークレットの種類別の追加対応
必要な対処はシークレットの種類によって異なります。種類が分かる場合は、それに応じた案内をしてください。
| シークレットの種類 | 追加対応 |
|---|---|
| DBアカウント・パスワード | パスワードの変更、接続文字列の更新、DBアクセスログの確認。 |
| AWS/GCP/AzureのAPIキー | キーの失効・新規発行、IAM権限の最小化、監査ログの確認。 |
| JWT/HMAC署名鍵 | 鍵のローテーションと、既存トークンの無効化または再ログインの検討。 |
| SSH秘密鍵 | 鍵の失効、authorized_keys の該当エントリ削除、サーバーアクセスログの確認。 |
| OAuthクライアントシークレット | シークレットの再発行と連携アプリケーションの設定更新。 |
| 証明書の秘密鍵 | 証明書の再発行が必要かの判断と、関連サービス全体の確認。 |
6. 検出結果メッセージの例
担当者がすぐに対処を理解できるよう、次の情報を含めてください。
- 見つかった値の種類
- 例:AWSアクセスキー、DBパスワード、JWTシークレットと推定される値。
- 保存されている場所
- 例:アプリケーションコード、設定ファイル、Dockerfile、GitHub Actionsワークフロー。
- 直ちに行う対応
- 例:値の失効、ログの確認、既存トークンの無効化。
- コードの修正方法
- 例:環境変数の参照、Kubernetes Secretの注入、Vaultからの取得。
- サービスに適した保存先
- 例:Kubernetes Secret、AWS Secrets Manager、GitHub Actions Secrets。
例1:コード内のDBパスワード
本番DBのパスワードがコードまたは設定ファイルに保存されているようです。直ちにパスワードを変更し、アプリケーションには
${DB_PASSWORD}のような環境変数の参照だけを残してください。KubernetesではSecretとsecretKeyRefで注入し、VMやECSを使うサービスではシークレット管理サービスまたはデプロイ環境の環境変数から供給してください。
例2:GitHub Actionsのトークン
CI/CDトークンがリポジトリのファイルに含まれています。直ちに失効させ、新しい値をGitHub Actions Secretsまたは利用中のCI/CD認証情報ストアに登録してください。ワークフローファイルには
${{ secrets.YOUR_TOKEN }}のような参照だけを残し、過去の実行ログに値が露出していないかも確認してください。
例3:JWT署名鍵
JWT署名鍵がコードにハードコードされています。コードから削除し、シークレットストアから実行時に注入するように変更してください。露出した鍵はローテーションし、必要に応じて既存トークンの無効化や全ユーザーの再ログインを検討してください。
参考資料
- GitHub: Removing sensitive data from a repository
- GitHub: About secret scanning
- AWS: Best practices for managing AWS access keys
- Google Cloud: Secret Manager best practices
- Kubernetes: Secret