シークレットを暗号化してgit管理したいときに使えるSOPS, ageの紹介

264 Views

February 26, 26

スライド概要

Gitでシークレットを扱いたい場面の整理を行い、解決策としてのSOPS + ageを軽く紹介します。

profile-image

座右の銘は「an infinite iterator has no upper bound」

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

シークレットを暗号化して git管理したいときに使える SOPS, ageの紹介 2026-02-26 / Masanori Tani (@uta8a)

2.

2 今日の流れ 発表で持ち帰って欲しいこと シークレットをgit管理したいとき どういう場面でシークレットをgit管理したいか 解決策 整理できた SOPS, ageの概要 SOPS, ageが何者か分かった 速習 SOPS 使い方のイメージが湧いた 速習 age 実際に使ってみた話 シークレットを暗号化して管理したい理由の整理 →解決するツールとしてのSOPS, ageの紹介

3.

3 シークレットをgit管理したいとき secretをgit管理したいとき A. シークレットも含め、変更履歴を残したい: GitOps的な B. ファイルがシークレット: YAMLなど C. シークレットストアのコスト: 保存コスト →それぞれのパターンを軽く見ていく

4.

4 A. 変更履歴を残したい 厳密なGitOpsでは、シークレットもSSoTで管理す る(はず?) シークレットの変更をcommit履歴に記録したい もちろんシークレットをそのままgit pushできない! SealedSecrets など、暗号化してgit管理する OpenGitOpsによるGitOpsPrinciples "retains a complete version history"

5.

5 B. ファイルがシークレット ファイルが丸ごとシークレットの場合、シークレットストアに入らない場合がある GitHub Actionsで使うRepository Secrets のサイズ制限は48KBまで 大きなシークレットは暗号化してgit管理する必要がある GitHub Docs ではgpgで暗号化してコミットする方法が紹介されている 参考: https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/usesecrets#storing-large-secrets AWS, Google Cloudのシークレットストア系サービスも同様 AWS Secrets Manager: Secret value size limit 65,536 Bytes(= 64 KiB) Google Cloud Secret Manager: Secret payload size limit 64 KiB

6.

6 C. シークレットストアのコスト ファイルに書かれているシークレットを分割してシークレットストアに入れたら良いのではないか? →個人開発だと結構コストが気になってしまう… AWS Secrets Managerは1つのシークレットあたり保存コストが USD 0.40/月 = 62円 正直こんな高性能なシークレットストアがこの値段は破格だと思うが、シークレット数が増えるとコストに 困る →やっぱり暗号化しておいて、復号鍵をシークレットストアで保存したい

7.

7 解決策 暗号化して、復号鍵を別で管理しよう 手段 強み 注意点 gpg で暗号化 枯れたツールで安定 重厚な操作/管理 SealedSecrets k8s 運用との相性の良さ k8sクラスタで使う前提 SOPS + age 導入が軽く、ファイル暗号化に特化 統合には工夫が必要 今回紹介するのは SOPS + age

8.

8 SOPSの概要 ageの概要 SOPSは構造化データ、バイナリを暗号化できるツー ル ageはファイル暗号化ツール ファイル構造を保ったまま部分暗号化も可能 仕組みは後述。マスターキーが必要で、それを管 理するのがKMS, age, PGPになっている ageはSOPSのバックエンドのひとつ It’s recommended to use age over PGP, if possible. https://github.com/getsops/sops#id8 SOPSでは、PGPよりageが推奨されている (参考) SOPS PR #688 コマンドは少なくシンプル SOPSのマスターキー管理に使える SOPS内部の実装で、ageをgoのライブラリとして呼 び出している。(=SOPSではファイル暗号化に使って いるわけではない) // aw: io.WriteCloser // key.parsedRecipient: age.Recipient (string) w, err := age.Encrypt(aw, key.parsedRecipient) w.Write(dataKey) (参考) v.3.12のSOPSのコードより、一部改変

9.

9 速習 SOPS # インストール $ mise use sops@latest --pin # 3.11.0 # Encrypt # age1... は公開鍵 $ sops encrypt --age age1... test.json > test.enc.json # Decrypt $ export SOPS_AGE_KEY_FILE=./key.txt # 秘密鍵ファイルを指定 $ sops decrypt --output-type json test.enc.json > test.dec.json # test.json == test.dec.json SOPSは拡張子を見てYAML, JSON, binaryなどに分岐した処理を行うので、 --input-type / --outputtype は明示すると良い。 明示していないと、 .enc.json なら通るが、 .json.enc だと通らないみたいなことが起こる。 (参考) SOPSのREADME 3.1 YAML, JSON, ENV and INI type extensions

10.
[beta]
10

元のtest.json
{"hoge": 1234, "fuga": "super-secret"}

暗号化したtest.enc.json
{

}

"hoge": "ENC[AES256_GCM,data:...,iv:...,tag:...,type:float]", // keyは暗号化後も見える
"fuga": "ENC[AES256_GCM,data:...,iv:...,tag:...,type:str]",
"sops": {
"age": [
{
"recipient": "age1...",
"enc": "..."
}
],
"lastmodified": "2026-02-13T13:52:08Z",
"mac": "ENC[AES256_GCM,data:...,iv:...,tag:...,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.11.0"
}

11.
[beta]
11

SOPS その他色々
binaryとして暗号化すると、 "data": ... のようになりkeyも見えなくなる
Key groupsを使うと1つのファイルの復号を複数のマスターキーが揃わないとできないようにできる
1つのファイルを復号する時は、通常1つのマスターキー
複数人の管理者が揃うと鍵が開けられるイメージ
シャミアの秘密分散法を用いている
鍵指定は .sops.yaml に置く。鍵は2つ以上指定できる(どれかで復号可能)→ローテーション時に役立
つ
# その他便利コマンド
# 部分的に復号する: `--extract`
$ sops decrypt --extract '["fuga"]' test.enc.json
super-secret
# 復号して環境変数とする: `exec-env`
$ sops exec-env test.enc.json 'printenv fuga' # この次の行で echo $fuga しても値は出てこない
# 復号してファイルとして渡す: `exec-file`
$ sops exec-file --output-type json test.enc.json 'cat {}' # JSONが出てくる

12.

12 速習 age # インストール $ mise use age@latest --pin # 1.3.1 # 鍵生成してkey.txtに保存 (秘密鍵と公開鍵が両方入る) $ age-keygen -o key.txt # 公開鍵を出力 $ age-keygen -y key.txt age1... # recipientと呼ぶ # 暗号化 $ age --encrypt -r age1... -o secret.txt.age secret.txt # 復号 $ age --decrypt -i key.txt -o secret.dec.txt secret.txt.age # secret.txt == secret.dec.txt ファイル暗号化ツールなので、jpgとかのバイナリも暗号化できる

13.

13 ageのPQC対応 シークレットをGitで管理して公開する可能性がある →PQC(Post Quantum Cryptography, 耐量子計算機暗号) 対応がされているかは気になる ageはPQC対応している。 age-keygen -pq でX25519 + ML-KEM hybridが使われる SOPSはageのPQC対応が入ったリリースはまだされてない(v3.12.0以降でもうすぐ出る)

14.

14 実際に使ってみた 対象: Cloudflare DomainのDNS record設定をTerraformで管理→Cloudflare API Tokenを暗号化してcommit 構成: SOPSのPQC対応リリースがされていなかったので、ageだけで運用している Google Cloud Secret Managerでageのsecret keyを管理 recipient(公開鍵)と .env.age はcommitした miseを用いて、手元で特定のmise taskを使った時にのみ復号して環境変数として読み込むようにした sops exec-env 相当(早く自前処理から置き換えたい) mise run apply した時にGoogle Cloudに接続して復号 パブリックリポジトリ: uta8a/domain

15.

15 まとめ シークレットを暗号化してgit管理したい場面がある SOPS, ageによって、シークレットを暗号化してgit管理することができる SOPSは主に構造化データの暗号化、ageはファイル暗号化ができる 使ってみたらageのおかげでシークレットストアへの保存数を減らせた ageのsecret key1つにできた パターンCの解決