使用 KMS 提供商进行数据加密
- 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。 如果你还没有集群,你可以通过 Minikube 构建一 个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入 .
需要 Kubernetes 1.10.0 或更新版本
需要 etcd v3 或更新版本
FEATURE STATE: Kubernetes v1.12
该功能目前处于 beta 状态,意味着:
- 版本名称包含 beta (例如 v2beta3)。
- 代码经过了充分测试,启用该功能被认为是安全的。默认情况下被启用。
- 对整体功能的支持在未来不会被移除,尽管细节上可能会做更改。
- 在后续的 beta 或稳定版本中,对象的模式、语义可能以不兼容的方式发生变化。当这种情况发生时,我们将提供迁移到下一个版本的说明。这可能需要删除、编辑和重建 API 对象,编辑过程可能需要一些思考。这可能导致依赖该功能的应用程序停机一段时间。
- 建议仅在非业务关键场景使用该功能,因为在后续版本中可能会发生不兼容的更改。如果您有多个可以独立升级的集群,那么您可能可以放松这个限制。
- 请尝试使用我们的 beta 版功能,并给出反馈!在它们退出 beta 测试阶段之后,我们将很难去做更多的更改。
KMS 加密提供商使用封套加密模型来加密 etcd 中的数据。数据使用数据加密秘钥(DEK)加密;每次加密都生成一个新的 DEK。这些 DEK 经一个秘钥加密秘钥(KEK)加密后在一个远端的 KMS 中存储和管理。KMS 提供商使用 gRPC 与一个特定的 KMS 插件通信。这个 KMS 插件作为一个 gRPC 服务器被部署在 Kubernetes 主服务器的同一个主机上,负责与远端 KMS 的通信。
配置 KMS 提供商
为了在 API 服务器上配置 KMS 提供商,在加密配置文件中的提供商数组中加入一个类型为 kms
的提供商,并设置下列属性:
name
: KMS 插件的显示名称。cachesize
: 以明文缓存的数据加密秘钥(DEKs)的数量。一旦被缓存,就可以直接使用 DEKs 而无需另外调用 KMS;而未被缓存的 DEKs 需要调用一次 KMS 才能解包。timeout
: 在返回一个错误之前,kube-apiserver 等待 kms-plugin 响应的时间(默认是 3 秒)。
参见
为实现一个 KMS 插件,您可以开发一个新的插件 gRPC 服务器或启用一个由您的云服务提供商提供的 KMS 插件。您可以将这个插件与远程 KMS 集成,并把它部署到 Kubernetes 的主服务器上。
有关启用云服务提供商特定的 KMS 插件的说明,请咨询您的云服务提供商。
您可以使用 Go 语言的存根文件开发 KMS 插件 gRPC 服务器。对于其他语言,您可以用 proto 文件创建可以用于开发 gRPC 服务器代码的存根文件。
使用 Go:使用存根文件 service.pb.go 中的函数和数据结构开发 gRPC 服务器代码。
然后使用存根文件中的函数和数据结构开发服务器代码。
注意:
- kms 插件版本:
v1beta1
作为对过程调用 Version 的响应,兼容的 KMS 插件应把 v1beta1 作为 VersionResponse.version 返回
- 消息版本:
v1beta1
所有来自 KMS 提供商的消息都把 version 字段设置为当前版本 v1beta1
- 协议:UNIX 域套接字 (
unix
)
gRPC 服务器应监听 UNIX 域套接字
KMS 插件可以用任何受 KMS 支持的协议与远程 KMS 通信。 所有的配置数据,包括 KMS 插件用于与远程 KMS 通信的认证凭据,都由 KMS 插件独立地存储和管理。KMS 插件可以用额外的元数据对密文进行编码,这些元数据是在把它发往 KMS 进行解密之前可能要用到的。
确保 KMS 插件与 Kubernetes 主服务器运行在同一主机上。
使用 KMS 提供商加密数据
为了加密数据:
使用
kms
提供商的相应的属性创建一个新的加密配置文件:
- 设置 kube-apiserver 的
--encryption-provider-config
参数指向配置文件的位置。 - 重启 API 服务器。
注意: 在 1.13 之前的加密功能的 alpha 版本需要一个带有 kind: EncryptionConfig
和 apiVersion: v1
的配置文件,并使用 --experimental-encryption-provider-config
标志。
写入 etcd 时数据被加密。重启 kube-apiserver 后,任何新建或更新的秘密信息在存储时应该已被加密。要验证这点,您可以用 etcdctl 命令行程序获取秘密信息内容。
在默认的命名空间里创建一个名为 secret1 的秘密信息:
kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
-
ETCDCTL_API=3 etcdctl get /kubernetes.io/secrets/default/secret1 [...] | hexdump -C
其中 是用于连接 etcd 服务器的额外参数。
验证保存的秘密信息是否是以
k8s:enc:kms:v1:
开头的,这表明kms
提供商已经对结果数据加密。验证秘密信息在被 API 获取时已被正确解密:
应该符合
mykey: mydata
格式
确保所有秘密信息都已被加密
因为秘密信息是在写入时被加密的,所以在更新秘密信息时会加密该内容。
下列命令读取所有秘密信息并更新他们以便应用服务器端加密。如果因为写入冲突导致错误发生,请重试此命令。对较大的集群,您可能希望根据命名空间或脚本更新去细分秘密内容。
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
为了从本地加密提供商切换到 kms
提供商并重新加密所有秘密内容:
在配置文件中加入
kms
提供商作为第一个条目,如下列样例所示kind: EncryptionConfiguration
apiVersion: apiserver.config.k8s.io/v1
resources:
- resources:
- secrets
providers:
name : myKmsPlugin
endpoint: unix:///tmp/socketfile.sock
cachesize: 100
keys:
- name: key1
secret: <BASE 64 ENCODED SECRET>
- 重启所有 kube-apiserver 进程。
运行下列命令使用
kms
提供商强制重新加密所有秘密信息。
禁用静态数据加密
要禁用静态数据加密:
将
identity
提供商作为配置文件中的第一个条目:kind: EncryptionConfiguration
apiVersion: apiserver.config.k8s.io/v1
resources:
- resources:
- secrets
providers:
- identity: {}
- kms:
name : myKmsPlugin
endpoint: unix:///tmp/socketfile.sock
cachesize: 100
- 重启所有 kube-apiserver 进程。
运行下列命令强制重新加密所有秘密信息。