Service 服务端证书
概述
Service 服务端证书为容器云平台中的 Service 提供自动化 TLS 证书生成和管理功能。此功能支持安全的 HTTPS 通信以及内部组件之间的流量加密,确保数据隐私和系统安全。
功能特性
此自动化证书签发机制提供以下主要功能:
- 零接触签发:开发者无需手动生成证书签名请求(CSR),也无需与证书颁发机构交互。证书签发通过标准 Kubernetes 注解实现全自动化。
- 跨命名空间 CA 同步:无需再手动将平台根 CA 复制到每个业务命名空间,从而消除相关繁琐操作。根 CA 证书会自动同步,使服务能够轻松验证彼此的身份。
- 自动化生命周期管理:利用
cert-manager 确保证书不仅能够自动签发,还能在过期前无缝续期,最大限度降低运维开销,并防止因证书过期导致服务中断。
- 标准化安全性:确保 TLS 证书通过统一、集中管理的
ClusterIssuer 生成,在平台上的所有应用之间保持一致的安全标准。
配置和部署(管理员)
要实现上述功能,平台系统管理员需要提前为 Kyverno 配置相关准入策略(ClusterPolicy)以及必要的 RBAC 权限。
前提条件
开始操作前,请确保已在集群中安装并启用 Alauda Container Platform Policy Management 插件。有关安装详情,请参阅安装 Compliance Plugin。
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 控制台配置工作负载的更多详情,请参阅配置容器部分。