• Русский
  • Service Serving Certificate

    Обзор

    Сертификаты обслуживания сервиса обеспечивают автоматическую генерацию и управление TLS-сертификатами для Services в платформе контейнерного облака. Эта возможность позволяет организовать защищённое HTTPS-соединение и зашифрованный трафик между внутренними компонентами, обеспечивая конфиденциальность данных и безопасность системы.

    Особенности

    Механизм автоматического предоставления сертификатов включает следующие ключевые возможности:

    • Автоматическое предоставление без участия пользователя: разработчикам не нужно вручную создавать запросы на подпись сертификатов (CSR) или взаимодействовать с центрами сертификации. Выпуск сертификатов полностью автоматизирован с помощью стандартных аннотаций Kubernetes.
    • Синхронизация CA между неймспейсами: устраняет необходимость вручную копировать корневой CA платформы в каждый бизнес-неймспейс. Корневой сертификат CA автоматически синхронизируется, позволяя сервисам легко проверять подлинность друг друга.
    • Автоматическое управление жизненным циклом: с использованием cert-manager сертификаты не только автоматически выдаются, но и своевременно обновляются до истечения срока действия, что минимизирует операционные затраты и предотвращает простои из-за просроченных сертификатов.
    • Стандартизированная безопасность: гарантирует, что TLS-сертификаты генерируются с использованием единого централизованного ClusterIssuer, поддерживая единые стандарты безопасности для всех приложений на платформе.

    Конфигурация и развертывание (для администраторов)

    Для реализации вышеуказанных функций системным администраторам платформы необходимо заранее подготовить соответствующие политики допуска (ClusterPolicy) для Kyverno и необходимые RBAC-разрешения.

    Предварительные требования

    Перед началом убедитесь, что в вашем кластере установлен и включён плагин Alauda Container Platform Compliance with Kyverno. Подробности установки смотрите в разделе Install 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 и генерирует Secret service-root-ca для новых неймспейсов.
    • sync-ca-rotation: отслеживает изменения в service-root-ca, получает реальное содержимое сертификата CA через API и синхронизирует значение ca.crt в Secret целевого неймспейса.
    • generate-service-cert: отслеживает ресурсы Service с аннотацией service.alauda.io/serving-cert-secret-name и генерирует запрос на выпуск Certificate с поддержкой wildcard-доменов на основе имени и неймспейса.

    Сохраните следующий 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" # Будет сгенерирован Secret с сертификатом с именем my-secure-service-tls
    spec:
      ports:
        - port: 443
          targetPort: 8443
      selector:
        app: my-app
    1. Проверьте созданный Secret с сертификатом

    После применения вышеуказанного Service:

    • Проверьте наличие автоматически созданного TLS-секрета в неймспейсе:
      kubectl get secret my-secure-service-tls -n my-namespace
    • Проверьте, что корневой сертификат CA, используемый для проверки, также автоматически скопирован в текущий неймспейс:
      kubectl get secret service-root-ca -n my-namespace
    1. Монтирование и использование сертификата в Pod

    Поскольку Secret с сертификатом CA (service-root-ca) и TLS-сертификат текущего приложения (my-secure-service-tls) уже присутствуют, вы можете смонтировать их как тома данных в рабочие нагрузки, например, в Deployment или StatefulSet вашего приложения.

    Ниже приведён пример YAML для Deployment, демонстрирующий, как смонтировать эти сертификаты:

    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:
            # Ссылка на автоматически созданный Secret с сертификатом сервиса
            - name: tls-cert
              secret:
                secretName: my-secure-service-tls
            # Ссылка на автоматически синхронизированный Secret с сертификатом CA
            - name: root-ca
              secret:
                secretName: service-root-ca

    Для получения дополнительной информации о конфигурации рабочих нагрузок через веб-консоль смотрите раздел Configure Containers.