Aws-cert-manager: различия между версиями
Sirmax (обсуждение | вклад) |
Sirmax (обсуждение | вклад) м (Sirmax переименовал страницу Aws LetsEncrypt в Aws-cert-manager) |
||
| (не показано 30 промежуточных версий этого же участника) | |||
| Строка 2: | Строка 2: | ||
[[Категория: K8s]] |
[[Категория: K8s]] |
||
[[Категория: EKS]] |
[[Категория: EKS]] |
||
| + | [[Категория: Ingress]] |
||
| + | [[Категория: SSL]] |
||
| + | [[Категория: LetsEncrypt]] |
||
| + | [[Категория: cert-manager]] |
||
| − | Для Ingress требуется автоматически выписывать |
+ | Для Ingress требуется автоматически выписывать сертификаты для доменов которые "Хостятся" на нем |
<BR> |
<BR> |
||
| Строка 16: | Строка 20: | ||
** Список возможных Issuers досаточно широк (https://cert-manager.io/docs/configuration/issuers/), для тестирования можно например использовать локально развернутый Hashicorp Vault |
** Список возможных Issuers досаточно широк (https://cert-manager.io/docs/configuration/issuers/), для тестирования можно например использовать локально развернутый Hashicorp Vault |
||
<BR> |
<BR> |
||
| − | * Использовать |
+ | * Использовать сертификаты от AWS (это пока не реализовано) |
=<code>cert-manager</code>= |
=<code>cert-manager</code>= |
||
| Строка 24: | Строка 28: | ||
* Установка в том чимсле создания <code>Custom Resource Definition</code> (далее <code>CRD</code>) |
* Установка в том чимсле создания <code>Custom Resource Definition</code> (далее <code>CRD</code>) |
||
* Cоздается ресусурс типа <code>Issuer</code> или <code>ClusterIssuer</code> — описывает, откуда брать сертификаты |
* Cоздается ресусурс типа <code>Issuer</code> или <code>ClusterIssuer</code> — описывает, откуда брать сертификаты |
||
| − | ** Разница в том что Issuer доступен только внутри namespace, в моем случае когда все |
+ | ** Разница в том что <code>Issuer</code> доступен только внутри namespace, в моем случае когда все сертификаты нужны для нескольких копий приложения ("окружений"), например <code>dev.domain.tld</code>, <code>staging.domain.tld</code>, <code>qa.domain.tld</code> нужно будет изменить <code>ClusterIssuer</code> на <code>Issuer</code>. Пока окружение одно это не важно, но как только их несколько то не хочется иметь один сертификат на всех с длинным списком Altnames (но это требует проверки) |
* После создания </code>Certificate</code>-ресурса — <code>cert-manager</code> следит за ним и выполняет выпуск согласно настройкам ресурса, результат сохраняет в <code>Secret</code> |
* После создания </code>Certificate</code>-ресурса — <code>cert-manager</code> следит за ним и выполняет выпуск согласно настройкам ресурса, результат сохраняет в <code>Secret</code> |
||
| Строка 31: | Строка 35: | ||
* делает HTTP или DNS-проверку чтобы подтвердить владение доменом (в этом случае HTTP так как у него нет доступа к управлению ресурсами зоны!) Как именно определено в поле <code>solvers</code> |
* делает HTTP или DNS-проверку чтобы подтвердить владение доменом (в этом случае HTTP так как у него нет доступа к управлению ресурсами зоны!) Как именно определено в поле <code>solvers</code> |
||
* получает сертификат от CA, определенного в поле <code>acme</code> |
* получает сертификат от CA, определенного в поле <code>acme</code> |
||
| − | * сохраняет в <code>Secret</code> |
+ | * сохраняет в <code>Secret</code> TODO |
* Мониторит и продлевает его до истечения срока действия. |
* Мониторит и продлевает его до истечения срока действия. |
||
| + | ==Возможные источники сертефикатов== |
||
| − | |||
| + | * https://cert-manager.io/docs/configuration/issuers/ |
||
==Установка== |
==Установка== |
||
<PRE> |
<PRE> |
||
| Строка 50: | Строка 55: | ||
</PRE> |
</PRE> |
||
| + | ==Пример <code>ClusterIssuer</code>== |
||
| − | ==2== |
||
| + | Достаточно простой объект |
||
| + | <PRE> |
||
apiVersion: cert-manager.io/v1 |
apiVersion: cert-manager.io/v1 |
||
kind: ClusterIssuer |
kind: ClusterIssuer |
||
metadata: |
metadata: |
||
| − | annotations: |
||
| − | creationTimestamp: "2025-06-01T11:56:58Z" |
||
| − | generation: 1 |
||
name: letsencrypt-http-cert-issuer |
name: letsencrypt-http-cert-issuer |
||
| − | resourceVersion: "329560" |
||
| − | uid: 4256d660-aa83-418e-b6d4-a5b6051943f0 |
||
spec: |
spec: |
||
acme: |
acme: |
||
| Строка 70: | Строка 72: | ||
ingress: |
ingress: |
||
class: nginx |
class: nginx |
||
| + | </PRE> |
||
| + | * имя можно выбрать произвольное |
||
| + | * <code>email: sirmax123@gmail.com</code> раньше был нужен что б Let's Encrypt мог прислать оповещение, но он уже давно это отключил и сецчас это просто ненужное но обязательное поле. |
||
| + | * <code>solvers</code> способ подтверждения владения доменом |
||
| + | * имя секрета в котором содержится ключ аккаунта, он создается автоматически если его нет. В целом его можно пересоздать, но тогда можно уперется в число запросов новых аккаунтов, потребуется повторная валидация домена и может еще что то, так что лучше его не удалять. |
||
| + | {{caution|text= |
||
| + | * Не путать с TLS-сертификатами для доменов — они хранятся в другом секрете, указанном в Certificate.spec.secretName. |
||
| + | * Один и тот же privateKeySecretRef можно использовать для многих доменов/сертификатов, чтобы сохранить "один аккаунт". |
||
| + | }} |
||
| + | |||
| + | =Генерация сертификатов= |
||
| + | ==Аннотация <code>Ingress</code>== |
||
| + | Для того что бы включить генерацию сертификатов требуется указать аннотацию у <code>Ingress</code>, в которой указать имя желаемого <code>Issuer</code> / <code>ClusterIssuer</code> |
||
| + | <PRE> |
||
| + | apiVersion: networking.k8s.io/v1 |
||
| + | kind: Ingress |
||
| + | metadata: |
||
| + | annotations: |
||
| + | cert-manager.io/cluster-issuer: letsencrypt-http-cert-issuer |
||
| + | </PRE> |
||
| + | |||
| + | |||
| + | При этом cert-manager проверить есть ли объект типа <code>Certificate</code> и если нет создаст его на основе значения <BR> |
||
| + | в секции <code>.spec.tls.mpp-staging-tls</code> объекта <code>Ingress</code> |
||
| + | <BR> |
||
| + | Например, для такого <code>Ingress</code>: |
||
| + | <PRE> |
||
| + | tls: |
||
| + | - hosts: |
||
| + | - be.staging.mydomain.tld |
||
| + | - login.staging.mydomain.tld |
||
| + | - log.staging.mydomain.tld |
||
| + | - content.staging.mydomain.tld |
||
| + | - fe.staging.mydomain.tld |
||
| + | - ca.staging.mydomain.tld |
||
| + | - shootin.mydomain.tld |
||
| + | - seeble.staging.myseconddomain.tld |
||
| + | - seeble2.staging.myseconddomain.tld |
||
| + | secretName: mpp-staging-tls |
||
| + | </PRE> |
||
| + | будет создан объект типа <code>Certificate</code> (в том же <code>namespace</code> где находится <code>Ingress</code>) |
||
| + | <PRE> |
||
| + | kubectl -n mpp-staging get Certificate |
||
| + | NAME READY SECRET AGE |
||
| + | mpp-staging-tls True mpp-staging-tls 6d20h |
||
| + | </PRE> |
||
| + | |||
| + | {{caution|text= |
||
| + | Это может выглядеть как парадокс "курицы и яйца" - секркт должен быть на момент выпуска сертификата,<BR> |
||
| + | но его нельзя создать так как нет еще сертификата который туда ложить. |
||
| + | <BR> |
||
| + | <BR> |
||
| + | Решение простое - нет секрета, не включится https (но http продолжит работать).<BR> |
||
| + | Когда <code>Cert-manager</code> отработает, он создаст все нужные объекты) |
||
| + | }} |
||
| + | |||
| + | ==Объект <code> Certificate</code>== |
||
| + | Объект создается в том же <code>namespace</code> что и <code>Ingress</code> |
||
| + | <PRE> |
||
| + | kubectl -n mpp-staging get certificates mpp-staging-tls -o wide |
||
| + | NAME READY SECRET ISSUER STATUS AGE |
||
| + | mpp-staging-tls True mpp-staging-tls letsencrypt-http-cert-issuer Certificate is up to date and has not expired 6d20h |
||
| + | </PRE> |
||
| + | Объект <code> Certificate</code> содержит в себе те же метки что и <code>Ingress</code> |
||
| + | <PRE> |
||
| + | kubectl -n mpp-staging get certificates mpp-staging-tls -o yaml |
||
| + | </PRE> |
||
| + | <PRE> |
||
| + | apiVersion: cert-manager.io/v1 |
||
| + | kind: Certificate |
||
| + | metadata: |
||
| + | creationTimestamp: "2025-06-01T18:25:43Z" |
||
| + | generation: 2 |
||
| + | labels: |
||
| + | app.kubernetes.io/managed-by: Helm |
||
| + | application: mpp-ingress |
||
| + | component: mpp-ingress |
||
| + | name: mpp-staging-tls |
||
| + | namespace: mpp-staging |
||
| + | ownerReferences: |
||
| + | - apiVersion: networking.k8s.io/v1 |
||
| + | blockOwnerDeletion: true |
||
| + | controller: true |
||
| + | kind: Ingress |
||
| + | name: mpp-ingress |
||
| + | uid: e600fec5-935b-4156-ab32-bf1ae73a92eb |
||
| + | resourceVersion: "2606170" |
||
| + | uid: daa30a3b-7e10-477f-9c14-61832fb3d284 |
||
| + | spec: |
||
| + | dnsNames: |
||
| + | - be.staging.mydomain.tld |
||
| + | - login.staging.mydomain.tld |
||
| + | - log.staging.mydomain.tld |
||
| + | - content.staging.mydomain.tld |
||
| + | - fe.staging.mydomain.tld |
||
| + | - ca.staging.mydomain.tld |
||
| + | - shootin.mydomain.tld |
||
| + | - seeble.staging.myseconddomain.tld |
||
| + | - seeble2.staging.myseconddomain.tld |
||
| + | issuerRef: |
||
| + | group: cert-manager.io |
||
| + | kind: ClusterIssuer |
||
| + | name: letsencrypt-http-cert-issuer |
||
| + | secretName: mpp-staging-tls |
||
| + | usages: |
||
| + | - digital signature |
||
| + | - key encipherment |
||
status: |
status: |
||
| − | acme: |
||
| − | lastPrivateKeyHash: uKB+SowPSRIAGsxpkCqlb9+ohZYVW+w88CW4yv8CG0w= |
||
| − | lastRegisteredEmail: sirmax123@gmail.com |
||
| − | uri: https://acme-v02.api.letsencrypt.org/acme/acct/2436037867 |
||
conditions: |
conditions: |
||
| − | - lastTransitionTime: "2025-06- |
+ | - lastTransitionTime: "2025-06-08T14:20:10Z" |
| − | message: |
+ | message: Certificate is up to date and has not expired |
| − | observedGeneration: |
+ | observedGeneration: 2 |
| − | reason: |
+ | reason: Ready |
status: "True" |
status: "True" |
||
type: Ready |
type: Ready |
||
| + | notAfter: "2025-09-06T13:21:39Z" |
||
| + | notBefore: "2025-06-08T13:21:40Z" |
||
| + | renewalTime: "2025-08-07T13:21:39Z" |
||
| + | revision: 1 |
||
| + | </PRE> |
||
| + | Так же из важной информации нужно отметить: |
||
| + | * Время жизни |
||
| + | * Список доменов |
||
| + | * usages |
||
| + | * <code>ownerReferences</code> - указание на то кто пользуется объектом |
||
| + | * <code>secretName: mpp-staging-tls</code> - указательна секрет (в том же <code>namespace</code>) где можно увидеть содержимое. |
||
| + | ==Secret== |
||
| + | * тип: kubernetes.io/tls |
||
| + | <PRE> |
||
| + | kubectl -n mpp-staging get secret mpp-staging-tls |
||
| + | NAME TYPE DATA AGE |
||
| + | mpp-staging-tls kubernetes.io/tls 2 7d2h |
||
| + | </PRE> |
||
| + | Выглядит как обычный секрет за исключением аннотаций |
||
| + | <PRE> |
||
| + | kubectl -n mpp-staging get secret mpp-staging-tls -o yaml |
||
| + | apiVersion: v1 |
||
| + | data: |
||
| + | tls.crt: LS0tL ... 0tLQo= |
||
| + | tls.key: LS0tL ... 0tLQo= |
||
| + | kind: Secret |
||
| + | metadata: |
||
| + | annotations: |
||
| + | cert-manager.io/alt-names: be.staging.arturhaunt.ninja,ca.staging.arturhaunt.ninja,content.staging.arturhaunt.ninja,fe.staging.arturhaunt.ninja,log.staging.arturhaunt.ninja,login.staging.arturhaunt.ninja,seeble.staging.rankparrot.com,seeble2.staging.rankparrot.com,shootin.staging.arturhaunt.ninja |
||
| + | cert-manager.io/certificate-name: mpp-staging-tls |
||
| + | cert-manager.io/common-name: be.staging.arturhaunt.ninja |
||
| + | cert-manager.io/ip-sans: "" |
||
| + | cert-manager.io/issuer-group: cert-manager.io |
||
| + | cert-manager.io/issuer-kind: ClusterIssuer |
||
| + | cert-manager.io/issuer-name: letsencrypt-http-cert-issuer |
||
| + | cert-manager.io/uri-sans: "" |
||
| + | creationTimestamp: "2025-06-01T12:58:16Z" |
||
| + | labels: |
||
| + | controller.cert-manager.io/fao: "true" |
||
| + | name: mpp-staging-tls |
||
| + | namespace: mpp-staging |
||
| + | resourceVersion: "2606163" |
||
| + | uid: e0d66584-dffd-4d0f-af36-31fdeed07a22 |
||
| + | type: kubernetes.io/tls |
||
| + | </PRE> |
||
| + | |||
| + | Проверить содержимое и декодировать сертификат можно например так |
||
| + | <PRE> |
||
| + | kubectl -n mpp-staging get secret mpp-staging-tls -o yaml \ |
||
| + | n | yq '.data."tls.crt"' | base64 -d | openssl x509 -noout -text |
||
| + | </PRE> |
||
| + | <PRE> |
||
| + | Certificate: |
||
| + | Data: |
||
| + | Version: 3 (0x2) |
||
| + | Serial Number: |
||
| + | 05:ca:16:47:3b:51:74:e3:46:19:62:ac:67:84:87:5d:75:14 |
||
| + | Signature Algorithm: sha256WithRSAEncryption |
||
| + | Issuer: C=US, O=Let's Encrypt, CN=R11 |
||
| + | Validity |
||
| + | Not Before: Jun 8 13:21:40 2025 GMT |
||
| + | Not After : Sep 6 13:21:39 2025 GMT |
||
| + | Subject: CN=be.staging.arturhaunt.ninja |
||
| + | Subject Public Key Info: |
||
| + | Public Key Algorithm: rsaEncryption |
||
| + | Public-Key: (2048 bit) |
||
| + | Modulus: |
||
| + | c4:af:61:53:cc:38:01:a6:29:8c:c6:6b:68:24:99: |
||
| + | <skipped> |
||
| + | 67:cb:d6:0e:cf:86:b3:06:82:0f:78:c3:3d:d7:fd: |
||
| + | Exponent: 65537 (0x10001) |
||
| + | X509v3 extensions: |
||
| + | X509v3 Key Usage: critical |
||
| + | Digital Signature, Key Encipherment |
||
| + | X509v3 Extended Key Usage: |
||
| + | TLS Web Server Authentication, TLS Web Client Authentication |
||
| + | X509v3 Basic Constraints: critical |
||
| + | CA:FALSE |
||
| + | X509v3 Subject Key Identifier: |
||
| + | B1:DA:D6:09:E1:CA:10:3C:E7:92:FA:D4:BC:75:E7:E5:CC:72:DA:E4 |
||
| + | X509v3 Authority Key Identifier: |
||
| + | C5:CF:46:A4:EA:F4:C3:C0:7A:6C:95:C4:2D:B0:5E:92:2F:26:E3:B9 |
||
| + | Authority Information Access: |
||
| + | CA Issuers - URI:http://r11.i.lencr.org/ |
||
| + | X509v3 Subject Alternative Name: |
||
| + | DNS:be.staging.mydomain.tld, DNS:ca.staging.mydomain.tld, DNS:content.staging.mydomain.tld, DNS:fe.staging.mydomain.tld, DNS:log.staging.mydomain.tld, DNS:login.mydomain.tld, DNS:seeble.staging.staging.myseconddomain.tld, DNS:seeble2.staging.myseconddomain.tld, DNS:shootin.staging.mydomain.tld |
||
| + | X509v3 Certificate Policies: |
||
| + | Policy: 2.23.140.1.2.1 |
||
| + | X509v3 CRL Distribution Points: |
||
| + | Full Name: |
||
| + | URI:http://r11.c.lencr.org/21.crl |
||
| + | CT Precertificate SCTs: |
||
| + | Signed Certificate Timestamp: |
||
| + | Version : v1 (0x0) |
||
| + | Log ID : CC:FB:0F:6A:85:71:09:65:FE:95:9B:53:CE:E9:B2:7C: |
||
| + | 22:E9:85:5C:0D:97:8D:B6:A9:7E:54:C0:FE:4C:0D:B0 |
||
| + | Timestamp : Jun 8 14:20:10.323 2025 GMT |
||
| + | Extensions: none |
||
| + | Signature : ecdsa-with-SHA256 |
||
| + | 30:44:02:20:5E:CB:C3:21:AF:32:15:B9:F7:32:50:31: |
||
| + | <sipped> |
||
| + | 6C:86:30:C5:EF:BD |
||
| + | Signed Certificate Timestamp: |
||
| + | Version : v1 (0x0) |
||
| + | Log ID : DD:DC:CA:34:95:D7:E1:16:05:E7:95:32:FA:C7:9F:F8: |
||
| + | 3D:1C:50:DF:DB:00:3A:14:12:76:0A:2C:AC:BB:C8:2A |
||
| + | Timestamp : Jun 8 14:20:10.383 2025 GMT |
||
| + | Extensions: none |
||
| + | Signature : ecdsa-with-SHA256 |
||
| + | 30:45:02:20:61:38:16:78:7F:A3:1C:B6:21:EA:B3:21: |
||
| + | <skipped> |
||
| + | 49:04:B4:86:AB:BF:47 |
||
| + | Signature Algorithm: sha256WithRSAEncryption |
||
| + | Signature Value: |
||
| + | 4f:9c:5a:69:5f:30:3c:2d:7e:08:da:29:18:f6:ed:85:30:df: |
||
| + | <skipped> |
||
| + | e8:6c:06:5b |
||
| + | </PRE> |
||
| + | Тут можно видеть что все доменные имена, которые присутвуют в конфигурации <code>Ingress</code> перечислены как <code>Alternative Name</code> |
||
| + | |||
| + | <BR> |
||
| + | ==<code>AltNames ?</code>== |
||
| + | В конфигурации <code>Ingress</code> для всех сертификатов указан общий секрет: |
||
| + | <PRE> |
||
| + | kubectl -n mpp-staging get ingress mpp-ingress -o yaml | yq '.spec.tls' |
||
| + | </PRE> |
||
| + | <PRE> |
||
| + | - hosts: |
||
| + | - be.staging.mydomain.tld |
||
| + | - login.staging.mydomain.tld |
||
| + | ... |
||
| + | - seeble2.staging.myseconddomain.tld |
||
| + | secretName: mpp-staging-tls |
||
| + | </PRE> |
||
| + | Если хочется иметь разные сертификаты для разных хостов, то нужно использовать конфигурацию вида |
||
| + | <PRE> |
||
| + | - hosts: |
||
| + | - be.staging.mydomain.tld |
||
| + | - login.staging. |
||
| + | secretName: mpp-staging-mydomain-tld-tls |
||
| + | - hosts: |
||
| + | - seeble1.staging.myseconddomain.tld |
||
| + | - seeble2.staging.myseconddomain.tld |
||
| + | secretName: mpp-staging-myseconddomain-tls |
||
| + | </PRE> |
||
| + | В такой конфигурации будет создано 2 отдельных сертификата каждый со свои списком AltNames. <BR> |
||
| + | Это может быть нужно, если не хочется дать понять внешнему пользователю что домены как-либо связаны. |
||
| + | <BR> |
||
| + | Ну и конечно еще более радикальный способ - сделать 2 экземпляра <code>Ingress</code> |
||
| + | |||
| + | =Дополгительный вопросы для проработки позже= |
||
| + | * Проверить другие способы получения сертификатов (Vault, Amazon) |
||
Текущая версия на 11:29, 23 июня 2025
Для Ingress требуется автоматически выписывать сертификаты для доменов которые "Хостятся" на нем
Предварительные требования
Требуется доступ (ручной или автоматический) к управлению зоной DNS для того что бы направить нужные домены на соответвующий Ingress
Возможные варианты решения
- Использовать независимое от cloud-провайдера решение, Let's encrypt.
- В завимсимости от того где лежит DNS-зона и как ей можно управлять, может требовать или не требовать ручной правкии зоны.
- В случае если зона хостится на AWS Route53 возможно применить например такую автоматизацию обновления зоны
- К плюсам можно отнести то что решение будет работать на любом клауде, не привязано к провайдеру.
- Список возможных Issuers досаточно широк (https://cert-manager.io/docs/configuration/issuers/), для тестирования можно например использовать локально развернутый Hashicorp Vault
- Использовать сертификаты от AWS (это пока не реализовано)
cert-manager
Для решения этой задачи существует cert-manager
Примерный принцип работы (насколько я его понимаю)
- Установка в том чимсле создания
Custom Resource Definition(далееCRD) - Cоздается ресусурс типа
IssuerилиClusterIssuer— описывает, откуда брать сертификаты- Разница в том что
Issuerдоступен только внутри namespace, в моем случае когда все сертификаты нужны для нескольких копий приложения ("окружений"), напримерdev.domain.tld,staging.domain.tld,qa.domain.tldнужно будет изменитьClusterIssuerнаIssuer. Пока окружение одно это не важно, но как только их несколько то не хочется иметь один сертификат на всех с длинным списком Altnames (но это требует проверки)
- Разница в том что
- После создания Certificate-ресурса —
cert-managerследит за ним и выполняет выпуск согласно настройкам ресурса, результат сохраняет вSecret
cert-manager автоматически:
- делает HTTP или DNS-проверку чтобы подтвердить владение доменом (в этом случае HTTP так как у него нет доступа к управлению ресурсами зоны!) Как именно определено в поле
solvers - получает сертификат от CA, определенного в поле
acme - сохраняет в
SecretTODO - Мониторит и продлевает его до истечения срока действия.
Возможные источники сертефикатов
Установка
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm \ install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --set installCRDs=true
Пример ClusterIssuer
Достаточно простой объект
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-http-cert-issuer
spec:
acme:
email: sirmax123@gmail.com
privateKeySecretRef:
name: letsencrypt-http
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- http01:
ingress:
class: nginx
- имя можно выбрать произвольное
email: sirmax123@gmail.comраньше был нужен что б Let's Encrypt мог прислать оповещение, но он уже давно это отключил и сецчас это просто ненужное но обязательное поле.solversспособ подтверждения владения доменом- имя секрета в котором содержится ключ аккаунта, он создается автоматически если его нет. В целом его можно пересоздать, но тогда можно уперется в число запросов новых аккаунтов, потребуется повторная валидация домена и может еще что то, так что лучше его не удалять.
|
Генерация сертификатов
Аннотация Ingress
Для того что бы включить генерацию сертификатов требуется указать аннотацию у Ingress, в которой указать имя желаемого Issuer / ClusterIssuer
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-http-cert-issuer
При этом cert-manager проверить есть ли объект типа Certificate и если нет создаст его на основе значения
в секции .spec.tls.mpp-staging-tls объекта Ingress
Например, для такого Ingress:
tls:
- hosts:
- be.staging.mydomain.tld
- login.staging.mydomain.tld
- log.staging.mydomain.tld
- content.staging.mydomain.tld
- fe.staging.mydomain.tld
- ca.staging.mydomain.tld
- shootin.mydomain.tld
- seeble.staging.myseconddomain.tld
- seeble2.staging.myseconddomain.tld
secretName: mpp-staging-tls
будет создан объект типа Certificate (в том же namespace где находится Ingress)
kubectl -n mpp-staging get Certificate NAME READY SECRET AGE mpp-staging-tls True mpp-staging-tls 6d20h
|
Это может выглядеть как парадокс "курицы и яйца" - секркт должен быть на момент выпуска сертификата, |
Объект Certificate
Объект создается в том же namespace что и Ingress
kubectl -n mpp-staging get certificates mpp-staging-tls -o wide NAME READY SECRET ISSUER STATUS AGE mpp-staging-tls True mpp-staging-tls letsencrypt-http-cert-issuer Certificate is up to date and has not expired 6d20h
Объект Certificate содержит в себе те же метки что и Ingress
kubectl -n mpp-staging get certificates mpp-staging-tls -o yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
creationTimestamp: "2025-06-01T18:25:43Z"
generation: 2
labels:
app.kubernetes.io/managed-by: Helm
application: mpp-ingress
component: mpp-ingress
name: mpp-staging-tls
namespace: mpp-staging
ownerReferences:
- apiVersion: networking.k8s.io/v1
blockOwnerDeletion: true
controller: true
kind: Ingress
name: mpp-ingress
uid: e600fec5-935b-4156-ab32-bf1ae73a92eb
resourceVersion: "2606170"
uid: daa30a3b-7e10-477f-9c14-61832fb3d284
spec:
dnsNames:
- be.staging.mydomain.tld
- login.staging.mydomain.tld
- log.staging.mydomain.tld
- content.staging.mydomain.tld
- fe.staging.mydomain.tld
- ca.staging.mydomain.tld
- shootin.mydomain.tld
- seeble.staging.myseconddomain.tld
- seeble2.staging.myseconddomain.tld
issuerRef:
group: cert-manager.io
kind: ClusterIssuer
name: letsencrypt-http-cert-issuer
secretName: mpp-staging-tls
usages:
- digital signature
- key encipherment
status:
conditions:
- lastTransitionTime: "2025-06-08T14:20:10Z"
message: Certificate is up to date and has not expired
observedGeneration: 2
reason: Ready
status: "True"
type: Ready
notAfter: "2025-09-06T13:21:39Z"
notBefore: "2025-06-08T13:21:40Z"
renewalTime: "2025-08-07T13:21:39Z"
revision: 1
Так же из важной информации нужно отметить:
- Время жизни
- Список доменов
- usages
ownerReferences- указание на то кто пользуется объектомsecretName: mpp-staging-tls- указательна секрет (в том жеnamespace) где можно увидеть содержимое.
Secret
- тип: kubernetes.io/tls
kubectl -n mpp-staging get secret mpp-staging-tls NAME TYPE DATA AGE mpp-staging-tls kubernetes.io/tls 2 7d2h
Выглядит как обычный секрет за исключением аннотаций
kubectl -n mpp-staging get secret mpp-staging-tls -o yaml
apiVersion: v1
data:
tls.crt: LS0tL ... 0tLQo=
tls.key: LS0tL ... 0tLQo=
kind: Secret
metadata:
annotations:
cert-manager.io/alt-names: be.staging.arturhaunt.ninja,ca.staging.arturhaunt.ninja,content.staging.arturhaunt.ninja,fe.staging.arturhaunt.ninja,log.staging.arturhaunt.ninja,login.staging.arturhaunt.ninja,seeble.staging.rankparrot.com,seeble2.staging.rankparrot.com,shootin.staging.arturhaunt.ninja
cert-manager.io/certificate-name: mpp-staging-tls
cert-manager.io/common-name: be.staging.arturhaunt.ninja
cert-manager.io/ip-sans: ""
cert-manager.io/issuer-group: cert-manager.io
cert-manager.io/issuer-kind: ClusterIssuer
cert-manager.io/issuer-name: letsencrypt-http-cert-issuer
cert-manager.io/uri-sans: ""
creationTimestamp: "2025-06-01T12:58:16Z"
labels:
controller.cert-manager.io/fao: "true"
name: mpp-staging-tls
namespace: mpp-staging
resourceVersion: "2606163"
uid: e0d66584-dffd-4d0f-af36-31fdeed07a22
type: kubernetes.io/tls
Проверить содержимое и декодировать сертификат можно например так
kubectl -n mpp-staging get secret mpp-staging-tls -o yaml \ n | yq '.data."tls.crt"' | base64 -d | openssl x509 -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
05:ca:16:47:3b:51:74:e3:46:19:62:ac:67:84:87:5d:75:14
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=Let's Encrypt, CN=R11
Validity
Not Before: Jun 8 13:21:40 2025 GMT
Not After : Sep 6 13:21:39 2025 GMT
Subject: CN=be.staging.arturhaunt.ninja
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
c4:af:61:53:cc:38:01:a6:29:8c:c6:6b:68:24:99:
<skipped>
67:cb:d6:0e:cf:86:b3:06:82:0f:78:c3:3d:d7:fd:
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
B1:DA:D6:09:E1:CA:10:3C:E7:92:FA:D4:BC:75:E7:E5:CC:72:DA:E4
X509v3 Authority Key Identifier:
C5:CF:46:A4:EA:F4:C3:C0:7A:6C:95:C4:2D:B0:5E:92:2F:26:E3:B9
Authority Information Access:
CA Issuers - URI:http://r11.i.lencr.org/
X509v3 Subject Alternative Name:
DNS:be.staging.mydomain.tld, DNS:ca.staging.mydomain.tld, DNS:content.staging.mydomain.tld, DNS:fe.staging.mydomain.tld, DNS:log.staging.mydomain.tld, DNS:login.mydomain.tld, DNS:seeble.staging.staging.myseconddomain.tld, DNS:seeble2.staging.myseconddomain.tld, DNS:shootin.staging.mydomain.tld
X509v3 Certificate Policies:
Policy: 2.23.140.1.2.1
X509v3 CRL Distribution Points:
Full Name:
URI:http://r11.c.lencr.org/21.crl
CT Precertificate SCTs:
Signed Certificate Timestamp:
Version : v1 (0x0)
Log ID : CC:FB:0F:6A:85:71:09:65:FE:95:9B:53:CE:E9:B2:7C:
22:E9:85:5C:0D:97:8D:B6:A9:7E:54:C0:FE:4C:0D:B0
Timestamp : Jun 8 14:20:10.323 2025 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:44:02:20:5E:CB:C3:21:AF:32:15:B9:F7:32:50:31:
<sipped>
6C:86:30:C5:EF:BD
Signed Certificate Timestamp:
Version : v1 (0x0)
Log ID : DD:DC:CA:34:95:D7:E1:16:05:E7:95:32:FA:C7:9F:F8:
3D:1C:50:DF:DB:00:3A:14:12:76:0A:2C:AC:BB:C8:2A
Timestamp : Jun 8 14:20:10.383 2025 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:45:02:20:61:38:16:78:7F:A3:1C:B6:21:EA:B3:21:
<skipped>
49:04:B4:86:AB:BF:47
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
4f:9c:5a:69:5f:30:3c:2d:7e:08:da:29:18:f6:ed:85:30:df:
<skipped>
e8:6c:06:5b
Тут можно видеть что все доменные имена, которые присутвуют в конфигурации Ingress перечислены как Alternative Name
AltNames ?
В конфигурации Ingress для всех сертификатов указан общий секрет:
kubectl -n mpp-staging get ingress mpp-ingress -o yaml | yq '.spec.tls'
- hosts:
- be.staging.mydomain.tld
- login.staging.mydomain.tld
...
- seeble2.staging.myseconddomain.tld
secretName: mpp-staging-tls
Если хочется иметь разные сертификаты для разных хостов, то нужно использовать конфигурацию вида
- hosts:
- be.staging.mydomain.tld
- login.staging.
secretName: mpp-staging-mydomain-tld-tls
- hosts:
- seeble1.staging.myseconddomain.tld
- seeble2.staging.myseconddomain.tld
secretName: mpp-staging-myseconddomain-tls
В такой конфигурации будет создано 2 отдельных сертификата каждый со свои списком AltNames.
Это может быть нужно, если не хочется дать понять внешнему пользователю что домены как-либо связаны.
Ну и конечно еще более радикальный способ - сделать 2 экземпляра Ingress
Дополгительный вопросы для проработки позже
- Проверить другие способы получения сертификатов (Vault, Amazon)