🎧 Listen to this article: हिंदी · English · தமிழ் · తెలుగు · ಕನ್ನಡ · മലയാളം · ଓଡ଼ିଆ · 日本語 · 中文
🌍 Read this in your language: हिंदी · தமிழ் · తెలుగు · ಕನ್ನಡ · മലയാളം · ଓଡ଼ିଆ · 日本語 · 中文
ほとんどの認証情報の漏洩は劇的なものではありません。ハッカーも、侵害報告もありません。誰かが単にホームディレクトリのプレーンテキストファイルにアカウント全体のAPIキーを保存しており、ある日、バックアップ、画面共有、貼り付けられたコマンド、またはAIコーディングセッションが、決して行くべきではない場所にそれを静かに運んでしまうのです。
2026年8月の時点で、その最後のベクトルが状況を大きく変えたものです。今やほぼすべての開発者が、ファイルの一読やコマンドの実行を代行するAIコーディングアシスタントを実行しています。そのようなツールが読み取るすべてのもの、およびコマンドが出力するすべてのものは、毎回モデルプロバイダーに送信されるセッショントランスクリプトの一部になります。プレーンテキストのキーがセッション中に表示されたり、画面に復号されたり、エコーされたりした場合、それはあなたの制御の及ばないトランスクリプト内に存在することになります。これは仮説ではありません: まさにこれこそが、完璧に慎重なエンジニアが明らかに間違ったことを一切せずにキーを漏洩させる方法なのです。
この記事は、それを修正するための完全かつ汎用的なランブックです。実例としてCloudflare Global API Keyを使用していますが、このテクニックはあらゆる高権限の認証情報に適用できます。パート1では、以下のもの以外は使用しません: gpg および bash そして、あらゆるLinuxまたはmacOSマシンで動作します。パート2は、AIコーディングアシスタントを使用し、その上に強力な強制ガードを必要とする人のみを対象としています。
なぜアカウント全体のキーが特別な扱いを受けるべきなのか
Cloudflare Global API Keyはアカウント全体に及び、スコープが設定されていません。そのメールアドレスに紐付けられたすべてのアカウントの、すべてのゾーン、ワーカー、DNSレコードに触れることができます。これにより、2つの明確なリスクが生じます:
- 保存時。 ホームディレクトリ内のファイルにあるプレーンテキストのキーは、ファイルシステムに触れるあらゆるプロセス、スクリプト、またはバックアップから読み取られる可能性があります。それは1回の不注意な
chmod、1つの広範すぎるバックアップジョブ、1台の借りたノートパソコンによって漏洩する可能性があります。 - AIセッション中。 コーディングアシスタントが読み取ったもの、またはキーを出力したすべてのコマンドは、プロバイダーに送信されるトランスクリプトに記録されます。
cat ~/.cf,echo $CLOUDFLARE_API_KEY、またはgpg --decrypt画面に出力するものはすべて、即座にそれを漏洩させます。
修正には3つの部分があります: キーを 保存状態では暗号化しておく、復号するのは 出力しない短命のサブプロセス内でのみ、そして(AIアシスタントがループに含まれている場合は)追加する コードによって強制される強力なブロック、注意を忘れないことに頼るのではなく。
開始前の注意点:使用しているツールがGlobal API Keyの代わりにスコープ付きAPIトークンをサポートしている場合は、トークンを使用してください。トークンは個別に失効させることができ、割り当てられたスコープ外のアクセスはできないため、漏洩時の影響範囲はGlobal Keyの一部にすぎません。以下の手順はトークンにも同様に適用されます。単に、メールアドレスとキーのペアの代わりに、単一のトークン値を保存するだけです。
ステップ 1: 認証情報を取得し、厳格な権限でステージングする
プロバイダーのダッシュボードからキーを取得します。Cloudflareの場合、「My Profile(マイプロフィール)」から「API Tokens(APIトークン)」タブを開き、「Global API Key」の横にある「View(表示)」をクリックします。
プロジェクトディレクトリ内のステージングファイルに書き込み、最初の1バイトからロックダウンされた状態で作成します:
mkdir -p ~/vault
umask 077 # new files are created 600, never world-readable
printf '%s\n' "[email protected] REPLACE_WITH_GLOBAL_API_KEY main-account" > ~/vault/.cf
chmod 600 ~/vault/.cf
この umask 077 は重要です: これは、作成中に他のユーザーがプレーンテキストを短時間でも読み取れないことを保証します。これは後の chmod では元に戻すことができません。
ステップ 2: GPG対称AES-256で暗号化する
ここでは、パスフレーズベースの対称暗号化が適切な選択です。このファイルを復号する必要があるのは1人だけなので、公開鍵/秘密鍵のペアは利点がないのに複雑さを増すだけです。
gpg --symmetric --cipher-algo AES256 -o ~/vault/.cf.gpg ~/vault/.cf
GPGはパスフレーズの入力と確認を促します。強力で一意なものを選び、パスワードマネージャーに記録してください。忘れた場合の回復方法はないからです。この時点から、そのパスフレーズだけが、ファイルシステムへのアクセスとキーの間に立つ唯一のものになります。
ステップ 3: 何かを削除する前に暗号化されたコピーを確認する
暗号文が1バイトずつ正確に復号されることを証明するまでは、絶対にプレーンテキストを削除しないでください:
diff <(gpg --quiet --batch --decrypt ~/vault/.cf.gpg) ~/vault/.cf
出力がないということは、2つが同一であり、安全に進めることを意味します。何らかの出力があるということは、パスフレーズの間違い、暗号の間違い、ファイルの破損など、何かが間違っていることを意味するため、プレーンテキストをまだ削除してはいけません。
ステップ 4: プレーンテキストを安全に削除する
shred -u ~/vault/.cf
chmod 600 ~/vault/.cf.gpg
ls -la ~/vault/.cf* # only .cf.gpg should remain
shred はリンクを解除する前にバイトを上書きするため、これより強力です: rm。その限界については正直になる必要があります: SSD、コピーオンライトのファイルシステム、またはスナップショットやバックアップが取得されたことのあるファイルでは、上書きの保証は弱くなります。本当に漏洩した認証情報に対する唯一の確実な保証は、1つのコピーの削除ではなく、ローテーションです。
ステップ 5: パスフレーズのキャッシュを短くする(オプションだが推奨)
デフォルトでは gpg-agent 入力後10分以上パスフレーズをキャッシュします。その時間を短縮するには:
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
cat >> ~/.gnupg/gpg-agent.conf <<'EOF'
default-cache-ttl 60
max-cache-ttl 120
EOF
chmod 600 ~/.gnupg/gpg-agent.conf
gpg-connect-agent reloadagent /bye
これにより、キャッシュの上限は60〜120秒になります。これは、復号した直後にスクリプトを実行するのには十分な長さであり、席を離れてもボルトが実質的にロック解除されたままにならない程度には短い時間です。
ステップ 6: シークレットを決して出力しないdecrypt-and-execラッパーを作成する
これは、キーを露出させることなくボルトを日常的に使えるようにするための手順です。これを次のように保存します: ~/vault/cf-run.sh:
#!/usr/bin/env bash
# cf-run.sh — decrypt .cf.gpg and exec a command with CLOUDFLARE_EMAIL /
# CLOUDFLARE_API_KEY set for that one child process only. The decrypted value
# is never printed, written to disk, or returned as this script's output.
# Usage: ./cf-run.sh npx wrangler deploy
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CREDS_FILE="$SCRIPT_DIR/.cf.gpg"
[ -f "$CREDS_FILE" ] || { echo "cf-run.sh: $CREDS_FILE not found" >&2; exit 1; }
[ "$#" -gt 0 ] || { echo "usage: cf-run.sh <command> [args...]" >&2; exit 1; }
CREDS="$(gpg --quiet --batch --decrypt "$CREDS_FILE")" || { echo "cf-run.sh: decryption failed" >&2; exit 1; }
CF_EMAIL="$(awk '{print $1}' <<<"$CREDS")"
CF_KEY="$(awk '{print $2}' <<<"$CREDS")"
unset CREDS
exec env CLOUDFLARE_EMAIL="$CF_EMAIL" CLOUDFLARE_API_KEY="$CF_KEY" "$@"
chmod +x ~/vault/cf-run.sh
それがなぜ安全なままなのか、行ごとの解説:
- 復号されたテキストは、コマンド置換を通じてシェル変数に直接入ります。端末や標準出力には決して出力されません。
awkはその変数から2つのフィールドを抽出します。依然として何も出力されません。unset CREDSは、各部分が取り出されるとすぐに、結合された行をメモリから破棄します。exec env VAR=... "$@"はラッパーのプロセスをターゲットのコマンドに置き換え、それ自身の環境でのみ値を渡します。いかなる時点でも、ディスクに書き込まれたり、ログに記録されたり、エコーされたりすることはありません。
ステップ 7: すべてにラッパーを使用する
これは絶対にしないでください: CLOUDFLARE_API_KEY=$(cat ...) wrangler deploy 今後は。すべてのコマンドをラッパー経由でルーティングし、ターゲットツールに自身の環境から変数を読み取らせます:
~/vault/cf-run.sh npx wrangler deploy
~/vault/cf-run.sh curl -s "https://api.cloudflare.com/client/v4/user" \
-H "X-Auth-Email: $CLOUDFLARE_EMAIL" -H "X-Auth-Key: $CLOUDFLARE_API_KEY"
ステップ 8(AIアシスタントユーザーのみ): 強力なガードフックを追加する
コーディングアシスタントがマシン上でコマンドを実行する場合、「キーを出力しないように覚えておく」ことは制御とは言えません。多くのアシスタントは、コマンドの実行前にそれを検査して拒否できるフックシステムを公開しています。このアイデアは、次の2つをブロックする実行前ガードです: ボルトのプレーンテキスト形式を直接読み取ること、および、キャプチャされた変数ではなく標準出力やパイプにボルトを復号すること。
ガードは、簡単に言えば、保留中のシェルコマンドを検査し、次のことを行います:
- ブロック: 読み取りコマンド(
cat,less,head,stringsなど)がボルトのプレーンテキストファイル名に向けられている場合。 - ブロック: による
gpg --decryptボルトの操作。ただし、出力が次のようなコマンド置換にキャプチャされる場合を除く:X="$(gpg -d ... )". - 許可: 正当なものを含め、その他すべて
cf-run.shの呼び出し。
最小限のPythonガードは、許可する場合は終了コード0を返し、ブロックする場合は終了コード2を返し、アシスタントが理由を把握できるように標準エラーに理由を出力します:
#!/usr/bin/env python3
import json, re, sys
VAULT_HINTS = ("vault/.cf",) # add every vault path you protect
READ_CMDS = r"(cat|less|more|head|tail|strings|xxd|od)"
def main() -> int:
try:
cmd = (json.load(sys.stdin).get("tool_input") or {}).get("command", "") or ""
except Exception:
return 0 # never break tooling on a parse error
# Block reading the plaintext vault directly (matches .cf but not .cf.gpg)
if re.search(rf"(^|[;&|]\s*){READ_CMDS}\s+[^\n]*vault/\.cf(\s|$)", cmd):
sys.stderr.write("BLOCKED: reading the plaintext vault would leak it. Use cf-run.sh.\n")
return 2
# Only care about decrypting a protected vault
if re.search(r"gpg\b.{0,60}?(-d\b|--decrypt\b)", cmd) and any(h in cmd for h in VAULT_HINTS):
if re.search(r"\$\(\s*gpg\b", cmd) or re.search(r"`\s*gpg\b", cmd):
return 0 # captured into a variable — safe
sys.stderr.write("BLOCKED: decrypting to stdout leaks secrets. Capture into a variable.\n")
return 2
return 0
if __name__ == "__main__":
sys.exit(main())
これをアシスタントのpre-toolフック設定に組み込み、おとりファイルでテストしてください。決して実際のボルトでテストしないでください。テスト中にルールのバグによって実際のシークレットが出力される可能性があるからです。無害な vault/.cf を使い捨てディレクトリの下に作成し、アシスタントがその読み取りを拒否することを確認し、それとは別に正当な cf-run.sh コマンドが依然として通過することを確認します。
結論
保存時に認証情報を暗号化するだけでは不十分です。その値が安全に保たれるのは、決して表面化しない方法で復号され、かつ(AIアシスタントが関与する場合)安全でないアクセスが、規律ではなくコードによってブロックされる場合のみです。GPG対称暗号化、decrypt-and-execラッパー、および実行前のガードフックを組み合わせることで、真に使いやすく、真に漏洩しにくいボルトが得られます。セットアップには15分かかりますが、誰にも気づかれない恥ずかしい漏洩を全体的に排除できます。
メリット
- ポータブルで依存関係なし: コアのセットアップに必要なのは
gpgおよびbashのみであり、ほぼすべてのUnixマシンに存在します。 - 通常の操作中、シークレットが印刷されたり、ディスクに書き込まれたり、ログに記録されたりすることは決してありません。
- 対称暗号化により、単一のオペレーターにとってモデルがシンプルに保たれます。
- オプションのガードフックにより、「注意する」という行為が、コードレベルでの強制的な制御に変わります。
- 同じパターンは、Cloudflareだけでなく、あらゆる高権限の認証情報に機能します。
デメリット
- パスフレーズを忘れると完全に失われます。回復方法はありません。
shredは、SSD、コピーオンライトファイルシステム、または以前にバックアップされたファイルでの削除を完全に保証することはできません。- 暗号化は今後のキーを保護しますが、過去の漏洩を取り消すことはありません。
- ガードフックはアシスタント固有のものであり、実際のボルトのパスと同期させておく必要があります。
注意
この記事内のすべての値( [email protected], REPLACE_WITH_GLOBAL_API_KEY, main-account、および ~/vault パス)はプレースホルダーです。ご自身のものに置き換え、プレーンテキストの認証情報をバージョン管理に決してコミットしないでください。実際のキーで信頼する前に、おとりファイルに対してラッパーとガードをテストし、漏洩が疑われる場合はすぐに認証情報をローテーションしてください。自己責任で進めてください。ご自身の認証情報とインフラストラクチャに対する責任はあなたにあります。
よくある質問
公開鍵/秘密鍵のペアではなく、GPG対称暗号化を使用するのはなぜですか? 暗号化と復号化の両方を単一のオペレーターが行う場合、パスフレーズベースの対称暗号のほうがシンプルで同様に強力です。この場合、キーペアはセキュリティの向上をもたらさずにキー管理のオーバーヘッドを追加するだけです。
暗号化された .cf.gpg ファイルを git に保存しても安全ですか? 暗号文をコミットすることは技術的には安全ですが、マシンから持ち出すメリットはありません。ローカルに保管し、プレーンテキストは絶対にコミットしないでください。
Global API Key の代わりに Cloudflare API Token を使用すべきですか? はい、ツールがサポートしている場合はいつでもそうしてください。スコープ付きのトークンは個別に失効させることができ、スコープ外のリソースにはアクセスできないため、漏洩した場合の被害はGlobal API Keyが漏洩した場合よりもはるかに小さくなります。
decrypt-and-execラッパーは実際には何から保護するのですか? これにより、復号されたシークレットが1つの子プロセスの環境にのみ存在することが保証されます。ターミナルに出力されたり、シェル履歴にキャプチャされたり、ディスクに書き込まれたりすることは決してありません。これらは一般的な偶発的な漏洩経路です。
AIコーディングアシスタントにシークレットが漏洩するのはなぜですか?
アシスタントが読み取ったもの、またはコマンドが出力したすべてのものは、モデルプロバイダーに送信されるセッショントランスクリプトに追加されます。たった1回のプレーンテキストキーの cat や、標準出力への復号により、キーはそのトランスクリプトに永続的に配置されます。
すでに一度漏洩した場合、キーを暗号化することは役立ちますか? いいえ。暗号化は、将来の漏洩からキーを保護するだけです。キーが印刷されたり、貼り付けられたり、トランスクリプトで見られたりしたことがある場合は、キーをローテーションする必要があります。古い値を暗号化しても、露出したものについて何も変わりません。
高権限のキーはどのくらいの頻度でローテーションすべきですか? リスク許容度に合わせたスケジュールでローテーションし、漏洩の疑いがある場合は直ちにローテーションしてください。アカウント全体のキーの場合、その影響範囲はアカウント全体に及ぶため、より頻繁にローテーションする側に倒してください。
これをAWS、データベース、またはその他の認証情報に適用できますか? はい。保存時の暗号化、使い捨てのサブプロセス内でのみ復号化、安全でない読み取りのブロックという同じ3つのアイデアは、あらゆるシークレットに適用されます。一致するように、ラッパーのフィールド解析と環境変数名を調整してください。
タグ
#Security #GPG #Encryption #SecretsManagement #Cloudflare #APIKeys #DevOps #DevSecOps #AICoding #Linux
Kubernetes Security Checklist
Harden cluster access, workload identity, pod security, network boundaries, software supply chain, secrets, and operational monitoring.
Free. No spam — unsubscribe in one click.


Responses
Sign in to leave a response.