【Kubernetes】SOPSとageでSecretのマニフェストを暗号化
はじめに
今回は、SOPSとageを使用して、KubernetesのSecretのマニフェストを暗号化する方法について紹介します。
KubernetesのSecret管理
KubernetesのSecretは、機密情報を管理するためのリソースですが、マニフェスト内の値はBase64でエンコードされているだけなので、デコードしてしまえば簡単に中身を見ることができてしまいます。
例えば、下記のようなSecretのマニフェストがあったとしても、
1apiVersion: v1
2kind: Secret
3metadata:
4 name: example-secret
5type: Opaque
6data:
7 secret: dGhpcyBpcyBjcmVkZW50aWFs
下記のようにデコードすることで中身を見ることができます。
1echo "dGhpcyBpcyBjcmVkZW50aWFs" | base64 -d
なので、このままマニフェストをGitなどで管理するのはセキュリティ上問題があるため、Kubernetesでは機密情報をSecretを使わず外部のセキュアなストレージに保存するか、Vaultなどの専用のツールを使ったりすることもあります。
ですが、今回はSOPSとageを使ってSecretのマニフェストを暗号化して、Gitなどで管理できるようにする方法を紹介します。
SOPSとage
まずは、SOPSとageについて簡単に説明します。
SOPS
SOPSは、YAMLやJSONなどのファイルを暗号化・復号化するためのツールです。実際に暗号化するのは、ageやGPGなどの暗号化ツールを使い、SOPS自体が暗号化を行うわけではありません。
SOPSを使うことで、ファイル全体ではなく、特定の値だけを暗号化できるようになります。
GitHub - getsops/sops: Simple and flexible tool for managing secrets
Simple and flexible tool for managing secrets. Contribute to getsops/sops development by creating an account on GitHub.
brew
を使ってインストールすることができます。
1brew install sops
age
ageは、シンプルな暗号化ツールです。Goのライブラリとしても提供されています。
GitHub - FiloSottile/age: A simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability.
A simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability. - FiloSottile/age
下記の書籍でも、1st EditionではGPGを使って暗号化を行っていましたが、2nd Editionではageを使って暗号化を行っています。
brew
を使ってインストールすることができます。
1brew install age
SOPSとageで暗号化・復号化
簡単にSOPSとageを使って暗号化・復号化する方法を紹介します。
まず、ageで鍵を生成します。
1age-keygen -o key.txt
実行すると、下記のように公開鍵が出力されます。
1Public key: age1fhhsvxmd55dwv5sak0vulq3utk5sxqas3l899u6apzkxu54jws3qeawch7
また、生成されたkey.txt
を確認すると、下記のように公開鍵と秘密鍵が記載されています。今回は試すだけなので公開してますが、実際には公開しないように注意してください(特に秘密鍵)。
1❯ cat key.txt
2# created: 2025-03-21T08:34:15+09:00
3# public key: age1fhhsvxmd55dwv5sak0vulq3utk5sxqas3l899u6apzkxu54jws3qeawch7
4AGE-SECRET-KEY-1RLUKSQZTFK2228Z4E3GV9658EJG9VGL6NUYXS3CE2EX362VSNGDQE6CDWQ
次に、暗号化したいファイル(test.yaml
)を作成します。
1secret: "this is a secret"
sops
コマンドで暗号化します。-e(--encrypt)
オプションを使って暗号化、-i(--in-place)
オプションを使ってファイルを上書きします。また、--age
オプションでageの公開鍵を指定します。
1sops -e -i --age age1fhhsvxmd55dwv5sak0vulq3utk5sxqas3l899u6apzkxu54jws3qeawch7 test.yaml
暗号化されたファイルは下記のようになります。secret
の値が暗号化されています。また、sops
の情報も追加されています。
1secret: ENC[AES256_GCM,data:yCSBwHb5WJaG9W28C24KjA==,iv:D0BwUYDeJmU34Qx+uDBao7i0Ca8rRe3f1HEgC06ZMQE=,tag:D8cBjIO5NVsQvOmMz+N9SA==,type:str]
2sops:
3 kms: []
4 gcp_kms: []
5 azure_kv: []
6 hc_vault: []
7 age:
8 - recipient: age1fhhsvxmd55dwv5sak0vulq3utk5sxqas3l899u6apzkxu54jws3qeawch7
9 enc: |
10 -----BEGIN AGE ENCRYPTED FILE-----
11 YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuU0pobytLNDI5cnk2L3lv
12 ODFUd2hCUG9TL3lKSFJ0MEZUaHZNSVNxdFZVCjhsVmpNTmxLTWpRM1F5MEhramZK
13 eHBHZ2VWV29NbjZSdHZoM0pGQk12ZW8KLS0tIGtQZXdKZ2tmTDhqbkpkY21yOTYw
14 QTFpY01EeDlzOFI1N0o1Y2hxVHJGWGcKeV8eq9zVhyRdIz2EAElhVMlC6v/K/wAB
15 GPzb7YNxhvPrWCq/LMgnP9NplFXMFZwyrPODXbrs48IwPGNNGxw8HQ==
16 -----END AGE ENCRYPTED FILE-----
17 lastmodified: "2025-03-20T23:46:09Z"
18 mac: ENC[AES256_GCM,data:5C8ZAR229it4OJ+UcfgASufYlyN8Vt5T4DnPBbiPWHZ5qiDa4rqQHZmG/s+EoFRs7ubwDKAuqrkLIk+cRyUNij/FTiOjfK0os6RWJsEaOYbWNzNJqMy45fOT5hkyRN24fCrBzcecPBpKfUZYiby6WnI3JS1d6VsebY4CO+q67+4=,iv:CGFXjjYFax8sViML6dIDryDChz7y0aGqzlu5FZPEh/s=,tag:l3BC/vhhBBGdntfg0EGMYw==,type:str]
19 pgp: []
20 unencrypted_suffix: _unencrypted
21 version: 3.9.4
復号化する場合、Macだとデフォルトで$HOME/Library/Application Support/sops/age/keys.txt
にある秘密鍵を使って復号しようとします。なので、作成したkey.txt
の内容を移しておく必要があります。また、XDG_CONFIG_HOME
環境変数を設定しておけば$XDG_CONFIG_HOME/sops/age/keys.txt
を指定したり、SOPS_AGE_KEY_FILE
環墋変数を使って任意のファイルを指定することもできます。
今回は、作成したkey.txt
を使って、-d(--decrypt)
オプションで復号化します。
1SOPS_AGE_KEY_FILE=$(pwd)/key.txt sops -d -i test.yaml
test.yaml
を確認すると、元の値に戻っていることが確認できます。
1secret: this is a secret
Secretのマニフェストを暗号化・複合化してみる
実際に、Secretのマニフェストを暗号化・複合化してみます。
Secretのマニフェストの作成
まず、Secretのマニフェスト(secret.yaml
)を作成します。このまま、Gitにコミットしてしまわないようにgitignore
などで除外しておくのがおすすめです。
1apiVersion: v1
2kind: Secret
3metadata:
4 name: secret-with-sops-age
5type: Opaque
6data:
7 PASSWORD: dGVzdHBhc3N3b3Jk
SOPSとageの準備
次に、SOPSとageの準備をします。
まず、ageで鍵を生成します。この鍵はGitにコミットしないように注意してください。今回は、複合化時に鍵の保存場所を~/.config/sops/age/keys.txt
にしているので、その場所に保存します。
1age-keygen >> ~/.config/sops/age/keys.txt
次に、SOPSの設定ファイル(.sops.yaml
)をプロジェクトのルートディレクトリに作成して、暗号化に使用するageの公開鍵の指定と、マニフェストの余計な部分を暗号化しないように暗号化する値の指定をします。
1creation_rules:
2 - encrypted_regex: ^(PASSWORD)$
3 age: age1tpey7z3lx8dy7hcc6pl7868d4ye8fg2kjcw6ply3tcndywu33glste57nk
Secretのマニフェストを暗号化
SOPSを使ってSecretのマニフェストを暗号化します。今回は元のファイルを上書きせず、新しいファイル(secret.enc.yaml
)に出力します。
1sops -e secret.yaml > secret.enc.yaml
暗号化されたファイル(secret.enc.yaml
)は下記のようになります。PASSWORD
の値のみが暗号化されています。
1apiVersion: v1
2kind: Secret
3metadata:
4 name: secret-with-sops-age
5type: Opaque
6data:
7 PASSWORD: ENC[AES256_GCM,data:D2M29p8UyUGWR4pYXebOSw==,iv:1DYb9+4x+YVDn5oUFjAlXlBiJqTPiE9b+tQUC+reauI=,tag:iyODzlElddtOo5xroBq5mA==,type:str]
8sops:
9 kms: []
10 gcp_kms: []
11 azure_kv: []
12 hc_vault: []
13 age:
14 - recipient: age1tpey7z3lx8dy7hcc6pl7868d4ye8fg2kjcw6ply3tcndywu33glste57nk
15 enc: |
16 -----BEGIN AGE ENCRYPTED FILE-----
17 YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5ZmM1Y3Vpd0RvWGhGdUda
18 c3pndEpqV1BTYnBaWnFsWWxtakkwa3dLdmtjClpNeXVvR1VsZ0N6WWpNRXBPRmJO
19 UnYyMXMvWXlQRTNDV0JLdGFzQUlZNVkKLS0tIEhJalBuUkFBd2lzTUJ5WkVaa0cz
20 ajh2MEdFNjdXYVhHU0IxbDhOa3ZmMVkKCiK1B3yKXjWeAhYtNfh3QjZtMQuW96NQ
21 wirazxlu6E+O2GVCoU6/TtQj4GxUuqdacvM7E4j4GJpILQ2E+Y2k7A==
22 -----END AGE ENCRYPTED FILE-----
23 lastmodified: "2025-03-21T00:31:52Z"
24 mac: ENC[AES256_GCM,data:6iJ0XwpzmcAKlMMf2JPKXqBH1E8y5diX2LNlMnW8A03bglvdanjSSkTLQ5nuaKmb5JzBChq4i0u0nhSTmCFc0iYqL20GAMhB781vB0OjbJfepWP+U07ItBYkscksmMHPQ8F0Vjc3+7Ng+H9eCPCZhYcDL976qvAtUSFi/e7ZTH4=,iv:+6X8gei2JNbjftKSc4z98opVrqbT0RfJ5qY+E1Bj8uE=,tag:rTg82kKA/cu/irPLAbRLTg==,type:str]
25 pgp: []
26 encrypted_regex: ^(PASSWORD)$
27 version: 3.9.4
これで、GitにコミットしてもSecretのマニフェストが暗号化されているので、安心して管理することができます。
Secretのマニフェストを復号化
Secretのマニフェストを復号化する場合は、下記のコマンドを実行します。
1sops -d secret.enc.yaml > secret.yaml
これで元のSecretのマニフェストが復元されます。
1apiVersion: v1
2kind: Secret
3metadata:
4 name: secret-with-sops-age
5type: Opaque
6data:
7 PASSWORD: dGVzdHBhc3N3b3Jk
まとめ
今回は、SOPSとageを使ってKubernetesのSecretのマニフェストを暗号化する方法について紹介しました。
SOPSとageで暗号化することで、機密情報の漏洩リスクを軽減することができます。また、SOPSを使うことで、ファイル全体ではなく、特定の値だけを暗号化できるので、マニフェスト自体の可読性を保ちつつ、機密情報を保護することができます。
参考
- getsops/sops: Simple and flexible tool for managing secrets
- FiloSottile/age: A simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability.