問題点:etcdには平文でデータが格納されている。
k8sの各種マニフェストははetcdに平文で保存されている。 secretであっても平文で保存されている。
twoという文字列を隠蔽したくてone-plus-oneというsecretを作成する。
$ k create secret generic one-plus-one --from-literal=ans=two
etcdの中を見てみと、twoという文字が確認できる。
$ etcdctl get /registry/secrets/default/one-plus-one | hexdump -C | grep two 000000f0 00 12 0a 0a 03 61 6e 73 12 03 74 77 6f 1a 06 4f |.....ans..two..O|
解決策
Kubernetesにおいてetcdと通信を行うアプリはkube-api-serverのみである。
そのため、kube-api-serverでデータの暗号化と復号化を行う。つまり、データをetcdに書き込む際には暗号化して書き込みを行い、データを読み出す場合にはetcdから読み出したデータを復号化して使う。
方法
EncryptionConfiguration
を用意して、それをkube-api-serverに--encryption-provider-config
オプションを使って読み込ませる。
EncryptionConfiguration
サンプル (参照元: Encrypting Confidential Data at Rest | Kubernetes)
# # # CAUTION: this is an example configuration. # Do not use this for your own cluster! # apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets - configmaps - pandas.awesome.bears.example # a custom resource API providers: - identity: {} - aesgcm: keys: - name: key1 secret: c2VjcmV0IGlzIHNlY3VyZQ== - name: key2 secret: dGhpcyBpcyBwYXNzd29yZA== - aescbc: keys: - name: key1 secret: c2VjcmV0IGlzIHNlY3VyZQ== - name: key2 secret: dGhpcyBpcyBwYXNzd29yZA== - resources: - events providers: - identity: {} - resources: - '*.apps' providers: - aescbc: keys: - name: key2 secret: c2VjcmV0IGlzIHNlY3VyZSwgb3IgaXMgaXQ/Cg==
.resources.resources
で暗号化、復号化を行う対象を選択する.resources.providers
で暗号化、復号化を行うproviderを選択する
.resources.providers
に指定するproviderの順序には以下のような意味があるので、注意が必要。
- 暗号化する際:
.resources.providers
に指定されている最初のproviderが利用される。 - 復号化する際:
.resources.providers
に指定されているproviderの中で適したものが自動で選択され使用される。
各種providerの意味は下記に記載されている。
試してみる
まずはEncryptionConfigurationを作成する
# # # CAUTION: this is an example configuration. # Do not use this for your own cluster! # apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: aG9nZWhvZ2Vob2dlaG9nZQ== - identity: {}
aG9nZWhvZ2Vob2dlaG9nZQ==
はecho -n hogehogehogehoge | base64
で適当に作ったものになっている。
このファイルは/etc/kubernetes/etcd/ec.yamlに保存した。(別にファイルの場所はkube-api-serverが渡せるならばどこでもよい。)
kube-api-serverに先ほど作成したEncryptionConfigurationを読み込ませる。
以下のような感じでkube-api-serverのマニフェストを修正。
@@ -13,6 +13,7 @@ containers: - command: - kube-apiserver + - --encryption-provider-config=/etc/kubernetes/etcd/ec.yaml - --allow-privileged=true - --authorization-mode=Node,RBAC @@ -92,6 +93,9 @@ - mountPath: /usr/share/ca-certificates name: usr-share-ca-certificates readOnly: true + - mountPath: /etc/kubernetes/etcd + name: etcd + readOnly: true hostNetwork: true priority: 2000001000 priorityClassName: system-node-critical @@ -119,4 +123,8 @@ path: /usr/share/ca-certificates type: DirectoryOrCreate name: usr-share-ca-certificates + - hostPath: + path: /etc/kubernetes/etcd + type: DirectoryOrCreate + name: etcd status: {}
one-minus-oneというsecretを新たに作成してみる
k create secret generic one-minus-one --from-literal=ans=zero
etcdctlでちゃんと暗号化されているか確認
$etcdctl get /registry/secrets/default/one-minus-one | hexdump -C | grep zero
大丈夫そう
元々あったone-plus-oneというsecretも暗号化してみる
この時点では元々あったsecretは暗号化されてない。
$ etcdctl get /registry/secrets/default/one-plus-one | hexdump -C | grep two 000000f0 00 12 0a 0a 03 61 6e 73 12 03 74 77 6f 1a 06 4f |.....ans..two..O|
元々あったsecretを全て再作成する。
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
改めてetcdctlでone-plus-oneを見てみる
$ etcdctl get /registry/secrets/default/one-plus-one | hexdump -C | grep two
何も出ない。つまり、暗号化された。