Entrada

HTTPS en Kubernetes

Configuración de certificados SSL automáticos para Kubernetes en K3s utilizando Cert-Manager y Traefik

HTTPS en Kubernetes

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.

Deployment

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.

Service

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!

Esta entrada está licenciada bajo CC BY 4.0 por el autor.