Создание сертификатов для Ingress объектов
1. Цель
Целью данной статьи является создание сертификатов для Ingress объектов, включая этапы:
-
Создание ресурса Issuer типа
SelfSigned
в cert-manager; -
Создание ресурса Ingress с аннотацией к созданному Issuer, который будет автоматически выпускать сертификаты для Ingress.
2. Cert-manager
cert-manager создает сертификаты TLS для рабочих нагрузок в кластере Kubernetes или в платформе Nova и обновляет сертификаты до истечения срока их действия.
cert-manager может получать сертификаты от различных центров сертификации, включая: StarVault, Let’s Encrypt, HashiCorp Vault, Venafi и частные PKI.
С помощью ресурса сертификатов cert-manager’а, закрытый ключ и сертификат хранятся в Kubernetes Secret, который монтируется приложением Pod или используется контроллером Ingress. При использовании csi-driver, csi-driver-spiffe или istio-csr закрытый ключ генерируется по требованию, перед запуском приложения. Закрытый ключ никогда не покидает узел и не хранится в Kubernetes Secret.
cert-manager уже предустановлен в платформу nova в пространство имен nova-cert-managment
3. Issuers
Issuers
и ClusterIssuers
- это ресурсы Kubernetes, представляющие центры сертификации (ЦС)
, которые могут генерировать подписанные сертификаты, выполняя запросы на подписание сертификатов. Все сертификаты cert-manager требуют наличия аннотации к Issuer.
Примером типа Issuer
является ЦС
. Простой ЦС
Issuer выглядит следующим образом:
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: ca-issuer
namespace: sandbox
spec:
ca:
secretName: ca-key-pair
Это простой Issuer
, который будет подписывать сертификаты на основе закрытого ключа. Сертификат, хранящийся в секрете ca-key-pair
, может использоваться для доверия к новым сертификатам, подписанным этим Issuer
, в системе инфраструктуры открытых ключей (PKI).
4. SelfSigned Issuers
⚠️ Самоподписанные SelfSigned
Issuers обычно полезны для локальной загрузки PKI, что является сложной темой для опытных пользователей. Для безопасного использования в производстве запуск PKI вводит сложные требования к планированию ротации, распределению доверенного хранилища и аварийному восстановлению.
Если вы не планируете запускать собственную PKI, используйте другой Issuer тип.
SelfSigned
Issuer не представляет собой центр сертификации как таковой, а вместо этого обозначает, что сертификаты будут "подписывать себя сами", используя заданный закрытый ключ. Другими словами, закрытый ключ сертификата будет использоваться для подписи самого сертификата.
Этот тип Issuer полезен для создания корневого сертификата для пользовательской PKI (Public Key Infrastructure - инфраструктура открытых ключей) или для создания простых специальных сертификатов для быстрого тестирования.
При использовании SelfSigned
Issuer следует учитывать важные предостережения, в том числе вопросы безопасности. В общем случае вам лучше использовать ЦС
Issuer, а не SelfSigned
Issuer. Тем не менее, SelfSigned
Issuer очень полезен для первоначальной установки ЦС
Issuer.
Примечание: CertificateRequest, ссылающийся на самоподписанный сертификат, должен также содержать аннотацию cert-manager.io/private-key-secret-name, поскольку закрытый ключ, соответствующий CertificateRequest, необходим для подписи сертификата. Эта аннотация добавляется автоматически контроллером сертификатов.
4.1. Развертывание
Поскольку SelfSigned
Issuer не зависит ни от какого другого ресурса, его проще всего настроить. В спецификации Issuer должна присутствовать только строка SelfSigned, других настроек не требуется:
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
namespace: sandbox
spec:
selfSigned: {}
Пример SelfSigned
Issuer для всего кластера:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-cluster-issuer
spec:
selfSigned: {}
После развертывания вы должны сразу увидеть, что Issuer готов к подписанию:
$ kubectl get issuers -n sandbox -o wide selfsigned-issuer
NAME READY STATUS AGE
selfsigned-issuer True 2m
$ kubectl get clusterissuers -o wide selfsigned-cluster-issuer
NAME READY STATUS AGE
selfsigned-cluster-issuer True 3m
4.2. Установка ЦС
issuers
Одним из идеальных вариантов использования SelfSigned
Issuers является загрузка пользовательского корневого сертификата для частной PKI вместе с ЦС
Issuer.
Приведенный ниже манифест создаст SelfSigned
Issuer, выпустит корневой сертификат и будет использовать этот корень в качестве ЦС
issuer:
apiVersion: v1
kind: Namespace
metadata:
name: sandbox
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-selfsigned-ca
namespace: nova-cert-managment
spec:
isCA: true
commonName: my-selfsigned-ca
secretName: root-secret
privateKey:
algorithm: ECDSA
size: 256
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: my-ca-issuer
namespace: sandbox
spec:
ca:
secretName: root-secret
ClusterIssuer "selfsigned-issuer" используется для выпуска корневого Certificate
ЦС. Этот сертификат хранится в секрете root-secret, который содержит сам корневой сертификат ca.crt
, подписанный сертификат tls.crt
(значение которого будет равняться ca.crt, т.к. он самоподписанный) и приватный ключ tls.key
. Затем ClusterIssuer "my-ca-issuer" используется для выпуска, а также для подписи сертификатов с использованием только что созданного корневого Certificate
ЦС, который вы будете использовать для будущих сертификатов в масштабах всего кластера.
4.3. Точки распространения CRL
Вы также можете указать точки распространения CRL (Certificate revocation list - список отозванных сертификатов) в виде массива строк, каждая из которых идентифицирует местоположение CRL, в котором можно проверить статус отзыва выпущенных сертификатов:
...
spec:
selfSigned:
crlDistributionPoints:
- "http://example.com"
4.4. Предостережения
4.4.1. Доверие
Клиенты, использующие SelfSigned
сертификаты, не могут доверять им, не имея предварительно сертификатов, что может быть затруднительно, если клиент находится в другом пространстве имен, чем сервер.
Это ограничение можно устранить, используя trust-manager для распространения ca.crt
в другие пространства имен.
Безопасной альтернативы решению проблемы распространения хранилищ доверия не существует. Можно использовать сертификат "TOFU" (trust-on-first-use), но такой подход уязвим для атак типа "человек посередине" (man-in-the-middle).
4.4.2. Срок действия сертификата
Одним из побочных эффектов самоподписания сертификата является то, что его Subject DN и Issuer DN идентичны. Раздел 4.1.2.4 стандарта X.509 RFC 5280 требует, чтобы:
Поле издателя ДОЛЖНО содержать непустое отличительное имя (DN).
Однако самоподписанные сертификаты по умолчанию не имеют DN субъекта. Если вы не зададите вручную Subject DN сертификата, то Issuer DN будет пустым, и сертификат будет технически недействительным.
Проверка этой конкретной области спецификации неравномерна и варьируется между библиотеками TLS, но всегда есть риск, что в будущем библиотека улучшит свою проверку - полностью в рамках спецификации - и сломает ваше приложение, если вы используете сертификат с пустым Issuer DN.
Чтобы избежать этого, обязательно задайте Subject для самоподписных сертификатов. Это можно сделать, задав spec.subject
объекту сертификат
в cert-manager, который будет выпущен SelfSigned
Issuer.
Начиная с версии 1.3, cert-manager будет выдавать предупреждающее событие Kubernetes типа BadConfig
, если обнаружит, что сертификат создается SelfSigned
Issuer, у которого пустой Issuer DN.
5. Аннотация к Ingress ресурсу
Частым случаем использования cert-manager является запрос сертификатов, подписанных TLS, для защиты ваших Ingress ресурсов. Это можно сделать, просто добавив аннотации к вашим ресурсам Ingress, и cert-manager облегчит создание ресурса сертификата для вас. За это отвечает небольшой подкомпонент cert-manager, ingress-shim.
5.1. Как это работает
Подкомпонент ingress-shim следит за ресурсами Ingress
в вашем кластере. Если он обнаружит Ingress
с аннотациями, описанными в разделе Поддерживаемые аннотации, он проверит, что в том же пространстве имен, где находится ресурс Ingress
, существует ресурс Certificate
с именем, указанным в поле tls.secretName
и настроенным, как описано в этом Ingress
.
Приведенный ниже манифест создаст Ingress ресурс с привязкой к ранее созданному Issuer my-ca-issuer
:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
# добалвение аннотации, указывающей какой _Issuer_ ипсользовать
cert-manager.io/issuer: my-ca-issuer
name: my-ingress
namespace: sandbox
spec:
rules:
- host: example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: myservice
port:
number: 80
tls: # < Размещение хоста в конфигурации TLS будет определять, что будет содержаться в subjectAltNames сертификата
- hosts:
- example.com
secretName: myingress-cert # < cert-manager будет хранить сертификат в этом секрете store.
5.2. Поддерживаемые аннотации
Вы можете указать следующие аннотации для ресурсов Ingress, чтобы вызвать автоматическое создание ресурсов сертификатов:
-
cert-manager.io/issuer
: имя Issuer, который должен выпустить сертификат, необходимый для данного Ingress
⚠️ Эта аннотация не предполагает наличие Issuer с привязкой к пространству имен. По умолчанию будет использоваться cert-manager.io Issuer, однако в случае внешних типов Issuers это должно быть использовано как для типов Issuers с привязкой к пространству имен, так и для типов Issuers с привязкой ко всему кластеру.
⚠️ Если используется Issuer для пространства имен, то он должен находиться в том же пространстве имен, что и ресурс Ingress.
-
cert-manager.io/cluster-issuer
: имя ClusterIssuer для получения сертификата, необходимого для этого Ingress. Не имеет значения, в каком пространстве имен находится ваш Ingress, так как ClusterIssuers - это ресурс с привязкой ко всему кластеру.
⚠️ Эта аннотация является сокращением для ссылки на cert-manager.io ClusterIssuer без необходимости указывать группу и тип. Она не предназначена для указания внешнего Issuer с кластерной привязкой - для этого используйте аннотацию cert-manager.io/issuer.
-
cert-manager.io/issuer-kind
: тип внешнего ресурса Issuer, напримерAWSPCAIssuer
. Это необходимо только для не стандартных Issuer. -
cert-manager.io/issuer-group
: группа API контроллера внешнего Issuer, например awspca.cert-manager.io. Это необходимо только для не стандартных Issuer. -
cert-manager.io/common-name
: (необязательно) эта аннотация позволяет настроитьspec.commonName
для генерируемого сертификата.
Другие поддерживаемые опциональные аннотации вы можете найти на оффициальном сайте.
5.3. Генерация нескольких сертификатов с несколькими Ingress
Если вам нужно сгенерировать сертификаты из нескольких Ingress, убедитесь, что они имеют аннотацию Issuer. Помимо аннотации, необходимо, чтобы каждый Ingress обладал уникальным именем tls.secretName
5.4. Устранение неполадок
Если после применения аннотаций ingress-shim ресурс Certificate
не создается, проверьте, установлен ли хотя бы cert-manager.io/issuer
или cert-manager.io/cluster-issuer
. Если вы хотите использовать kubernetes.io/tls-acme: "true"
, убедитесь, что проверили все шаги выше, и, возможно, захотите поискать ошибки в логах cert-manager pod, если они не устранены.