秘密鍵をGitに入れてしまったとき
更新
個人アプリ開発でいちばん焦る事故のひとつが、署名用の秘密鍵を Git に入れてしまうことです。
コッペの開発でも ios_distribution_private_key.pem を履歴に載せてしまったことがあり、プライベートリポジトリとはいえ、これがチーム開発で起きていたらゾッとする出来事です。
この記事は、本来コミットすべきではないもの(今回は鍵ファイル)を例に、何をするかを手順としてまとめます。コマンドの細部は環境で違うので、順番と判断を中心に書きます。
何が起きているか
Apple の配布用秘密鍵(例:ios_distribution_private_key.pem)がコミットに含まれると、次のリスクが同時に出ます。
- リポジトリを読める人が、その鍵をコピーできる
- clone / fork / CI のキャッシュ / バックアップに残る可能性がある
- 「今の main から消した」だけでは、古いコミットに残る
つまり問題は「今のツリーが綺麗か」ではなく、一度でも外に出た鍵を、このまま信頼してよいかです。答えは「信頼しない」なので、最初の作業は失効です。
対応の順番
1. まず失効させる(最優先)
履歴を書き換える前に、漏れた鍵では署名できない状態にします。ここを後回しにすると、掃除しているあいだも同じ鍵が有効なままです。
- Apple Developer で、該当する配布用証明書を取り消す(Revoke)
- 新しい配布用証明書を発行する
- Provisioning Profile を新しい証明書で作り直す
- Keychain、CI のシークレット、Fastlane Match など、鍵の保管場所を新しいものに差し替える
- 古い
.pem/.p12を手元のディスクからも消す(ゴミ箱も含む)
2. 拡散を止める
失効と並行して、まだ鍵ファイルが見える経路を閉じます。
- リポジトリが public なら、一時的に private にするか、アクセス権を見直す
- チャットや PR に鍵の中身を貼っていないか確認する
- CI の成果物・アーティファクトに鍵が乗っていないか見る
3. 履歴から鍵ファイルを消す
失効したあとに、過去のコミットからもファイルを除去します。今のコミットから消すだけでは足りません。よく使うのは git filter-repo(または BFG)です。
# 例:特定ファイルを履歴全体から除去(実行前にバックアップを取る)
git filter-repo --path ios_distribution_private_key.pem --invert-paths
4. force push する
履歴を書き換えたら、リモートに反映します。これは後始末で、失効の代わりにはなりません。
git push --force --all
# タグも使っている場合
git push --force --tags
ここまでで「今から clone する人」には見えにくくなります。ただし、すでに clone 済みの人・ミラー・キャッシュには残り得ます。だからこそ、先に失効させておく必要があります。
5. 再発防止
.gitignoreに*.pem/*.p12/*.mobileprovisionなどを入れる- 秘密情報はリポジトリ外(パスワードマネージャ、CI の Secrets、暗号化された別管理)に置く
- 可能なら pre-commit や秘密検知(gitleaks など)を入れる
- 証明書ファイルをプロジェクトに置く運用自体をやめる
失効したあとにやりがちな抜け
- 証明書は取り消したが、手元の Xcode が古い証明書のまま
- CI だけ新しい鍵にして、別 PC の Keychain に古い
.p12が残っている - ローカルの別フォルダに、鍵入りの古い clone が残っている
- GitHub の fork や、過去の Actions ログにパスや中身の断片がある
- チャットにファイルを添付していた
チェックの最後は、新しい証明書で Archive / TestFlight まで通るかです。
個人開発での現実的なライン
大企業のインシデント対応ほど形式ばらなくてよい一方で、次だけは省略しない方がよいです。
- 鍵・証明書の失効と作り直し
- 履歴からの除去と force push
.gitignoreと保管場所の見直し
「プライベートだし、バレてないと思うからそのまま」は、後から効いてくるタイプの事故です。
まとめ
- 秘密鍵が Git に入ったら、最初に失効させる
- 履歴削除と force push は、そのあとの後始末
- 同じ種類のファイルが二度とコミットされない仕組みを残す