0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ETCDのSecret暗号化を理解する

Posted at

目的

  • ETCDの暗複合化を理解する

手段

killercodaで手を動かす

環境

killercoda

ETCDの暗複合化 とは

ETCDはKubernetesの脳のようなもので、クラスターの状態に関する全ての情報(Secret、ConfigMap、Podの定義など)を保存しています。これらの情報が万が一漏洩すると大変なことになるため、ETCDに保存されるデータを暗号化しておくことがセキュリティ上非常に重要です。

つまり、ETCDに保存する重要なAPIリソース(Secrets等)は暗号化してセキュリティ強度を高めようということですね。k8s 公式ドキュメントで 暗号化鍵をクラスター内に保存することは大してセキュリティ向上に寄与しない と明言されています。暗号化鍵は 外部のKMS に保管しましょう。

設定に必要な手順は以下の通りです

  • 暗号化に利用するランダム文字列生成
  • 暗号化に利用する鍵設定を作成
  • APIサーバはETCD 暗号化設定を利用するように設定及び設定ファイルマウント

1つずつ手順を確認します。

  • 暗号化に利用するランダム文字列生成
controlplane:~$ head -c 32 /dev/urandom | base64
K6tBMZgu+Isixi4wXOB7LIhk/v6FVHc7lqAVcH5co+I=
# ランダム文字列生成

controlplane:~$ echo -n this-is-very-sec | base64
dGhpcy1pcy12ZXJ5LXNlYw==
# 特定文字列を基に文字列生成
  • 暗号化に利用する鍵設定を作成
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
  # 暗号化対象のリソースを指定
      - secrets
    providers:
      - aesgcm:
          keys:
            - name: key1
              secret: dGhpcy1pcy12ZXJ5LXNlYw==
      # 暗号化鍵を指定。複数の鍵や暗号プロバイダーを指定可能
      - identity: {}
      # プレーンテキスト読み取り用の設定。この行削除で平文リソース読み取り不可

kube-apiサーバに対して etcd 暗号化設定を適用する前に、既存 secret を確認します。

controlplane:/etc/kubernetes/etcd$ k get secrets -A
NAMESPACE   NAME      TYPE     DATA   AGE
one         s1        Opaque   1      5m13s
one         s2        Opaque   1      5m13s

controlplane:/etc/kubernetes/etcd$ k get secrets -n one s1 -o yaml
apiVersion: v1
data:
  data: c2VjcmV0
kind: Secret
metadata:
  creationTimestamp: "2025-10-16T07:51:01Z"
  name: s1
  namespace: one
  resourceVersion: "2379"
  uid: df9247cd-6143-4ee1-adfb-560dc239fe0e
type: Opaque

controlplane:/etc/kubernetes/etcd$ echo c2VjcmV0 | base64 --decode
secret
# secret は平文で保存されていることを確認

念の為、etcdctl コマンドでも確認します。

controlplane:/etc/kubernetes/etcd$ ETCDCTL_API=3 etcdctl \
   --cacert=/etc/kubernetes/pki/etcd/ca.crt   \
   --cert=/etc/kubernetes/pki/etcd/server.crt \
   --key=/etc/kubernetes/pki/etcd/server.key  \
   get /registry/secrets/one/s1 | hexdump -C
00000000  2f 72 65 67 69 73 74 72  79 2f 73 65 63 72 65 74  |/registry/secret|
00000010  73 2f 6f 6e 65 2f 73 31  0a 6b 38 73 00 0a 0c 0a  |s/one/s1.k8s....|
00000020  02 76 31 12 06 53 65 63  72 65 74 12 c0 01 0a a5  |.v1..Secret.....|
00000030  01 0a 02 73 31 12 00 1a  03 6f 6e 65 22 00 2a 24  |...s1....one".*$|
00000040  64 66 39 32 34 37 63 64  2d 36 31 34 33 2d 34 65  |df9247cd-6143-4e|
00000050  65 31 2d 61 64 66 62 2d  35 36 30 64 63 32 33 39  |e1-adfb-560dc239|
00000060  66 65 30 65 32 00 38 00  42 08 08 e5 c7 c2 c7 06  |fe0e2.8.B.......|
00000070  10 00 8a 01 61 0a 0e 6b  75 62 65 63 74 6c 2d 63  |....a..kubectl-c|
00000080  72 65 61 74 65 12 06 55  70 64 61 74 65 1a 02 76  |reate..Update..v|
00000090  31 22 08 08 e5 c7 c2 c7  06 10 00 32 08 46 69 65  |1".........2.Fie|
000000a0  6c 64 73 56 31 3a 2d 0a  2b 7b 22 66 3a 64 61 74  |ldsV1:-.+{"f:dat|
000000b0  61 22 3a 7b 22 2e 22 3a  7b 7d 2c 22 66 3a 64 61  |a":{".":{},"f:da|
000000c0  74 61 22 3a 7b 7d 7d 2c  22 66 3a 74 79 70 65 22  |ta":{}},"f:type"|
000000d0  3a 7b 7d 7d 42 00 12 0e  0a 04 64 61 74 61 12 06  |:{}}B.....data..|
000000e0  73 65 63 72 65 74 1a 06  4f 70 61 71 75 65 1a 00  |secret..Opaque..|
000000f0  22 00 0a                                          |"..|
000000f3
# 先頭に `k8s:enc` 等の文字列はありません。暗号化されていないことを表しています
  • APIサーバはETCD 暗号化設定を利用するように設定及び設定ファイルマウント
    - --encryption-provider-config=/etc/kubernetes/etcd/ec.yaml
  - mountPath: /etc/kubernetes/etcd
      name: enc-config
      readOnly: true
  - hostPath:
      path: /etc/kubernetes/etcd
      type: DirectoryOrCreate
    name: enc-config
# 関連設定のみ抜粋。設定ファイルを作成して特定パスにマウントする形です

watch crictl ps コマンドで kube-api server の再起動を確認します。

controlplane:/etc/kubernetes/manifests$ ps -aux |grep api
root       14353  3.0 13.1 1526252 288608 ?      Ssl  08:08   0:04 kube-apiserver --encryption-provider-config=/etc/kubernetes/etcd/ec.yaml --advertise-address=172.30.1.2 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/etc/kubernetes/pki/ca.crt --enable-admission-
# encryption-provider-config=/etc/kubernetes/etcd/ec.yaml 設定が渡されています

暗号化設定前に作成された API リソースは平文で ETCD に保存されています。暗号化設定後に対象APIリソースを暗号化する場合は下記コマンドを実行します。

controlplane:/etc/kubernetes/manifests$ k get -n one secrets -o json | kubectl replace -f -
secret/s1 replaced
secret/s2 replaced

ETCD の暗号化設定フラグを無効化し、暗号化された secret を読み取れるか確認します。

controlplane:/etc/kubernetes/manifests$ cat kube-apiserver.yaml |grep "#"
    #- --encryption-provider-config=/etc/kubernetes/etcd/ec.yaml
#    - mountPath: /etc/kubernetes/etcd
#      name: enc-config
#      readOnly: true
#  - hostPath:
#      path: /etc/kubernetes/etcd
#      type: DirectoryOrCreate
#    name: enc-config

controlplane:/etc/kubernetes/manifests$ k get -n one secrets s1 -o yaml
Error from server (InternalError): Internal error occurred: identity transformer tried to read encrypted data
# 暗号化された secret の読み取りに失敗しています。

次に平文の secret を確認します。

controlplane:/etc/kubernetes/manifests$ k get -n two secrets secret1 -o yaml
apiVersion: v1
data:
  data: c2VjcmV0
kind: Secret
metadata:
  creationTimestamp: "2025-10-16T07:51:01Z"
  name: secret1
  namespace: two
  resourceVersion: "2381"
  uid: f1b19148-2947-40b6-bead-f547b4e7be90
type: Opaque
controlplane:/etc/kubernetes/manifests$ echo c2VjcmV0 |base64 --decode
secret
# 平文のsecretは読み取り可能です。

etcd 暗号化設定を再有効化して暗号化した secret を確認します。

controlplane:/etc/kubernetes/manifests$ k get -n one secrets s1 -o yaml
apiVersion: v1
data:
  data: c2VjcmV0
kind: Secret
metadata:
  creationTimestamp: "2025-10-16T07:51:01Z"
  name: s1
  namespace: one
  resourceVersion: "4156"
  uid: df9247cd-6143-4ee1-adfb-560dc239fe0e
type: Opaque
# 暗号化された secret を読み取り可能です

secretcontrolplane:/etc/kubernetes/manifests$ k get -n two secrets secret1 -o yaml
apiVersion: v1
data:
  data: c2VjcmV0
kind: Secret
metadata:
  creationTimestamp: "2025-10-16T07:51:01Z"
  name: secret1
  namespace: two
  resourceVersion: "2381"
  uid: f1b19148-2947-40b6-bead-f547b4e7be90
type: Opaque
# 平文の secret も読み取り可能です

etcd 暗号化設定後は、平文のAPIリソースに対する読み取りは identity: {} 行で制御します。
暗号化設定ファイルから削除して kube-apiserver を再起動します。

controlplane:/etc/kubernetes/etcd$ cat ec.yaml |grep "#"
      #- identity: {}
# identity 行をコメントアウトします

controlplane:/etc/kubernetes/etcd$ k get -n one secrets s1 -o yaml
apiVersion: v1
data:
  data: c2VjcmV0
kind: Secret
metadata:
  creationTimestamp: "2025-10-16T07:51:01Z"
  name: s1
  namespace: one
  resourceVersion: "4156"
  uid: df9247cd-6143-4ee1-adfb-560dc239fe0e
type: Opaque
controlplane:/etc/kubernetes/etcd$ k get -n two secrets secret1 -o yaml
Error from server (InternalError): Internal error occurred: no matching prefix found
# 平文の API リソース読み取りに失敗しています。

おさらい

  • etcd 暗号化設定前に作成した API リソースは etcd暗号化設定後に再作成(暗号化)する必要がある
  • etcd暗号化設定後の平文APIリソース読み取りは etcd 暗号化設定ファイルの identity: {} で制御する
  • 暗号化鍵は外部 KMS 等できちっと管理する

あとがき

Kubernetes は奥が深い...

ソース

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?