1. 为什么我们需要加密Kubernetes Secrets
Kubernetes Secrets是用来存储和管理敏感信息(如密码、OAuth令牌、SSH密钥等)的对象。但默认情况下,这些Secrets只是做了简单的Base64编码,而不是真正的加密。这就好比你把家门钥匙藏在门口的地毯下 - 任何人都知道去那里找。
在Kubernetes集群中,Secrets数据最终会存储在ETCD这个分布式键值存储中。如果不加密,任何能够访问ETCD的人(比如系统管理员)都可以直接查看这些敏感信息。这显然不符合安全最佳实践。
想象一下这样的场景:你的生产环境中有一个包含数据库密码的Secret。如果黑客入侵了你的ETCD,或者有内部人员滥用权限,他们就能轻松获取这些关键凭证,进而控制你的整个数据库。这绝对不是我们想看到的结果。
2. ETCD数据加密基础
2.1 Kubernetes中的静态数据加密
Kubernetes提供了静态数据加密(Encryption at rest)功能,可以在数据写入ETCD之前对其进行加密。这就像给你的敏感数据加了一个保险箱,即使有人拿到了ETCD的数据文件,没有密钥也无法解密内容。
Kubernetes使用一个称为"EncryptionConfiguration"的配置文件来定义加密方案。这个配置文件告诉API服务器如何加密和解密资源。
2.2 支持的加密方案
Kubernetes支持多种加密方案,主要包括:
- AES-CBC:使用AES算法在CBC模式下的加密,密钥长度可以是128位、192位或256位
- AES-GCM:使用AES算法在GCM模式下的加密,提供更好的性能和安全性
- Secretbox:使用XSalsa20和Poly1305算法的加密方案
- KMS插件:与外部密钥管理服务集成的方案
其中,AES-GCM是目前推荐的选择,因为它既安全又高效。而KMS插件方案则适合需要更高安全级别的场景。
3. 配置ETCD数据加密
3.1 创建EncryptionConfiguration文件
让我们从最基本的AES-GCM加密开始。首先,我们需要生成一个加密密钥,然后创建EncryptionConfiguration文件。
# encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-secret>
- identity: {} # 允许未加密的资源被读取(向后兼容)
要生成一个安全的密钥,我们可以使用以下命令:
# 生成32字节(256位)的随机密钥并使用base64编码
head -c 32 /dev/urandom | base64
3.2 应用加密配置
有了配置文件后,我们需要让API服务器使用它。这通常需要修改API服务器的启动参数:
# 修改kube-apiserver的启动参数
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml
在kubeadm管理的集群中,我们可以通过修改/var/lib/kubelet/config.yaml文件来添加这个参数。
3.3 验证加密是否生效
应用配置后,我们可以通过以下步骤验证加密是否正常工作:
创建一个测试Secret:
kubectl create secret generic test-secret --from-literal=mykey=mydata直接查询ETCD查看数据:
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/apiserver-etcd-client.crt \ --key=/etc/kubernetes/pki/apiserver-etcd-client.key \ get /registry/secrets/default/test-secret
如果配置正确,你应该看到加密后的数据,而不是原始的"mydata"。
4. 使用外部密钥管理服务(KMS)
虽然本地加密提高了安全性,但密钥仍然存储在集群中。为了更高级别的安全,我们可以集成外部密钥管理服务(Key Management Service, KMS)。
4.1 KMS插件工作原理
KMS插件通过gRPC与外部密钥管理服务通信。当API服务器需要加密数据时:
- 将明文发送给KMS插件
- KMS插件转发给外部KMS服务
- KMS服务返回加密后的数据
- API服务器将加密数据存储到ETCD
解密过程则相反。关键在于加密密钥永远不会暴露给Kubernetes集群。
4.2 配置AWS KMS插件示例
AWS提供了KMS插件实现。下面是一个使用AWS KMS的EncryptionConfiguration示例:
# encryption-config-kms.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- kms:
name: aws-kms
endpoint: unix:///var/run/kms-plugin/socket.sock
cachesize: 100
timeout: 3s
- identity: {}
4.3 部署KMS插件
部署AWS KMS插件通常需要以下步骤:
- 在AWS中创建KMS密钥并记录其ARN
- 创建IAM角色和策略,允许插件访问KMS
- 部署插件作为DaemonSet或Deployment
- 配置API服务器使用插件
# 部署AWS KMS插件的Deployment示例
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: aws-encryption-provider
namespace: kube-system
spec:
replicas: 2
selector:
matchLabels:
app: aws-encryption-provider
template:
metadata:
labels:
app: aws-encryption-provider
spec:
containers:
- name: aws-encryption-provider
image: amazon/aws-encryption-provider:latest
args: ["--key=arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"]
ports:
- containerPort: 8080
volumeMounts:
- name: sock
mountPath: /var/run/kms-plugin
volumes:
- name: sock
emptyDir: {}
EOF
5. 密钥轮换策略
5.1 为什么需要轮换密钥
即使使用了加密,定期轮换密钥也是安全最佳实践。这可以:
- 限制密钥泄露的影响范围
- 符合合规要求
- 应对潜在的密钥破解风险
5.2 本地加密密钥轮换
对于本地加密方案,轮换密钥需要:
- 在EncryptionConfiguration中添加新密钥(确保放在keys数组的第一个位置)
- 重启API服务器
- 重写所有Secrets以使用新密钥加密
# 更新后的encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key2 # 新密钥
secret: <new-base64-encoded-secret>
- name: key1 # 旧密钥
secret: <old-base64-encoded-secret>
- identity: {}
5.3 KMS密钥轮换
对于KMS方案,轮换通常更简单:
- 在KMS服务中创建新密钥
- 更新插件配置使用新密钥ARN
- 滚动重启插件和API服务器
大多数KMS服务(如AWS KMS)支持自动密钥轮换,可以进一步简化这个过程。
6. 实际应用场景分析
6.1 金融行业应用
在金融行业,合规要求通常非常严格。使用KMS集成方案可以:
- 满足PCI DSS等标准对密钥管理的要求
- 实现职责分离(密钥管理与集群管理分开)
- 提供详细的密钥使用审计日志
6.2 多租户环境
在多租户Kubernetes环境中,ETCD加密可以:
- 防止租户间通过ETCD访问互相的Secrets
- 结合RBAC提供纵深防御
- 支持租户特定的加密密钥(通过多个EncryptionConfiguration)
6.3 混合云部署
对于跨云部署的场景,外部KMS方案可以:
- 提供一致的密钥管理体验
- 避免被单一云厂商锁定
- 支持企业级密钥管理策略
7. 技术优缺点对比
7.1 本地加密方案
优点:
- 实现简单,不需要额外基础设施
- 性能开销小
- 适合小型或测试环境
缺点:
- 密钥仍然存储在集群内
- 密钥轮换复杂
- 缺乏高级密钥管理功能
7.2 KMS集成方案
优点:
- 更高的安全性(密钥不存储在集群中)
- 专业的密钥管理功能(轮换、审计等)
- 符合严格合规要求
缺点:
- 需要额外的基础设施
- 可能引入性能开销
- 增加系统复杂性
8. 注意事项与最佳实践
8.1 加密前的Secrets
启用加密前存在的Secrets不会被自动加密。你需要手动更新它们:
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
8.2 性能考虑
加密会增加API服务器的CPU开销。对于大规模集群:
- 考虑使用AES-GCM而不是AES-CBC
- 对KMS插件进行性能测试
- 可能需要增加API服务器资源
8.3 备份与恢复
加密会影响备份策略:
- 备份ETCD数据时,确保也备份EncryptionConfiguration
- 恢复集群时,需要使用相同的加密密钥
- 考虑将加密配置纳入版本控制(不含密钥)
8.4 多集群管理
管理多个集群时:
- 考虑使用集中式的KMS服务
- 为每个集群使用不同的加密密钥
- 文档化每个集群的加密方案
9. 总结
Kubernetes Secrets加密是保护集群敏感数据的关键措施。从基本的ETCD加密到与外部KMS服务集成,Kubernetes提供了多种方案来满足不同安全需求。
对于大多数生产环境,特别是受严格合规要求约束的环境,推荐使用KMS集成方案。虽然设置更复杂,但它提供了企业级的安全保障和密钥管理能力。
无论选择哪种方案,都要确保:
- 理解加密的范围和限制
- 实施适当的密钥轮换策略
- 考虑加密对运维流程(如备份、恢复)的影响
- 定期审计加密配置和访问权限
通过合理配置ETCD数据加密和外部密钥管理,你可以显著提升Kubernetes集群的安全性,保护关键业务数据不被泄露。
评论