Service Serving Certificate

Overview

Service 服务端证书为容器云平台中的 Service 提供自动化的 TLS 证书生成和管理功能。该能力实现了内部组件之间的安全 HTTPS 通信和流量加密,保障数据隐私和系统安全。

Features

该自动化证书配置机制具备以下关键特性:

  • 零接触配置:开发者无需手动生成证书签名请求(CSR)或与证书颁发机构交互。证书颁发通过标准 Kubernetes 注解实现全自动化。
  • 跨命名空间 CA 同步:免去手动将平台根 CA 复制到每个业务命名空间的繁琐操作。根 CA 证书自动同步,使服务间轻松验证身份。
  • 自动生命周期管理:借助 cert-manager,证书不仅自动颁发,还能在到期前无缝续期,降低运维负担,避免因证书过期导致的服务中断。
  • 安全标准统一:确保 TLS 证书由统一的、集中管理的 ClusterIssuer 生成,维护平台上所有应用的一致安全标准。

Configuration and Deployment (For Administrators)

为实现上述功能,平台系统管理员需提前配置 Kyverno 相关的准入策略(ClusterPolicy)及必要的 RBAC 权限。

Prerequisites

操作前请确保集群已安装并启用 Alauda Container Platform Compliance with Kyverno 插件。安装详情请参见 Install Compliance Plugin

1. Configure RBAC Permissions

为赋予 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. Create Certificate

创建以下 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. Configure Kyverno Policies

创建并应用以下三个核心 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"

User Guide (For Developers)

对于应用开发者,底层集群策略配置完成后,无需关心底层证书颁发逻辑。只需在定义业务 Service 资源时添加专属注解,即可实现自动证书配置:

  1. 为 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" # 将为您生成名为 my-secure-service-tls 的证书 Secret
spec:
  ports:
    - port: 443
      targetPort: 8443
  selector:
    app: my-app
  1. 验证生成的证书 Secret

应用上述 Service 后:

  • 检查自动生成的 TLS 证书 Secret 是否存在于命名空间:
    kubectl get secret my-secure-service-tls -n my-namespace
  • 检查用于验证的根 CA 证书是否也已自动复制到当前命名空间:
    kubectl get secret service-root-ca -n my-namespace
  1. 在 Pod 中挂载并使用证书

由于 CA 证书 Secret(service-root-ca)和当前应用的 TLS 服务端证书 Secret(my-secure-service-tls)均已就绪,您可以在目标应用的 DeploymentStatefulSet 等工作负载中,将它们作为数据卷挂载。

以下是一个具体的 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:
            # 挂载服务端证书
            - name: tls-cert
              mountPath: "/etc/tls/certs"
              readOnly: true
            # 挂载根 CA 证书
            - name: root-ca
              mountPath: "/etc/tls/ca"
              readOnly: true
      volumes:
        # 引用自动生成的 Service 证书 Secret
        - name: tls-cert
          secret:
            secretName: my-secure-service-tls
        # 引用自动同步的 CA 证书 Secret
        - name: root-ca
          secret:
            secretName: service-root-ca

更多关于通过 Web 控制台配置工作负载的详情,请参见 Configure Containers 部分。