diff --git a/README.md b/README.md index 7b78474..ae83039 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,9 @@ ## Kubernetes (k3s/k8s) * [Установка k3s на Orange Pi 5 Plus](raspberry-and-orange-pi/k3s.md) -* [Под с Shadowsocks-клиент](kubernetes/k3s-shadowsocks-client.md) (k3s) -* [Под с 3X-UI](kubernetes/k3s-3xui-pod.md) (k3s) +* [Под с Shadowsocks-клиент](kubernetes/k3s-shadowsocks-client.md) в k3s +* [Подключение менеджера сертификатов (cert-manager) Let's Encrypt](kubernetes/k3s-lets-encrypt-cert-manager.md) к k3s +* [Под с 3X-UI](kubernetes/k3s-3xui-pod.md) в k3s * [Проксирование внешнего хоста через Traefik (Ingress-контроллер)](kubernetes/k3s-proxy.md) * [Перенос контейнера Docker в k3s](kubernetes/k3s-migrating-container-from-docker-to-kubernetes.md) diff --git a/kubernetes/k3s-lets-encrypt-cert-manager.md b/kubernetes/k3s-lets-encrypt-cert-manager.md new file mode 100644 index 0000000..557fb08 --- /dev/null +++ b/kubernetes/k3s-lets-encrypt-cert-manager.md @@ -0,0 +1,212 @@ +# Подключение менеджера сертификатов (cert-manager) Let's Encrypt к k3s + +№ Установка cert-manager + +Установим `cert-manager` из официального манифеста GitHub. Это автоматически добавит все необходимые компоненты, +включая CRD (Custom Resource Definitions) и контроллеры: + +```bash +kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.3/cert-manager.yaml +``` + +Это установит cert-manager версии 1.15.3 (предварительно надо проверь актуальную версию на GitHub cert-manager). +Компоненты развернутся в namespace cert-manager. + +Проверим установку: +```bash +kubectl get pods --namespace cert-manager +``` + +Увидим, что все поды в статусе `Running`: +```text +NAME READY STATUS RESTARTS AGE +cert-manager-778cb8f45-gxtpf 1/1 Running 0 22m +cert-manager-cainjector-6d5854cdd8-w4d8x 1/1 Running 0 22m +cert-manager-webhook-78b57fb6bb-jljdx 1/1 Running 0 22m +``` + +Что это за поды: +- `cert-manager` — основной контроллер cert-manager, который управляет созданием и обновлением сертификатов. +- `cert-manager-cainjector` — контроллер, который автоматически добавляет CA-сертификаты в секреты и ресурсы Kubernetes. +- `cert-manager-webhook` — контроллер, который обрабатывает запросы на валидацию и мутацию ресурсов cert-manager. + +Проверим, что Custom Resource Definitions (CRDs) для cert-manager созданы: +```bash +kubectl get crd | grep cert-manager +``` + +Должны быть `certificates.cert-manager.io`, `issuers.cert-manager.io`, `clusterissuers.cert-manager.io и другие: +```text +certificaterequests.cert-manager.io 2025-04-27T16:29:56Z +certificates.cert-manager.io 2025-04-27T16:29:56Z +challenges.acme.cert-manager.io 2025-04-27T16:29:56Z +clusterissuers.cert-manager.io 2025-04-27T16:29:56Z +issuers.cert-manager.io 2025-04-27T16:29:56Z +orders.acme.cert-manager.io 2025-04-27T16:29:57Z +``` + +# Создание ClusterIssuer (Эмитент сертификатов для всего кластера) + +Создадим `ClusterIssuer` для Let's Encrypt. Это позволит cert-manager автоматически запрашивать и обновлять сертификаты. +Разместим его в отдельном файле `~/k3s/cert-manager/letsencrypt-clusterissuer.yaml`: +```bash +mkdir -p ~/k3s/cert-manager +nano ~/k3s/cert-manager/letsencrypt-clusterissuer.yaml +``` + +И вставим в него следующий код (не забудьте заменить `<my@email.com>` на свой email): +```yaml +apiVersion: cert-manager.io/v1 # Версия API для cert-manager, v1 — текущая стабильная. +kind: ClusterIssuer # Тип ресурса. ClusterIssuer — глобальный объект для выдачи сертификатов + # всему кластеру (в отличие от Issuer, который ограничен namespace). +metadata: + name: letsencrypt-prod # Имя `ClusterIssuer`, на него будем ссылаться в манифестах (например, в Certificate). +spec: + acme: # Используется ACME-протокол (Automated Certificate Management Environment) Let's Encrypt. + server: https://acme-v02.api.letsencrypt.org/directory # URL сервера Let's Encrypt (боевой). + email: <my@email.com> # Логин-клиент Let's Encrypt (раньше так же использовался для уведомлений). + privateKeySecretRef: + name: letsencrypt-prod # Имя секрета, где будет храниться приватные ключи для ACME-аккаунта. + solvers: # Список способов "решения" ACME-задач для подтверждения владения доменом. + - http01: # Используется HTTP-01 challenge (подтверждение через HTTP-запросы). + ingress: + class: traefik # Указывает, что ingress-контроллер Traefik будет обрабатывать HTTP-01 challenge + # (создает временные маршруты для `/.well-known/acme-challenge`) для подтверждения + # владения доменом. +``` + +Применим манифест: +```bash +kubectl apply -f ~/k3s/cert-manager/letsencrypt-clusterissuer.yaml +``` + +Проверим, что `ClusterIssuer` создан: +```bash +kubectl get clusterissuer +``` + +Увидим что-то вроде: +```text +NAME READY AGE +letsencrypt-prod True 27s +``` + +Проверим статус: +```bash +kubectl describe clusterissuer letsencrypt-prod +``` + +Увидим что-то вроде: +```text +... +... +Status: + Acme: + Last Private Key Hash: тут-хранится-хэш-приватного-ключа + Last Registered Email: <my@email.com> + Uri: https://acme-v02.api.letsencrypt.org/acme/acct/2365771147 + Conditions: + Last Transition Time: 2025-04-27T17:00:56Z + Message: The ACME account was registered with the ACME server + Observed Generation: 1 + Reason: ACMEAccountRegistered + Status: True + Type: Ready +... +``` + +Должны быть `Status: True` и `Reason: ACMEAccountRegistered`, что означает, что `ClusterIssuer` успешно зарегистрирован +и готов к использованию. + +# Создание сертификата + +Эта общая часть, объясняющая как создавать манифесты для выпуска сертификатов. + +В своем манифесте, например, в манифесте пода, создается блок (данный кусочек взят из манифеста пода +[Gitea](k3s-migrating-container-from-docker-to-kubernetes.md) и он находится в пространстве имен `gitea`): +```yaml +--- +# Манифест для получения сертификата от Let's Encrypt +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: gitea-tls # Имя сертификата `gitea-tls` + namespace: gitea # В пространстве имен `gitea` +spec: + secretName: gitea-tls # Имя секрета для сертификата + dnsNames: # Доменные имена для сертификата... + - git.cube2.ru + issuerRef: # Эмитент сертификата (Issuer) + name: letsencrypt-prod # Имя ClusterIssuer, который отвечает за получение сертификата: `letsencrypt-prod` + kind: ClusterIssuer # Тип эмитента +``` + +После применения манифеста, можно проверить статус сертификата: +```bash +kubectl get certificate -A +``` + +Увидим что-то вроде: +```text +NAMESPACE NAME READY SECRET AGE +ab-shelf audiobookshelf-tls False audiobookshelf-tls 4h +gitea gitea-tls True gitea-tls 14m +``` + +Тут можно заметить, что сертификат `audiobookshelf-tls` не готов (False), а `gitea-tls` готов (True). + +Как проверить статус сертификата и причину его неготовности (на примере `audiobookshelf-tls`): +```bash +kubectl describe certificate audiobookshelf-tls -n ab-shelf +``` + +Увидим что-то вроде: +```text +Name: audiobookshelf-tls +Namespace: ab-shelf +... +... +... +Spec: + Dns Names: + <тут-будет-доменное-имя-для-которого-выдается-сертификат> + Issuer Ref: + Kind: ClusterIssuer + Name: letsencrypt-prod + Secret Name: audiobookshelf-tls +Status: + Conditions: + Last Transition Time: 2025-04-27T17:13:32Z + Message: The certificate request has failed to complete and will be retried: Failed to wait for order resource "audiobookshelf-tls-1-722111375" to become ready: order is in "errored" state: Failed to create Order: 429 urn:ietf:params:acme:error:rateLimited: too many certificates (5) already issued for this exact set of domains in the last 168h0m0s, retry after 2025-04-28 19:30:09 UTC: see https://letsencrypt.org/docs/rate-limits/#new-certificates-per-exact-set-of-hostnames + Observed Generation: 1 + Reason: Failed + Status: False + Type: Issuing + Last Transition Time: 2025-04-27T17:13:29Z + Message: Issuing certificate as Secret does not exist + Observed Generation: 1 + Reason: DoesNotExist + Status: False + Type: Ready +... +... +... +``` + +Как видно, причина неготовности сертификата `audiobookshelf-tls` в том, что уже превышен лимит на количество сертификатов +(5) для данного доменного имени за последние 168 часов (7 дней). Указано время после которого можно повторить запрос. + +По идее запрос на повторный сертификат будет отправлен автоматически, но это может произойти спустя несколько часов +после разрешенного времени (учтите что время указывается в UTC, делайте поправку по своему локальному времени). + +Чтобы ускорить процесс, можно удалить сертификат и создать его заново (на примере `audiobookshelf-tls`): +```bash +kubectl delete certificate audiobookshelf-tls -n ab-shelf +``` + +А затем повторно принять манифест, в котором у вас находится `kind: Certificate` + +| Заметка | +|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Пока Let's Encrypt не выдал сертификат, Traefik будет работать по SSL (https) на самоподписанном сертификате. Можно открыть анонимное окно браузера, согласится с предупреждениями безопасности и пользоваться сайтом. | +| | \ No newline at end of file