etcd

Kubernetes のコントロールプレーンには、クラスタの情報を格納する KV ストアとして etcd があります。 etcd はデフォルトでは 2379/tcp で API を提供しています。

root@master1:/# ss -ntlp4 | grep etcd
LISTEN    0         4096             127.0.0.1:2379             0.0.0.0:*        users:(("etcd",pid=11583,fd=6))
LISTEN    0         4096            10.0.1.105:2379             0.0.0.0:*        users:(("etcd",pid=11583,fd=5))
LISTEN    0         4096            10.0.1.105:2380             0.0.0.0:*        users:(("etcd",pid=11583,fd=3))

保管する情報には Secret リソースも含まれるため、適切なアクセス制御や暗号化を施す必要があります。
多くのクラスタ構築ツールでは外部公開せずに、TLS クライアント証明書による接続が必須になるように構成されます。

etcd の操作

etcd は API を介して操作することができます。

root@master1:/# curl -s -k \
    --cert /etc/ssl/etcd/ssl/node-master1.pem \
    --key /etc/ssl/etcd/ssl/node-master1-key.pem \
    --cacert /etc/ssl/etcd/ssl/ca.pem \
    https://127.0.0.1:2379/version | jq
{
  "etcdserver": "3.4.13",
  "etcdcluster": "3.4.0"
}

また、etcdctl を使って操作することもできます。etcd のバージョンによって API が異なるため、ETCDCTL_API 環境変数で利用するバージョンを指定する必要があります。
キーの一覧を取得すると Kubernetes クラスタのほとんどのリソースが含まれていることがわかります。

root@master1:/# etcdctl \
    --cert /etc/ssl/etcd/ssl/node-master1.pem \
    --key /etc/ssl/etcd/ssl/node-master1-key.pem \
    --cacert /etc/ssl/etcd/ssl/ca.pem \
    --endpoints https://127.0.0.1:2379 \
    get / --prefix --keys-only

/registry/apiextensions.k8s.io/customresourcedefinitions/bgpconfigurations.crd.projectcalico.org
/registry/apiextensions.k8s.io/customresourcedefinitions/bgppeers.crd.projectcalico.org
/registry/apiextensions.k8s.io/customresourcedefinitions/blockaffinities.crd.projectcalico.org
...
/registry/clusterrolebindings/calico-kube-controllers
/registry/clusterrolebindings/calico-node
/registry/clusterrolebindings/cephfs-csi-nodeplugin
...
/registry/clusterroles/admin
/registry/clusterroles/calico-kube-controllers
/registry/clusterroles/calico-node
...
/registry/configmaps/default/kube-root-ca.crt
/registry/configmaps/kube-node-lease/kube-root-ca.crt
/registry/configmaps/kube-public/cluster-info
...
/registry/controllerrevisions/kube-system/calico-node-f68f5dfc5
/registry/controllerrevisions/kube-system/kube-proxy-5bd89cc4b7
/registry/controllerrevisions/kube-system/nodelocaldns-84bfb6b45f
...
/registry/daemonsets/kube-system/calico-node
/registry/daemonsets/kube-system/kube-proxy
/registry/daemonsets/kube-system/nodelocaldns
...
/registry/deployments/kube-system/calico-kube-controllers
/registry/deployments/kube-system/coredns
/registry/deployments/kube-system/dns-autoscaler
...
/registry/namespaces/default
/registry/namespaces/kube-node-lease
/registry/namespaces/kube-public
...
/registry/pods/kube-system/calico-kube-controllers-7c5b64bf96-l54fz
/registry/pods/kube-system/calico-node-g7r9q
/registry/pods/kube-system/calico-node-pxzx4
...
/registry/secrets/kube-node-lease/default-token-jqg65
/registry/secrets/kube-public/default-token-rhw5q
/registry/secrets/kube-system/attachdetach-controller-token-dn6nl
...

値はシリアライズされたバイナリ値となっているため、可読性に乏しいですが、リソースのオブジェクトが入っていることがわかります。

root@master1:/# etcdctl \
    --cert /etc/ssl/etcd/ssl/node-master1.pem \
    --key /etc/ssl/etcd/ssl/node-master1-key.pem \
    --cacert /etc/ssl/etcd/ssl/ca.pem \
    --endpoints https://127.0.0.1:2379 \
    get /registry/namespaces/kube-system -w fields
"ClusterID" : 18321220406064639639
"MemberID" : 7551142479662027965
"Revision" : 1223524
"RaftTerm" : 3
"Key" : "/registry/namespaces/kube-system"
"CreateRevision" : 4
"ModRevision" : 4
"Version" : 1
"Value" : "k8s\x00\n\x0f\n\x02v1\x12\tNamespace\x12\xb6\x01\n\x9b\x01\n\vkube-system\x12\x00\x1a\x00\"\x00*$a65a4862-cb15-4a8d-9115-35cb3dd9a6422\x008\x00B\b\b\xc9\xffو\x06\x10\x00z\x00\x8a\x01O\n\x0ekube-apiserver\x12\x06Update\x1a\x02v1\"\b\b\xc9\xffو\x06\x10\x002\bFieldsV1:\x1d\n\x1b{\"f:status\":{\"f:phase\":{}}}\x12\f\n\nkubernetes\x1a\b\n\x06Active\x1a\x00\"\x00"
"Lease" : 0
"More" : false
"Count" : 1

Secret の暗号化

etcd に含まれるデータはデフォルトでは暗号化されません。そのため、etcd の API にアクセスされた場合、Secret リソースも含めた Kubernetes クラスタに含まれるクレデンシャルが漏洩する可能性があります。

❯ kubectl create secret generic password --from-literal=pass='p@ssw0rd'
secret/password created

root@master1:/# etcdctl \
    --cert /etc/ssl/etcd/ssl/node-master1.pem \
    --key /etc/ssl/etcd/ssl/node-master1-key.pem \
    --cacert /etc/ssl/etcd/ssl/ca.pem \
    --endpoints https://127.0.0.1:2379 \
    get /registry/secrets/default/password -w fields
"ClusterID" : 18321220406064639639
"MemberID" : 7551142479662027965
"Revision" : 1228694
"RaftTerm" : 3
"Key" : "/registry/secrets/default/password"
"CreateRevision" : 1228577
"ModRevision" : 1228577
"Version" : 1
# `p@ssw0rd` が含まれている
"Value" : "k8s\x00\n\f\n\x02v1\x12\x06Secret\x12\xcc\x01\n\xaf\x01\n\bpassword\x12\x00\x1a\adefault\"\x00*$85ed6ed7-af50-4962-9450-29de336c26132\x008\x00B\b\b\xf9\xde\xed\x88\x06\x10\x00z\x00\x8a\x01_\n\x0ekubectl-create\x12\x06Update\x1a\x02v1\"\b\b\xf9\xde\xed\x88\x06\x10\x002\bFieldsV1:-\n+{\"f:data\":{\".\":{},\"f:pass\":{}},\"f:type\":{}}\x12\x10\n\x04pass\x12\bp@ssw0rd\x1a\x06Opaque\x1a\x00\"\x00"
"Lease" : 0
"More" : false
"Count" : 1

適切に暗号化を行うと、値は次のようになり、etcd の API 経由では平文は取得できなくなります。

"Value" : "k8s:enc:aesgcm:v1:key1:ZZS(՝Uu\x1e\x81\xc0owc\x83j\x8e\x05\x8b\a(\x85\xb2\x0e\x8dd%\xc9!\xeey7\x..."

暗号化方式にはいくつかのパラメータが利用できますが、ローカルで管理している暗号化キーを使用する場合、EncryptionConfiguration のファイルに暗号化キーが保存されているため、ホストが侵害された場合は、復号される可能性があります。そのため、KMS のような Envelope 暗号化を利用する方式が推奨されます。

Rerefences

results matching ""

    No results matching ""