Kubernetes авто-генерируемые SSL сертификаты LetEncrypt

Работая с Kubernetes скорее всего вы сталкивались с ситуацией когда вам нужно обеспечить HTTPS соединение для вашего ingress домена. Тут я опишу процесс автоматического выписывания TLS сертификатов в вашем Kubernetes кластере.

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

Для успешного понимание вам потребуется следующее:

  • Helm 3 - для управления зависимостями вашего кластера;
  • Kubernetes cluster - собственно кластер. где мы будем конфигурировать авто-генерацию сертификатов;
  • Kubectl - для управление вашим кластером.

Шаг 0: Подготовка

Вы вполне можете практиковать шаги нище на уже существующем неймспейсе, но в целях идентичности рекомендую создать отдельный неймспейс в котором мы будем запускать наш менеджер сертификатов:

kubectl create namespace cert-manager

Далее, с помощью Helm мы устанавливаем инструмент который будет оперировать нашими сертификатами, для этого необходимо добавить новый Helm репозиторий:

helm repo add jetstack [https://charts.jetstack.io](https://charts.jetstack.io/)

После этого мы готовы установить cert-manager.

cert-manager - это Kubernetes расширение позволяющее автоматически выписывать и управлять TLS сертификатами из различных источников.

helm install certmanager --namespace cert-manager jetstack/cert-manager \ 
         --set ingressShim.defaultIssuerName=issuer-letsencrypt \
         --set ingressShim.defaultIssuerKind=ClusterIssuer

После установки проверяем результат:

helm list -n cert-manager

NAME           NAMESPACE   	 STATUS  	  CHART                  APP VERSION
certmanager    cert-manager	 deployed	  cert-manager-v1.1.0   v1.1.0

Выше, мы установили cert-manager в наш cert-manager неймспейс, но вы могли заметить что мы использовали два дополнительных параметра:

ingressShim.defaultIssuerName=issuer-letsencrypt - определяет имя для автоматического управления сертификатами. Далее мы будем использовать это имя для наших ingress конфигураций;

ingressShim.defaultIssuerKind=ClusterIssuer - определяет тип выписывания сертификатов.

Есть два типа IssuerKind:

  • Issuer - выписывает и управляет сертификатами в неймспейсе где он создан; Использовать повторно в разных неймспейсах невозможно.
  • ClusterIssuer - выписывает и управляет сертификатами всего кластера независимо от неймспейса. Для того чтобы cert-manager выписал новый сертификат нам необходимо указать соответствующую аннотацию, что мы рассмотрим на примере ниже.

Шаг 1. Создаем Issuer

Прежде всего, мы должны создать наш Issuer на основе которого cert-manager будет понимать как и кому выписывать сертификаты.

Устанавливая cert-manager выше мы указали ему имя по умолчанию **issuer-letsencrypt**, именно его он и будет использовать чтобы понимать какими Issuer он должен управлять.

Тип ClusterIssuer

Если мы хотим создать Issuer который будет выписывать сертификаты по всем неймспейсам кластера, тогда нужно создать Kubernetes Issuer типа ClusterIssuer.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: issuer-letsencrypt
  namespace: cert-manager
spec:
  acme:
    email: [your email address here]
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: issuer-letsencrypt
    solvers:
      - http01:
          ingress:
            class: nginx

Почти всегда эта конфигурация будет такой же за исключением ecme.email и acme.solvers.http01 если на вашем кластере Ingress Controller не Nginx, тогда вам нужно указать свой solver ingress class.

Также, мы создали этот Issuer в том же неймспейсе что и cert-manager для удобства, так как нет смысла класть его в любой другой неймспейс.

Тип Issuer

В случае когда по каким либо причинам мы хотим настроить изолировано выписывание сертификатов для конкретного неймспейса, тогда нам стоит использовать тип Issuer.

Обратите внимание что создавая Issuer с типом Issuer мы указываем namespace где он будет создан и именно там он будет выписывать сертификаты.

apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: issuer-letsencrypt
  namespace: staging
spec:
  acme:
    email: [your email address here]
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: issuer-letsencrypt
    solvers:
      - http01:
          ingress:
            class: nginx

Как вы могли заметить оба Issuer типа создаются с одинаковой структурой и свойствами, где важными есть:

  • metadata.name=issuer-letsencrypt - имя всех Issuer, которые будут управляться нашим cert-manager используя defaultIssuerName указанное при установки;
  • spec.acme.email - email который будет использоваться при подписании сертификатов;
  • spec.acme.server - есть два сервера production и staging:

Более детальная документация тут.

Шаг 2. Используем созданный Issuer

Ниже приведен реальный пример использования Issuer:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: issuer-letsencrypt
  name: [some-ingress-name]
  namespace: staging
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: [some-service-name]
          servicePort: 8080
        path: /
  tls:
  - hosts:
    - example.com
    secretName: [tls secret name]

Используя аннотацию: cert-manager.io/cluster-issuer: issuer-letsencrypt мы сообщаем cert-manager, что этот ingress объект будет управляться Issuer который мы создали выше.

Для лучшего понимания я опущу все что не влияет на cert-manager и оставлю те свойства, которые участвуют в том чтобы ingress успешно получил свой сертификат:

metadata:
  annotations:
    cert-manager.io/cluster-issuer: issuer-letsencrypt
    # или используйте эту аннотацию в случае если вы испольуете тип Issuer*
    cert-manager.io/issuer: issuer-letsencrypt
spec:
  tls:
  - hosts:
    - example.com
    secretName: [TLS secret name]

Помимо аннотации, мы также говорим как будет называться наш secret и для какого домена/хоста будет выписываться сертификат.

Теперь ваш домен должен поддерживать HTTPS.