Развертывание веб приложений в Kubernetes является одной из стандартных задач для бизнеса. В современной инфраструктуре использование сертификатов TLS и HTTPs протокола не является опциональным (например, с 2018 года браузер Chrome помечает все HTTP сайты как небезопасные). В этой статье мы рассмотрим как с помощью приложений с открытым исходным кодом абсолютно бесплатно получить сертификат для вашего приложения, автоматизировать весь процесс и обновление.
В нашем примере мы будем рассматривать следующие компоненты:
- Kubernetes кластер - подойдет любой кластер с доступом в Интернет и публичным IP-адресом
- ingress-nginx - их много вариантов, но мы возьмем тот, что активно поддерживается сообществом и Cloud Native Computing Foundation
- cert-manager - это оператор, который автоматизирует создание и управление сертификатами в k8s
- Let’s Encrypt - бесплатный, автоматизированный центр сертификации - выпускают TLS сертификаты
Установка компонентов
Веб сервис
Для начала задеплоим простейший Под с nginx и создадим для него Service объект:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: my-test-app
spec:
containers:
- name: nginx
image: nginx
---
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: my-test-app
ports:
- protocol: TCP
port: 80
Это будет наше приложение, которое спрятано за сертификатами.
Ingress
Установим ingress-nginx. Проще всего делать это с helm:
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
Это установит ingress контроллер и выставит его во внешний мир через LoadBalancer сервис. Если у ваш кластер не поддерживает LoadBalancer, то есть другие варианты, которые вы можете посмотреть в документации.
cert-manager
Проще всего тоже взять команду из документации, так как версии могут отличаться. На момент написания статьи, стабильная версия 1.14.3:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.yaml
HTTP
Все готово к первым шагам. Начнем с того, что наше приложение будет доступно по HTTP через ingress. Для этого, создадим Ingress объект:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: default
annotations:
kubernetes.io/ingress.allow-http: "true"
spec:
ingressClassName: nginx
rules:
- host: mytest.l3k.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
Из основных параметров:
- ingressClassName: nginx - указывает, что мы хотим использовать именно ingress-nginx контроллер. Это нужно, если у вас в кластере есть и другие контроллеры. Например, так часто бывает в публичных облаках.
- - host: mytest.l3k.io - открывает секцию, которая указывает на Домен, который мы хотим выставить наружу.
- Секция backend: - говорит Ingress объекту, куда нужно отправлять запросы для этого сайта. Это наш сервис, который смотрит на Под nginx.
Посмотреть состояние Ingress можно следующим образом:
% kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
test-ingress nginx mytest.l3k.io 12.123.123.123 80 5m1s
Можно проверить, все ли работает и увидеть стандартное приглашение nginx:
% curl -H "Host: mytest.l3k.io" http://12.123.123.123
…
<h1>Welcome to nginx!</h1>
…
Чтобы двигаться дальше, нужно добавить в DNS запись, которая направит нужный домен на IP-адрес ингресса. В моем случае, я добавлю A-запись:
mytest.l3k.io A 12.123.123.123
Теперь сайт откроется и в браузере.
HTTPs
Staging
cert-manager будет заниматься тем, что запросит для нас сертификат у Let’s Encrypt и создаст секрет в кубернетес кластере, который ingress будет использовать. У Let’s Encrypt очень жесткие лимиты по количеству подключений в минуту, поэтому для начала обкатываем все на staging.
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-staging
namespace: default
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: <YOUR_EMAIL> # поменять на ваш имейл
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- http01:
ingress:
ingressClassName: nginx
Если попробовать открыть страницу, то сертификат будет невалидный, так как подписан staging CA Let’s Encrypt:
% curl -v --insecure https://mytest.l3k.io
…
* Server certificate:
* subject: CN=mytest.l3k.io
* start date: Feb 23 11:56:07 2024 GMT
* expire date: May 23 11:56:06 2024 GMT
* issuer: C=US; O=(STAGING) Let's Encrypt; CN=(STAGING) Artificial Apricot R3
Production
Если все работает, то можно пробовать Let’s Encrypt production. Для этого нужно создать production Issuer:
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-production
namespace: default
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: <YOUR_EMAIL>
privateKeySecretRef:
name: letsencrypt-production
solvers:
- http01:
ingress:
ingressClassName: nginx
Так же меняем Ingress, где указываем, что Issuer будет production:
% diff -u ingress-https-staging.yaml ingress-https-prod.yaml
--- ingress-https-staging.yaml 2024-02-23 15:53:22
+++ ingress-https-prod.yaml 2024-02-23 18:03:02
@@ -5,7 +5,7 @@
namespace: default
annotations:
kubernetes.io/ingress.allow-http: "true"
- cert-manager.io/issuer: letsencrypt-staging
+ cert-manager.io/issuer: letsencrypt-production
acme.cert-manager.io/http01-edit-in-place: "true"
spec:
ingressClassName: nginx
Теперь у нас есть полностью валидный сертификат.
Wildcard
Wildcard дает возможность покрыть TLS сертификатами поддомены. Это удобно, если у вас приложение обслуживает несколько субдоменов сразу. Например:
- abc.l3k.io
- def.l3k.io
Для получения wildcard сертификата, небходима проверка DNS01. Можно почитать про это здесь. У cert-manager есть нативная интеграция со многими DNS провайдерами, например AWS Route 53 (список). К тому же есть поддержка вебхуков (webhooks). Вебхуки для всевозможных провайдеров можно найти в Гитхабе в поиске по cert-manager-webhook. Есть официальные проекты, например от Яндекса.
Свой вебхук тоже можно написать, используя пример отсюда. Мы используем name.com для домена l3k.io, который тоже поддерживается только хуками. Берем вот этот проект: https://github.com/imgrant/cert-manager-webhook-namecom/tree/main
Деплоим все по инструкции. В итоге мы создаем следующие ресурсы
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-namecom
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: <YOUR_EMAIL>
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- dns01:
webhook:
groupName: acme.name.com
solverName: namedotcom
config:
username: <YOUR_LOGIN>
apitokensecret:
name: namedotcom-credentials
key: api-token
- Certificate - сам сертификат wild card. Это создаст сертификат в wild-cert.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: l3k-test
spec:
dnsNames:
- '*.l3k.io'
issuerRef:
name: letsencrypt-namecom
kind: ClusterIssuer
secretName: wild-cert
Теперь можно и поменять наш Ingress. Мы поменяем домен на *.l3k.io и будем ссылаться на сертификат напрямую:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: default
annotations:
kubernetes.io/ingress.allow-http: "true"
spec:
ingressClassName: nginx
tls:
- secretName: wild-cert
hosts:
- '*.l3k.io'
rules:
- host: '*.l3k.io'
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
Теперь мы можем направить любой поддомен l3k.io на этот ingress, приложение уже само будет распределять трафик по субдоменам.
Заключение
В заключение, использование сертификатов TLS и протокола HTTPS в Kubernetes является критически важным аспектом для обеспечения безопасности и надежности веб-приложений. В этом посте мы обсудили, как можно легко и бесплатно развернуть сертификаты для вашего приложения, используя открытые и доступные инструменты, такие как ingress-nginx, cert-manager, и Let’s Encrypt.
Следуя этим шагам, вы не только обеспечите безопасность своего веб-приложения, но и автоматизируете процесс обновления сертификатов, снизив тем самым ручные усилия и вероятность возникновения ошибок. Это демонстрирует мощь и гибкость Kubernetes как платформы для развертывания современных веб-приложений и подчеркивает важность внедрения лучших практик безопасности с самого начала разработки.
Поможем с настройкой, проконсультируем и поддержим. Напишите нам.