HTTPS en Kubernetes
Configuración de certificados SSL automáticos para Kubernetes en K3s utilizando Cert-Manager y Traefik
Traefik
Traefik es un proxy inverso y balanceador de carga diseñado para entornos nativos en la nube. En Kubernetes, se usa como Ingress Controller para gestionar el tráfico hacia los servicios internos del clúster. Facilita el enrutamiento de solicitudes, el manejo de certificados SSL y la integración con herramientas como cert-manager
para la gestión automática de HTTPS.
Instalación
De acuerdo a la Documentación podemos instalar Traefik utilizando Helm. Con lo siguiente podríamos instalarlo con sus valores por defecto en cualquier entorno de Kubernetes.
1
2
3
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install traefik traefik/traefik
Configuración
En nuestro caso, como estamos utilizando K3s ya tenemos Traefik instalado, solo debemos hacerle algunos ajustes para dejarlo funcional.
En K3s Traefik se instalará en el namespace
kube-system
Validamos que el deployment existe.
Y el Service tipo LoadBalancer con una dirección IP externa asignada gracias a MetalLB. Puedes ver el paso a paso de como configurar MetalLB en un post anterior.
Lo que no trae la instalación por defecto de Traefik en K3s es la configuración de los entrypoints. Estos serán los puertos de escucha al exterior, todo tráfico que llegue a estos puertos será enrutado por Traefik según la configuración que hayamos hecho. Configuraremos el puerto 80
para el tráfico http
o inseguro y 443
para el https
, además de una redirección desde http
a https
por defecto.
Otra configuración importante son los Providers. Para nuestro caso habilitaremos kubernetesCRD
y kubernetesIngress
aunque probablemente solo ocupemos este último.
Para continuar, crearemos un objeto Kubernetes de tipo ConfigMap
en el namespace de kube-system
con la siguiente data.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config
namespace: kube-system
data:
traefik.yml: |
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: "websecure"
scheme: "https"
permanent: true
websecure:
address: ":443"
providers:
kubernetesCRD: {}
kubernetesIngress: {}
certificatesResolvers:
letsencrypt:
acme:
email: "[email protected]"
storage: "/data/acme.json"
httpChallenge:
entryPoint: web
1
kubectl apply -f traefik-config.yml
Con esto ya estaría funcional Traefik, pero para testearlo crearemos un deployment service de Nginx y un Ingress que enrutará el tráfico hacia la web.
He dispuesto el DNS nginx-k3s.home.cervant.net
que apunta a la dirección del LoadBalancer de Traefik 192.168.1.200
.
Aplicaremos el manifiesto de Nginx.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: blog
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: blog
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
Y posteriormente el del Ingress, que debe tener el annotation traefik.ingress.kubernetes.io/router.entrypoints
con el valor del entrypoint al que queramos redirigirlo, en este caso apunta a web y websecure porque queremos que nuestro nginx se publique en ambos protocolos.
Mas abajo en spec.rules.host
se define el nombre de DNS que hemos indicado anteriormente.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
namespace: blog
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web, websecure
spec:
rules:
- host: nginx-k3s.home.cervant.net
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
Si verificamos en un navegador, vemos que nginx-k3s.home.cervant.net
ya está respondiendo con la bienvenida de Nginx.
Y funciona de maravilla! El único detalle es que nos arroja error de certificado pero eso es algo que solucionaremos ahora.
Cert-Manager
Cert-Manager es una herramienta que automatiza la gestión de certificados TLS en Kubernetes. Permite obtener, renovar y administrar certificados de forma sencilla a través de Let’s Encrypt u otras autoridades certificadoras. Se integra con Ingress Controllers como Traefik para garantizar conexiones seguras sin intervención manual.
Instalación
Primero crearemos un archivo values para usar en la instalación con Helm.
1
2
3
4
5
6
namespace: cert-manager
crds:
enabled: true
extraArgs:
- --dns01-recursive-nameservers=1.1.1.1:53,1.0.0.1:53
- --dns01-recursive-nameservers-only
Y lo aplicaremos de esta manera.
1
2
helm repo add jetstack https://charts.jetstack.io --force-update
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --values certmanager-values.yml
Después de unos segundos veremos que se han creado los siguientes recursos en el namespace cert-manager
.
Configuración
Ahora deberemos crear un secreto para almacenar el API TOKEN de nuestro proveedor de DNS, en mi caso es Cloudflare. Deberemos obtener un API TOKEN y convertir el string a base64.
En linux puedes convertir un string a base64 ejecutando
echo -n '<API-TOKEN>' | base64
1
2
3
4
5
6
7
8
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-token-secret
namespace: cert-manager
type: Opaque
data:
api-token: <API-TOKEN-BASE64>
Luego, necesitaremos un ClusterIssuer
que es el que se encargará de obtener los certificados a través del proveedor DNS y para todo el cluster.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: cloudflare-clusterissuer
namespace: cert-manager
spec:
acme:
email: [email protected]
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: cloudflare-clusterissuer-account-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
Una vez que ya tenemos todo esto, debemos modificar el ingress para utilizar certificados SSL. Agregaremos los siguientes campos.
1
2
3
4
5
6
7
8
9
10
metadata:
annotations:
traefik.ingress.kubernetes.io/router.tls: "true"
cert-manager.io/cluster-issuer: cloudflare-clusterissuer
---
spec:
tls:
- hosts:
- nginx-k3s.home.cervant.net
secretName: nginx-k3s.home.cervant.net-tls
El manifiesto completo quedaría así.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
namespace: blog
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web, websecure
traefik.ingress.kubernetes.io/router.tls: "true"
cert-manager.io/cluster-issuer: cloudflare-clusterissuer
spec:
tls:
- hosts:
- nginx-k3s.home.cervant.net
secretName: nginx-k3s.home.cervant.net-tls
rules:
- host: nginx-k3s.home.cervant.net
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
Actualizamos la configuración con kubectl apply -f ingress.yml
.
Podemos validar si el certificado se generó correctamente con el comando
1
kubectl describe certificate nginx-k3s.home.cervant.net-tls -n blog
Al ingresar nuevamente a Nginx veremos que ya cuenta con su certificado SSL.
Referencias
Construye, automatiza, repite. ¡Nos vemos en el próximo post!