Установка и настройка cert-manager

2024-08-13

1. Настройка FreeIPA для работы с Cert-manager по протоколу ACME

1.1. Включение ACME

  1. Для включения протокола ACME для IPA-домена, выполните следующие команды на одной из IPA-реплик:

    [[ $(ipa-acme-manage status -q) = 'ACME is disabled' ]] && ipa-acme-manage enable

1.2. Подготовка переменных

  1. Задайте переменную с именем целевого домена:

    SUBDOMAIN_NAME='k8s.example.org'

1.3. Создание TSIG-ключа для удалённого обновления DNS-зоны

  1. Сгенерируйте TSIG-ключ, добавьте его в настройки Named и перезапустите демон:

    TSIG_KEY_NAME="${SUBDOMAIN_NAME}-acme"
    
    tsig-keygen -a hmac-sha512 ${TSIG_KEY_NAME} | tee -a /etc/named/ipa-ext.conf
    systemctl restart named
    stdout:
    key "k8s.example.org-acme" {
            algorithm hmac-sha512;
            secret "1oDJxfU16OOPUN4exDwivoDx22rTUYwTtWwL3yisBcUyUTEcgwPmHph7KFiq04evzPOcP8hDMc+0UwPNGyuGpg==";
    };
  2. Скопируйте сгенерированный TSIG-ключ на все IPA-реплики с перезапуском демона 'named'.

1.4. Добавление DNS-зоны при необходимости

  1. Если зона для поддомена в DNS не существует, то создайте зону с опциями динамического обновления и синхронизации записей в обратной зоне:

    ipa dnszone-add ${SUBDOMAIN_NAME} \
      --allow-sync-ptr=1 \
      --dynamic-update=1
    stdout:
    Zone name: k8s.example.org.
    Active zone: True
    Authoritative nameserver: dev-ipa01.example.org.
    Administrator e-mail address: hostmaster
    SOA serial: 1723470918
    SOA refresh: 3600
    SOA retry: 900
    SOA expire: 1209600
    SOA minimum: 3600
    BIND update policy: grant EXAMPLE.ORG krb5-self * A; grant EXAMPLE.ORG krb5-self * AAAA; grant EXAMPLE.ORG krb5-self * SSHFP;
    Dynamic update: True
    Allow query: any;
    Allow transfer: none;
    Allow PTR sync: True
  2. Разрешите обновление зоны по TSIG-ключу для записей типа TXT. Если указать ANY, то выдаются излишне широкие права, тогда как cert-manager будет добавлять только записи типа TXT и записи '_acme-challenge' с длинным символьно-цифровым значением.

    ACME_POLICY="grant ${TSIG_KEY_NAME} subdomain ${SUBDOMAIN_NAME} TXT;"
    
    # Получаем текущие политики для DNS-зоны.
    CURRENT_UPDATE_POLICY="$(ipa dnszone-show ${SUBDOMAIN_NAME} --raw | grep idnsupdatepolicy)"
    # idnsupdatepolicy: grant EXAMPLE.ORG krb5-self * A; \
    # grant EXAMPLE.ORG krb5-self * AAAA; \
    # grant EXAMPLE.ORG krb5-self * SSHFP;
    
    # Обрезаем начало строки до двоеточия и пробела
    # и добавляем ещё одну политику к текущим политикам.
    NEW_UPDATE_POLICY="${CURRENT_UPDATE_POLICY#*: } ${ACME_POLICY}"
    # grant EXAMPLE.ORG krb5-self * A; \
    # grant EXAMPLE.ORG krb5-self * AAAA; \
    # grant EXAMPLE.ORG krb5-self * SSHFP; \
    # grant k8s.example.org-acme-update subdomain k8s.example.org TXT;
    
    # Обновляем политики новым значением.
    ipa dnszone-mod ${SUBDOMAIN_NAME} \
      --update-policy="${NEW_UPDATE_POLICY}"
    stdout:
    Zone name: k8s.example.org.
    Active zone: True
    Authoritative nameserver: dev-ipa01.example.org.
    Administrator e-mail address: hostmaster
    SOA serial: 1716816431
    SOA refresh: 3600
    SOA retry: 900
    SOA expire: 1209600
    SOA minimum: 3600
    BIND update policy: grant k8s.example.org-acme-update subdomain k8s.example.org TXT;
    Dynamic update: True
    Allow query: any;
    Allow transfer: none;

2. Cert-manager. Изменения в Helm Chart перед применением

  1. Найти и заменить?

    1. Все вхождения replicaCount: 1 увеличить до 2-3 в Production

    2. Все вхождения ВpodDisruptionBudget.enable: false изменить на true

  2. Добавьте volume-определения во всех вхождениях:

    volumes:
      - name: ca-bundle
        configMap:
          name: ca-example.org
    
    volumeMounts:
      - name: ca-bundle
        mountPath: /etc/ssl/certs/ca-certificates.crt
        subPath: ca-certificates.crt
        readOnly: false
  3. Добавьте опцию '--enable-gateway-api'. :title: Cert-manager. Применение Helm Chart :docdate: 2024-05-23

3. Cert-manager. Применение Helm Chart

3.1. Заметки

  1. cert-manager не использует официальный метод helm для установки ресурсов CRD. По той причине, что это делает модернизацию CRD невозможно с helm Только CLI. Объяснение ограничения этого подхода здесь .

  2. CRD установим отдельно с помощью kubectl. В этом случае, CRD не будет изменено или удалено при манипуляциях с cert-manager через helm. А это значит, что выданные сертификаты и другие объекты не будут удалены в этом случае. Есть небольшой минус: при обновлении cert-manager через helm, CRD необходимо обновлять вручную через kubectl.

3.2. Установка CRD с помощью kubectl

  1. Выполните:

    kubectl apply -f cert-manager.crds.yaml
    stdout:
    customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
    customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
    customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
    customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
    customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
    customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created

3.3. Установка cert-manager с помощью helm

  1. Выполните:

    helm install \
      cert-manager . \
      --namespace cert-manager \
      --create-namespace
    stdout:
    NAME: cert-manager
    LAST DEPLOYED: Fri May 24 14:45:36 2024
    NAMESPACE: cert-manager
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    NOTES:
    cert-manager v1.14.5 has been deployed successfully!
    
    In order to begin issuing certificates, you will need to set up a ClusterIssuer
    or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).
    
    More information on the different types of issuers and how to configure them
    can be found in our documentation:
    
    https://cert-manager.io/docs/configuration/
    
    For information on how to configure cert-manager to automatically provision
    Certificates for Ingress resources, take a look at the `ingress-shim`
    documentation:
    
    https://cert-manager.io/docs/usage/ingress/

3.4. Установка утилиты cmctl

  1. Обновите утилиту в локальном репозитории.

  2. Выполните скачивание утилиты на, например, control plane ноду и установите в /usr/local/bin:

    curl -LOu $USER_PASS https://nexus.example.org:8081/repository/evo_raw/kubernetes/cert-manager/cmctl_linux_amd64
    install cmctl_linux_amd64 /usr/local/bin/cmctl

4. Cert-manager. Настройка получения сертификатов из FreeIPA

Использованные материалы

4.1. Добавление TSIG-ключа в именованное пространство cert-manager’а

  1. Добавьте в Kubernetes ранее сгенерированный для FreeIPA TSIG-ключ командой:

    NAMESPACE='cert-manager'
    SUBDOMAIN_NAME='k8s.example.org'
    SECRET_NAME="tsig-${SUBDOMAIN_NAME}-acme"
    SECRET_KEY_NAME='tsig-key'
    # TSIG_KEY возьмите из `/etc/named/ipa-ext.conf` на любой IPA-реплике
    TSIG_KEY='1oDJxfU16OOPUN4exDwivoDx22rTUYwTtWwL3yisBcUyUTEcgwPmHph7KFiq04evzPOcP8hDMc+0UwPNGyuGpg=='
    
    kubectl --namespace ${NAMESPACE} create secret generic ${SECRET_NAME} \
    --from-literal=${SECRET_KEY_NAME}=$(echo ${TSIG_KEY} | base64 -w0)

4.2. Добавление сертификата Центра Сертификации FreeIPA в именованное пространство cert-manager’а

  1. На любой машине, введённой в домен FreeIPA, можно найти сертификат Центра Сертификации в файле /etc/ipa/ca.crt. В данном примере, K8s-хост, где производились работы, принадлежит другому домену, поэтому файл ca.crt был скопирован с FreeIPA-сервера и помещён в файл ca-example.org.crt в рабочий каталог.

  2. Добавьте этот файл в K8s, где его имя будет изменено на ca-certificates.crt. Проверить, такое имя необходимо для работы cert-manager?

    CONFIGMAP_NAME='ca-example.org'
    EXT_CA_CRT_FILE="/etc/ipa/ca.crt"
    INT_CA_CRT_FILE='ca-certificates.crt'
    
    kubectl --namespace cert-manager create configmap ${CONFIGMAP_NAME} \
      --from-file ${INT_CA_CRT_FILE}=${EXT_CA_CRT_FILE}

4.3. Создание выпускателя TLS-сертификатов

  1. По умолчанию на каждой IPA-реплике выпущен SAN 'ipa-ca.example.org' к TLS-сертификату на 443 порту, что позволяет обращаться по этому URL к любой IPA-реплике. Если в /etc/resolv.conf указана опция 'rotate', то обращение к 'ipa-ca.example.org' будет адресовано по очереди к каждому IPA-серверу.

  2. Создайте и примените манифест:

    ACME_URI='https://ipa-ca.example.org/acme/directory'
    DNS_VIP='10.0.0.53'
    SUBDOMAIN_NAME='k8s.example.org'
    TSIG_KEY_NAME="${SUBDOMAIN_NAME}-acme"
    
    cat << EOF > issuer.yaml
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: ${SUBDOMAIN_NAME}
      namespace: cert-manager
    spec:
      acme:
        email: admin@${SUBDOMAIN_NAME}
        server: ${ACME_URI}
        privateKeySecretRef:
          name: ipa-issuer-account-key
        solvers:
          - dns01:
              rfc2136:
                nameserver: ${DNS_VIP}
                tsigKeyName: ${TSIG_KEY_NAME}
                tsigAlgorithm: HMACSHA512
                tsigSecretSecretRef:
                  name: ${SECRET_NAME}
                  key: ${SECRET_KEY_NAME}
            selector:
              dnsZones:
                - ${SUBDOMAIN_NAME}
    EOF

5. Тестовый запрос сертификата

  1. Создайте манифест и примените его:

    HOST_NAME='host5.k8s.example.org'
    CLUSTER_ISSUER_NAME='ipa-example.org'
    
    cat << EOF > getcert_${HOST_NAME}.yaml
    ---
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: cert-${HOST_NAME}
      namespace: default
    spec:
      commonName: "${HOST_NAME}"
      dnsNames:
        - ${HOST_NAME}
      issuerRef:
        name: ${CLUSTER_ISSUER_NAME}
        kind: ClusterIssuer
      privateKey:
        algorithm: RSA
        encoding: PKCS1
        size: 4096
      secretName: ${HOST_NAME}
    EOF
    
    kubectl apply -f getcert_${HOST_NAME}.yaml
  2. Выпуск сертификата занимает на данный момент примерно пару минут.