Service 服务端证书
概述
Service 服务端证书可为容器云平台中的 Service 自动生成和管理 TLS 证书。此功能支持安全的 HTTPS 通信以及内部组件之间的流量加密,确保数据隐私和系统安全。
功能特性
此自动化证书签发机制提供以下主要功能:
- 零接触签发:开发者无需手动生成证书签名请求 (CSR),也无需与证书颁发机构交互。证书通过标准 Kubernetes 注解全自动签发。
- 跨命名空间 CA 同步:无需再手动将平台根 CA 复制到每个业务命名空间。根 CA 证书会自动同步,让服务能够轻松验证彼此的身份。
- 自动化生命周期管理:借助
cert-manager,证书不仅会自动签发,还会在到期前无缝续期,从而最大限度地降低运维开销,并避免因证书过期而导致服务中断。
- 标准化安全性:确保 TLS 证书使用统一且集中管理的
ClusterIssuer 生成,从而在平台上的所有应用之间维持一致的安全标准。
配置和部署(管理员)
为实现上述功能,平台系统管理员需要预先为 Kyverno 配置相关准入策略 (ClusterPolicy) 和必要的 RBAC 权限。
前提条件
在继续操作之前,请确保集群已安装并启用 Alauda Container Platform Policy Management(之前称为 Alauda Container Platform Compliance for Kyverno)插件。有关安装详情,请参阅安装 Compliance 插件。
1. 配置 RBAC 权限
若要授予 Kyverno 创建相应资源和调用相关接口的权限,请将以下权限聚合到平台的后台控制器:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
rbac.kyverno.io/aggregate-to-background-controller: "true"
rbac.kyverno.io/aggregate-to-admission-controller: "true"
rbac.kyverno.io/aggregate-to-reports-controller: "true"
name: kyverno:serving-certs
rules:
- apiGroups:
- cert-manager.io
resources:
- certificates
verbs:
- create
- update
- delete
- get
- list
- watch
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- update
- delete
- get
- list
- watch
2. 创建证书
创建以下 Certificate 资源,将其用作服务根 CA:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: service-root-ca
namespace: cert-manager
spec:
commonName: ServiceRootCA
isCA: true
issuerRef:
kind: ClusterIssuer
name: cpaas-ca
secretName: service-root-ca
3. 配置 Kyverno 策略
创建并应用以下三个核心 ClusterPolicy 资源:
- clone-ca-secret:监听 Namespace 创建事件,并为新命名空间生成
service-root-ca Secret 资源。
- sync-ca-rotation:监听
service-root-ca 的变更,通过 API 获取实际 CA 证书内容,并将 ca.crt 值同步到目标命名空间中的 Secret。
- generate-service-cert:监听带有
service.alauda.io/serving-cert-secret-name 注解的 Service 资源,并根据其名称和命名空间生成支持泛域名的 Certificate 签发请求。
将以下 YAML 内容保存为文件并执行应用 (kubectl apply -f):
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: clone-ca-secret
spec:
background: true
rules:
- name: generate-ca-secret-shell
match:
any:
- resources:
kinds:
- Namespace
exclude:
any:
- resources:
namespaces:
- kube-system
- cpaas-system
- cert-manager
generate:
apiVersion: v1
kind: Secret
name: service-root-ca
namespace: "{{request.object.metadata.name}}"
synchronize: true
generateExisting: true
data:
kind: Secret
type: Opaque
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
generate.kyverno.io/policy-name: clone-ca-secret
- name: initial-sync-on-creation
match:
any:
- resources:
kinds:
- Secret
names:
- service-root-ca
exclude:
any:
- resources:
namespaces:
- cert-manager
- kube-system
- cpaas-system
context:
- name: cacrt
apiCall:
method: GET
urlPath: "/api/v1/namespaces/cert-manager/secrets/service-root-ca"
jmesPath: 'data."ca.crt"'
mutate:
patchStrategicMerge:
data:
ca.crt: "{{ cacrt }}"
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: sync-ca-rotation
spec:
mutateExistingOnPolicyUpdate: true
background: true
rules:
- name: rotation-sync
match:
any:
- resources:
kinds:
- Secret
namespaces:
- cert-manager
names:
- service-root-ca
mutate:
targets:
- apiVersion: v1
kind: Secret
name: service-root-ca
selector:
matchLabels:
app.kubernetes.io/managed-by: kyverno
generate.kyverno.io/policy-name: clone-ca-secret
patchStrategicMerge:
data:
ca.crt: '{{ request.object.data."ca.crt" }}'
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: generate-service-cert
spec:
background: true
rules:
- name: generate-cert
match:
any:
- resources:
kinds:
- Service
annotations:
service.alauda.io/serving-cert-secret-name: "?*"
generate:
apiVersion: cert-manager.io/v1
kind: Certificate
name: "{{request.object.metadata.name}}-cert"
namespace: "{{request.object.metadata.namespace}}"
synchronize: true
data:
spec:
secretName: '{{request.object.metadata.annotations."service.alauda.io/serving-cert-secret-name"}}'
issuerRef:
name: cpaas-ca
kind: ClusterIssuer
dnsNames:
- "{{request.object.metadata.name}}"
- "{{request.object.metadata.name}}.{{request.object.metadata.namespace}}"
- "{{request.object.metadata.name}}.{{request.object.metadata.namespace}}.svc"
- "{{request.object.metadata.name}}.{{request.object.metadata.namespace}}.svc.cluster.local"
用户指南(面向开发人员)
对于应用开发人员而言,在底层集群策略配置完成后,无需关注底层证书签发逻辑。您只需在定义业务 Service 资源时添加专用注解,即可实现证书自动配置:
- 为 Service 添加注解
在业务命名空间(例如 my-namespace)下,创建或更新 Service,并添加 service.alauda.io/serving-cert-secret-name 注解,以指定生成的证书 Secret 名称。例如:
apiVersion: v1
kind: Service
metadata:
name: my-secure-service
namespace: my-namespace
annotations:
service.alauda.io/serving-cert-secret-name: "my-secure-service-tls" # Will generate a certificate Secret named my-secure-service-tls for you
spec:
ports:
- port: 443
targetPort: 8443
selector:
app: my-app
- 验证生成的证书 Secret
应用上述 Service 后:
- 检查命名空间中是否存在自动生成的 TLS 证书 Secret:
kubectl get secret my-secure-service-tls -n my-namespace
- 检查用于验证的根 CA 证书是否也已自动复制到当前命名空间:
kubectl get secret service-root-ca -n my-namespace
- 在 Pod 中挂载并使用证书
由于 CA 证书 Secret(service-root-ca)和当前应用的 TLS 服务证书 Secret(my-secure-service-tls)均已就绪,因此可以将它们作为数据卷挂载到目标应用的 Deployment 或 StatefulSet 等工作负载中。
以下是一个具体的 Deployment YAML 示例,演示如何挂载这些证书:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: my-namespace
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app-container
image: my-app-image:latest
volumeMounts:
# Mount the serving certificate
- name: tls-cert
mountPath: "/etc/tls/certs"
readOnly: true
# Mount the root CA certificate
- name: root-ca
mountPath: "/etc/tls/ca"
readOnly: true
volumes:
# Reference the automatically generated Service certificate Secret
- name: tls-cert
secret:
secretName: my-secure-service-tls
# Reference the automatically synchronized CA certificate Secret
- name: root-ca
secret:
secretName: service-root-ca
有关通过 Web 控制台配置工作负载的更多详细信息,请参阅配置容器部分。