基本概念
KMS,Key Management Service,即密钥管理服务,在 K8S 集群中,以驱动和插件的形式启用对 Secret,Configmap 进行加密。以保护敏感数据,
驱动和插件需要使用者按照需求进行定制和实现自己的 KMS 插件,插件可以是 gRPC 服务器或者启用一个云服务商提供的 KMS 插件。
本文中演示使用的 KMS 服务是京东云舰中的 KMS 加密服务。
目前 KMS 分为 V1,V2,本文基于 V1 进行演示。
架构
内部可以利用 kms 加密实现自己的加密算法,甚至国密算法。
当用户新建 secret 资源时,kube-apiserver 会通过 gRPC 调用 kms-plugin,而 kms-plugin 与加密服务器通信,进行数据加密。
此时如果通过直接获取 etcd 中的原始数据,内容为密文数据。
当用户获取 secret 资源内容时,kube-apiserver 会通过 gRPC 调用 kms-plugin,而 kms-plugin 与加密服务器通信,进行数据解密,将明文展示给用户。
操作步骤
需要一套已经运行的 Kubernetes 集群服务,如果是多台 master 节点,需要同时配置。
新建目录
/etc/kubernetes/kms/jdcloud
新建 EncryptionConfiguration
该配置是 kms 基本的加密配置,包括加密资源对象,socket 地址等等。
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets # 这里表示,只加密secret
providers:
- kms:
name: myKmsPlugin
endpoint: unix:///var/run/k8s-kms-plugin/kms-plugin.sock # 如果不以pod(jdcloud-kms-plugin.yaml)启动,需要sock文件放到master节点。
cachesize: 100
timeout: 3s
- identity: {}
复制代码
以上内容保存在/etc/kubernetes/kms/jdcloud/apiserver-encryption.conf
新建 jdcloud kms plugin 配置
kms server 的上联信息配置
{
"AccessKey": "xxx", # 部署前,该参数需要预先知道,
"SecretKey": "yyy", # 部署前,该参数需要预先知道。
"KmsEndpoint": "kms.internal.cn-north-1.jdcloud-api.com", # 部署前,该参数需要预先知道。
"KmsKeyId": "abcd", # 部署前,该参数需要预先知道。
"KmsSchema": "http",
"GRPCSocketPath": "/var/run/k8s-kms-plugin/kms-plugin.sock"
}
复制代码
以上内容保存在/etc/kubernetes/kms/jdcloud/jdcloud-kms-plugin.json
新建 jdcloud kms plugin 服务
该服务是启动 socket 服务,并按照配置和上联的 kms server 进行通信,加密和解密数据,并通过 socket 服务和 K8S APIServer 交互。
该 pod 需要在 kube-apiserver 启动之前启动,否则与 apiserver 可能产生循环依赖。
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
component: jdcloud-kms-plugin
tier: control-plane
name: jdcloud-kms-plugin-node-01
namespace: kube-system
spec:
containers:
- command:
- /k8s-kms-plugin
- -f=/etc/kubernetes/kms/jdcloud/jdcloud-kms-plugin.json # 指定json
image: hub-pub.jdcloud.com/k8s/jdcloudsec/k8s-kms-plugin:v1.0.1
imagePullPolicy: IfNotPresent
name: jdcloud-kms-plugin
resources:
requests:
cpu: 250m
volumeMounts:
- mountPath: /etc/kubernetes/kms/jdcloud/jdcloud-kms-plugin.json # 注意路径
name: jdcloud-kms-plugin-configfile
readOnly: true
- mountPath: /var/run/k8s-kms-plugin/
name: k8s-kms-plugin-unixsock-directory
readOnly: false
hostNetwork: true
priorityClassName: system-cluster-critical
volumes:
- hostPath:
path: /etc/kubernetes/kms/jdcloud/jdcloud-kms-plugin.json # 注意路径
type: File
name: jdcloud-kms-plugin-configfile
- hostPath:
path: /var/run/k8s-kms-plugin/
type: DirectoryOrCreate
name: k8s-kms-plugin-unixsock-directory
status: {}
复制代码
以上内容保存在/etc/kubernetes/manifests/jdcloud-kms-plugin.yaml
修改 kube apiserver 配置
...
- --encryption-provider-config=/etc/kubernetes/kms/jdcloud/apiserver-encryption.conf
image: hub-pub.jdcloud.com/k8s/kube-apiserver:v1.19.9-109
imagePullPolicy: IfNotPresent
livenessProbe:
...
- mountPath: /etc/kubernetes/kms/jdcloud/apiserver-encryption.conf
name: apiserver-encryption-conf
readOnly: true
- mountPath: /var/run/k8s-kms-plugin/
name: k8s-kms-plugin-unixsock-directory
readOnly: false
...
- hostPath:
path: /etc/kubernetes/kms/jdcloud/apiserver-encryption.conf
type: File
name: apiserver-encryption-conf
- hostPath:
path: /var/run/k8s-kms-plugin/
type: DirectoryOrCreate
name: k8s-kms-plugin-unixsock-directory
复制代码
修改后保存
验证
在默认的命名空间里创建一个名为 secret1 的 Secret:
kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
复制代码
用 etcdctl 命令行,从 etcd 读取出 Secret:
etcdctl.sh get /kubernetes.io/secrets/default/secret1 [...] | hexdump -C
复制代码
结果为加密数据
验证 Secret 在被 API server 获取时已被正确解密:
kubectl describe secret secret1 -n default
复制代码
该结果为明文,mykey: mydata
产品能力
在 K8S 集群中,京东内部一直比较重视对敏感数据加密,特别是云舰面对越来越多的金融行业客户,加密服务基本是云舰中的标准配置。
经过产品能力打磨和内部实现,KMS 加密服务和 K8S 自动化集群以及一键配置创建都在云舰内实现了很好的产品化能力,可以随集群创建,一键启用 KMS 加密服务。
参考:
1. 使用 KMS 驱动进行数据加密
评论