メインコンテンツへスキップ
Gitに秘密を残さない
レッスン 5 / 15|10分で読めます

Gitに秘密を残さない

削除コミットでは消えない、という事実から出発する。gitignoreの再点検、GitHub Push Protectionの有効化、漏らした日の正しい手順。

Gitには、他のツールにはない性質があります。

すべての歴史が残る。

これはバージョン管理としては最高の性質で、秘密管理としては最悪の性質です。

年間2,900万件。第2回で見たとおり、公開リポジトリに混入する秘密情報の数です。しかもAIコーディング支援が有効なリポジトリのほうが漏洩率が40%高い。速く作れるほど、うっかりも速くなる。

今回は、うっかりを根性ではなく仕組みで防ぎます。

  • なぜ「削除してコミット」では手遅れなのか?
  • 混入を水際で止める仕組みはあるのか?
  • それでも漏れた日、最初の10分で何をするか?

「削除」が効かない理由

Gitは、変更の歴史を全部覚えています。

.env を誤ってコミットし、慌てて削除してコミットし直したとします。最新の状態からはファイルが消えました。しかし git log をたどれば、コミットした瞬間の中身はいつでも復元できます。公開リポジトリなら、その歴史ごと全世界に公開されています。

図書館に例えるなら、Gitは全ての版を保存する図書館です。最新版から1ページ破いても、書庫には破る前の版が全部並んでいます。

だから、鉄則はこうなります。

混入した秘密は「消す」ものではなく「無効化する」もの。

漏れたキーを無効化して新しいキーに替えれば(ローテーション)、歴史に残った古いキーはただの文字列になります。歴史を書き換える技術(履歴の強制改変)も存在はしますが、公開後では手遅れになりやすく、第一手は常にローテーションです。

水際で止める: 2つの仕組み

仕組み1: .gitignore を「秘密の側」から点検する

.gitignore.env を書くのはデプロイ回でやりました。今回は点検の向きを変えます。

ファイル一覧から「これは除外したか」を見るのではなく、「いま自分のリポジトリに、秘密を含むファイルはどれか」を先に書き出して、それが全部除外されているかを見ます。

# コミット予定の中に秘密が混ざっていないかを、コミット前に見る癖
git status
git diff --staged

git add -A(全部まとめて追加)を打つ前に、この2つで何を追加しようとしているのかを目視する。地味ですが、これだけで混入の大半は水際で見つかります。

仕組み2: GitHub Push Protection を有効にする

目視には限界があるので、機械にも見張らせます。

GitHubのPush Protectionは、APIキーらしき文字列を含むコミットを、プッシュの瞬間にブロックしてくれる機能です。事後に警告するのではなく、出て行く前に止める。空港の手荷物検査に近い仕組みです。

有効化は、リポジトリの Settings から Code security の項目を開き、Secret scanning と Push protection をオンにするだけです。既定ではオフなので、リポジトリを作るたびに自分でオンにします。

注意

機械は「知っているパターン」しか止めない

Push Protectionが検出するのは、主要サービスのキーの形式(AnthropicやOpenAIのキーなど)です。自作の合言葉や、形式が珍しい秘密は素通りします。手荷物検査があっても、申告は自分でする。目視と機械、両方で守ります。

なお、Anthropic APIキーには追加の保険があります。GitHubとの提携により、公開リポジトリに漏れたAnthropicキーは自動検出されて無効化されます。ただしこれは最後の保険で、頼る前提にするものではありません。

漏れた日の最初の10分

それでも漏れる日は来ます。私も一度、認証情報入りのファイルをコミットしかけました。そのとき体で覚えた手順です。

漏れた日の最初の10分

1

無効化

発行元でキーをrevoke。数分以内

2

差し替え

再発行して環境変数を更新

3

影響確認

そのキーで何ができたかを見る

4

再発防止

同じ穴をふさぐ変更を1つ

1. 無効化(最優先・数分以内)

漏れたキーの発行元(Supabase、Anthropic、Google等)の管理画面を開き、そのキーを無効化(revoke)します。削除コミットより先。犯人探しより先。これが止血です。

2. 再発行して差し替える

新しいキーを発行し、環境変数(ローカル .env とデプロイ先の金庫)を差し替えます。アプリが新しいキーで動くことを確認します。

3. 影響範囲を見る

漏れていた期間、そのキーで何ができたかを考えます。読み取り専用の鍵か、書き込みもできる鍵か。データベースに不審な変更がないか、サービスの利用量に異常な急増がないかを確認します。

4. 再発防止を1つ足す

Push Protectionをオンにする、git add -A をやめる、コミット前チェックを増やす。同じ穴をふさぐ変更を1つ入れて終わります。

明日のアクション

今日中にやる3点

  1. 自分の公開リポジトリ全部で Push Protection をオンにする
  2. git log --all -- .env を実行し、過去に .env をコミットした歴史がないか確かめる
  3. もし歴史にあれば、そのキーを今すぐローテーションする(履歴の削除ではなく)

今日のまとめ

3行で振り返ります。

  • Gitは全ての歴史を保存する。混入した秘密は削除ではなくローテーションで無害化する
  • 水際の守りは目視(git diff --staged)と機械(Push Protection)の二段構え。Push Protectionは既定オフ
  • 漏れた日の第一手はキーの無効化。数分以内。それから差し替えと影響確認

次のレッスン

ここまでで「鍵」の守りは一通り揃いました。次回は視点を変えて、利用者のログインの話です。パスワードの常識はこの数年で大きく書き換わりました。「複雑なパスワードを定期的に変更」が、もう推奨されていないことを知っていますか。

参考・出典