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

  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 控制台配置工作负载的更多详细信息,请参阅配置容器部分。