〜Ageと組み合わせて「安全にGit管理」できる最小構成を知る〜
この記事は ZOZO Advent Calendar 2025 の16日目 の記事です。
2025年新卒のじゅんじゅんです。普段はFlutterでのプロダクト開発に従事しています。
はじめに
アプリ開発において必ず向き合うのが APIキー・パスワードなどの秘密情報管理。
個人開発などでは .env をSlackで渡してしまったり、
メンバーの誰が最新のやつを持っているか分からなくなることもあります。
さらに、PRレビューでは「どの値が変わったの?」が全く見えず困ったことがある人も多いはず。
そこで今回紹介するのが SOPS + Age。
- 値だけ暗号化して、キー名は残す
- 暗号化されたまま Gitで扱える
- 差分レビューがしやすい
- CI/CDで自動復号できる
この記事では、最短でSOPSを実務に導入できる理解 を目指します。
この記事でわかること
- SOPSの仕組み:値だけ暗号化し、キー名と構造を保持する理由
- Ageとの連携方法:公開鍵/秘密鍵を使った暗号化フロー
- Git運用パターン:差分レビュー、環境別管理、鍵管理
- CI/CDでの復号方法:GitHub Actionsでの実例
対象読者
| 経験 | レベル |
|---|---|
| Git | 基本操作が分かる |
| 秘密情報管理 |
.env で苦しんだ経験がある |
| SOPS | 初見でもOK |
完成形(イメージ)
SOPSのすごいところは、暗号化後も どのキーが変わったか分かること です。
api:
- key: ENC[AES256_GCM,data:old...]
+ key: ENC[AES256_GCM,data:new...]
+ new_token: ENC[AES256_GCM,data:xxx...] # 新規追加
database:
- password: ENC[AES256_GCM,data:before...]
+ password: ENC[AES256_GCM,data:after...]
「値」は暗号化されて見えませんが、キー名は見えるためレビューが非常にしやすい。
👉 デモリポジトリ: https://github.com/junjun-1345/flutter-sops
SOPSとは
SOPS(Secrets OPerationS) は YAML / JSON / ENV などの構造を保ったまま値のみ暗号化するツール です。
SOPSの特徴
- 値だけ暗号化、キー名と構造はそのまま
- Git管理でも差分レビューしやすい
- Age / KMS / PGP など複数の暗号方式を選べる
- VSCodeで復号編集可能
暗号化例
# 暗号化前
api:
key: my_secret_key
database:
password: super_secret
# SOPS暗号化後
api:
key: ENC[AES256_GCM,data:xxx...]
database:
password: ENC[AES256_GCM,data:yyy...]
「キー名は見える」とは?
値のみ暗号化され、key や password といった 項目名は残る仕様 のこと。
そのため、PRレビュー時の変更点が把握しやすくなります。
Age + SOPS のセットアップ
インストール
brew install sops age
Age鍵の生成
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
出力例:
Public key: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxx
公開鍵は暗号化にのみ利用されるため、漏洩リスクは低く Git 管理しても一般的には問題ありません。
ただし、組織のセキュリティポリシーに従って管理してください。
SOPSが秘密鍵を参照する設定
echo 'export SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt"' >> ~/.zshrc
source ~/.zshrc
SOPSの基本的な使い方
1. .sops.yaml をプロジェクトルートに作成
creation_rules:
- path_regex: .*\.yaml$
age: age1xxxxxxxxxxxxxxx
2. 平文ファイルを暗号化する
cat > secrets.yaml <<'EOF'
api:
key: my_secret_key
database:
password: super_secret
EOF
sops encrypt secrets.yaml > secrets.sops.yaml
rm secrets.yaml
3. 復号化
sops decrypt secrets.sops.yaml
4. 編集(最も便利)
sops secrets.sops.yaml
- 復号 → 編集 → 再暗号化 を自動で実行
Git差分がなぜ見えるのか?
api:
key: ENC[AES256...]
+ new_token: ENC[AES256...]
構造が残るため、どのキーが追加・変更されたか分かります。
SOPS は AES256-GCM を使用しており、一般的に十分安全とされています。
ただし、鍵管理の不備があると安全性は損なわれる ため注意が必要です。
公開鍵と秘密鍵の違い
| 種類 | 例 | Git管理 | 用途 |
|---|---|---|---|
| 公開鍵 | age1xxxx... |
可 | 暗号化に使用 |
| 秘密鍵 | AGE-SECRET-KEY-xxxx |
不可 | 復号化に使用 |
CI/CDでの復号化(GitHub Actions例)
- name: Setup SOPS
run: |
mkdir -p ~/.config/sops/age
echo "${{ secrets.SOPS_AGE_KEY }}" > ~/.config/sops/age/keys.txt
- name: Decrypt secrets
run: sops decrypt secrets.sops.yaml > config.yaml
※ 復号後のファイル内容をログに出さないよう十分注意してください。
.gitignore
secrets.yaml
config.yaml
keys.txt
実務での運用パターン
1. チームメンバー全員で復号したいケース
creation_rules:
- path_regex: .*\.yaml$
age: >-
age1xxx..., # Aさん
age1yyy..., # Bさん
age1zzz... # CI/CD
2. 環境別ファイル
secrets/
├── dev.sops.yaml
├── stg.sops.yaml
└── prod.sops.yaml
3. 運用フローまとめ
まとめ
- SOPS + Age は安全に秘密情報を管理しつつGitで扱える
- 値だけ暗号化してキー名を残す ため差分レビューがしやすい
- 公開鍵はGit管理可(ただし組織ポリシーに従う)
- CI/CD まで含めたワークフローがシンプル