この記事について
この記事は、生成AIを活用しながら公式情報と一次情報を確認して整理しています。検証ステータス:🧪 構文・ロジック確認済み
Linux / GNU Bash環境で、ダミーの秘密情報を使った構文・変換テストを実施しています。実際の設定ファイルへ適用する前に、自分の環境でも確認してください。
設定ファイルをAIへ渡す前に、秘密情報を機械的にマスクする工程を入れておくと、手作業だけに頼るより消し忘れを減らせます。ただし、自動マスクは「最後の確認を不要にする仕組み」ではありません。機械処理と人間の目視を組み合わせる前提で使います。 、元ファイルを変更せず、マスク済みの別ファイルを作るBashスクリプトを作ります。
このスクリプトで守りたいこと
対象にするのは、設定ファイルに入りやすい次のような値です。
password / passwd
token
api_key / api-key
secret / client_secret
access_key
URL内の user:password@
PEM形式の PRIVATE KEY 本文
一方で、独自のキー名や複雑なJSON/YAMLまで完全に判定できるとは考えません。
flowchart LR
A[元の設定ファイル] -->|読み取り| B[mask-secrets.sh]
B --> C{秘密情報らしいか}
C -->|Yes| D[値を **** に置換]
C -->|No| E[そのまま出力]
D --> F[.masked ファイル]
E --> F
F --> G[機械チェック]
G --> H[人間が目視]
H --> I[AIへ渡す]
元ファイルを上書きしない
安全側に倒すため、このサンプルは入力ファイルを書き換えません。
app.conf ↓ 読み取り mask-secrets.sh ↓ app.conf.masked
マスク処理にバグがあっても、元の設定ファイルまで壊さないためです。また、同名の .masked が存在する場合も上書きせず停止します。
Bashスクリプト
mask-secrets.sh として保存します。
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <config-file>" >&2
exit 2
fi
input=$1
if [[ ! -f "$input" ]]; then
echo "ERROR: file not found: $input" >&2
exit 2
fi
output="${input}.masked"
if [[ -e "$output" ]]; then
echo "ERROR: output already exists: $output" >&2
exit 3
fi
umask 077
tmp=$(mktemp "${output}.tmp.XXXXXX")
trap 'rm -f "$tmp"' EXIT
awk '
BEGIN { in_private_key = 0 }
{
line = $0
if (line ~ /-----BEGIN ([A-Z0-9 ]+ )?PRIVATE KEY-----/) {
print line
print "****"
in_private_key = 1
next
}
if (in_private_key) {
if (line ~ /-----END ([A-Z0-9 ]+ )?PRIVATE KEY-----/) {
print line
in_private_key = 0
}
next
}
gsub(/:\/\/[^\/:@[:space:]]+:[^@\/[:space:]]+@/, "://****:****@", line)
lower = tolower(line)
if (lower ~ /^[[:space:]]*(export[[:space:]]+)?[a-z0-9_.-]*(password|passwd|token|api[_-]?key|secret|client[_-]?secret|access[_-]?key)[a-z0-9_.-]*[[:space:]]*[:=]/) {
eq = index(line, "=")
co = index(line, ":")
if (eq == 0) sep = co
else if (co == 0) sep = eq
else if (eq < co) sep = eq
else sep = co
print substr(line, 1, sep) " ****"
next
}
print line
}
' "$input" > "$tmp"
chmod 600 "$tmp"
mv "$tmp" "$output"
trap - EXIT
printf 'Created: %s\n' "$output"
umask 077 を設定してから一時ファイルを作り、最後に chmod 600 を適用しています。目的は、マスク途中のファイルを他ユーザーから読まれにくい状態で扱うことです。
ダミーデータで確認する
本物のパスワードやAPIキーは使わず、テスト専用の値で確認します。
cat > demo.conf <<'EOF' host=localhost password = dummy-password API_KEY: dummy-api-key export ACCESS_TOKEN=dummy-token url=https://alice:dummy-pass@example.com/api note=keep-this-line -----BEGIN PRIVATE KEY----- DUMMY-PRIVATE-KEY-BODY -----END PRIVATE KEY----- EOF chmod +x mask-secrets.sh bash -n mask-secrets.sh ./mask-secrets.sh demo.conf cat demo.conf.masked
想定される出力です。
host=localhost password = **** API_KEY: **** export ACCESS_TOKEN= **** url=https://****:****@example.com/api note=keep-this-line -----BEGIN PRIVATE KEY----- **** -----END PRIVATE KEY-----
既知のダミー値が残っていないかも確認できます。
grep -En 'dummy-password|dummy-api-key|dummy-token|dummy-pass|DUMMY-PRIVATE-KEY-BODY' demo.conf.masked
何も表示されなければ、今回用意したダミー秘密文字列は残っていません。ただし、未知の秘密情報まで存在しないことを証明したわけではありません。
自動マスクだけでは足りない理由
秘密情報の名前はシステムごとに異なります。たとえば credential、bearer、private_token、独自の変数名などは、このサンプルの正規表現では漏れる可能性があります。
flowchart TB
A[自動マスク] --> B[既知の秘密文字列をgrep]
B --> C[差分と本文を目視]
C --> D{怪しい値が残る?}
D -->|Yes| E[ルールを追加して再実行]
E --> A
D -->|No| F[必要な範囲だけAIへ渡す]
JSONやYAMLなど構造が重要な形式では、単純な行処理ではなく jq や yq など専用パーサーを使う方が安全な場合があります。
AIへ渡す情報自体を減らす
マスクと同じくらい重要なのが「必要な部分だけ渡す」ことです。設定ファイル全体を送る必要がないなら、問題の再現に必要なセクションだけ切り出します。
安全性は次のような多層構造で考えます。
flowchart LR
A[必要範囲だけ抽出] --> B[秘密情報をマスク]
B --> C[機械チェック]
C --> D[人間が確認]
D --> E[AIへ送信]
まとめ
元ファイルを変更せず、マスク済みコピーを作る
一時ファイルの権限も作成時から制限する
自動検出を100%とは考えず、既知値のチェックと目視を残す
複雑な構造化データは専用パーサーを検討する
AIへ渡す情報量そのものも必要最小限にする
公式情報・一次情報
GNU Bash Reference Manual
https://www.gnu.org/software/bash/manual/bash.html
GNU Awk User’s Guide
https://www.gnu.org/software/gawk/manual/gawk.html
OWASP Secrets Management Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html

コメント