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 资源时,只需添加专属注解,即可自动配置证书:

  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" # Will generate a certificate Secret named my-secure-service-tls for you
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)均已就绪,因此可以将它们作为数据卷挂载到目标应用的 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 控制台配置工作负载的更多详情,请参阅配置容器部分。