問題点: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)
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
- pandas.awesome.bears.example
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の意味は下記に記載されている。
kubernetes.io
試してみる
まずはEncryptionConfigurationを作成する
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
何も出ない。つまり、暗号化された。
参照
kubernetes.io