Certificados SSL gratuitos y automáticos en Kubernetes K3s usando Cert Manager

Certificados SSL gratuitos y automáticos en Kubernetes K3s usando Cert Manager

Obtenga certificados SSL gratuitos y automáticos usando el administrador de certificados y Let's Encrypt

En el escenario actual, los certificados SSL son la parte más importante de la implementación de una aplicación en Internet. Son solo los atributos más importantes los que determinan si sus sitios web son seguros o no.

image.png

Este símbolo transmite a su cliente que el sitio web que está visitando es seguro, protegido y verificado. Entonces, ¿cómo logra realmente HTTPS en su sitio web?

HTTP + SSL = HTTPS.

Obtener un certificado SSL no es tan fácil. Además, también es caro. En el mundo actual, donde Kubernetes está predominantemente en todas partes.

Y millones de recursos de Ingress en Kubernetes, se vuelve realmente difícil obtener una cantidad tan grande de certificados, monitorearlos y rotarlos cada vez.

Esto sería un Dolor de Cabeza para nosotros los DevOps. ¿Qué sucede si les digo que existe una herramienta que podría obtener certificados SSL gratuitos y rotarlos automáticamente cuando caduquen?

Aquí viene Cert-Manager

Cert-Manager automatiza el aprovisionamiento de certificados dentro de los clústeres de Kubernetes. Proporciona un conjunto de recursos personalizados para emitir certificados y adjuntarlos a los servicios.

Uno de los casos de uso más comunes es proteger las aplicaciones web y las API con certificados SSL de Let's Encrypt . Aquí se explica cómo agregar Cert-Manager a su clúster, configurar un emisor de certificados de Let's Encrypt y adquirir un certificado para pods expuestos a través de un Ingress .

¿De qué se trata toda la historia?

Comprender los conceptos de cert-manager Comprender varios desafíos de ACME (DNS01, HTTP01) Crear un certificado de Let's Encrypt Staging y finalmente obtenga el certificado de Let's Encrypt Production.

Crear certificado con cert-manager

Cert Manager admite la solicitud de certificados de servidores ACME (Entorno de gestión de certificados automatizado). Un ejemplo de estos servidores ACME es Let's Encrypt. El protocolo ACME admite varios mecanismos.

  • HTTP01
  • DNS01

HTTP01 es relativamente más fácil en comparación con el mecanismo DNS01. Pero el mecanismo DNS01 es más seguro que HTTP01.

En el desafío DNS01 , la propiedad de su dominio se prueba cuando el administrador de certificados puede crear con éxito un registro TXT en su zona alojada.

En HTTP01, la propiedad de su dominio se prueba cuando el administrador de certificados puede garantizar con éxito que un archivo está presente en el dominio en una ruta determinada.

Let's Encrypt tiene 2 URL de servidor ACME

Ambiente Staging acme-staging-v02.api.letsencrypt.org/direct..

Producción: acme-v02.api.letsencrypt.org/directory

Hay algunos límites de tasa restringidos en el servidor de producción (Ej: Certificados por dominio registrado -> 50 por semana, etc.).

Por lo tanto, siempre se recomienda realizar cualquier tipo de prueba en la URL de prueba "staging" y luego pasar al entorno de producción.

Muy bien, suficiente de la charla. Pasemos ahora a la acción.

¡Suena bien! ¿Qué necesito?

Deberías cumplir con estos pre-requisitos:

  • Tener un clúster de kubernetes funcional con nginx como ingress-controller
  • Tener helm instalado ò instalar con los manifest de la pagina oficial de cert-manager
  • Tener un dominio que apunte hacia el clúster , estoy usando nip.io
  • Descarga mi Repo github
  • Ganas de aprender de rompercosas y desafiar al SSL 🦸‍♀️

¡Empecemos!

Primero necesitamos añadir el repositorio de helm para cert-manager:

helm repo add jetstack https://charts.jetstack.io

Siempre validen la version del helm chart en su web oficial

$ helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.7.1 \

Instalando con kubectl

$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.7.1/cert-manager.crds.yaml

Dale unos segundos de margen para que termine y deberías ver un mensaje de SUCCESS con éxito.

Recuerden que necesitamos tener instalado nginx controller lo puede instalar desde su pagina oficial Website

Pero Les traigo una Documentación que realiza Gisela Torres , muy bien explicado con relación al ingress-controller con Nginx ademas les explica sobre el dominio "temporal" nip.io

Configurar un Ingress Controller con Nginx, Helm y nip.io

Acá la documentación

Luego que revisen los pasos del ingress-controller son muy simples.

Ahora si vamos a lo que venimos!!!

Primer Paso realicen un chequeo si tienen el ingress.controller nginx

root@localhost:~# k get svc -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE
ingress-nginx-controller-admission   ClusterIP      10.43.147.229   <none>         443/TCP                      119m
ingress-nginx-controller             LoadBalancer   10.43.194.181   45.79.215.27   80:30173/TCP,443:31766/TCP   119m

Si vieron la documentación voy a tomar en cuenta el External-IP para la configuracion de mi dominio nip.io y el cert-manager

Ahora vamos a crear el ClusterIssuer

Podemos usar tanto un Issuer como un ClusterIssuer (namespace vs cluster-scoped). Es exactamente lo mismo, solo cambia el scope. El Issuer/ClusterIssuer representa la CA de la que queremos obtener el nuevo certificado, en este caso usaremos LetsEncrypt.

Fíjate a continuación que el objeto ClusterIssuer realmente es muy simple. Tanto el nombre como el nombre del secret pueden ser lo que tú quieras:

Recuerden dejo el repo en github

Les voy a mostrar la configuracion tanto para ambiente de prueba como la de producción

cluster-issuer-staging.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
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:
    - selector: {}
      http01:
        ingress:
          class: nginx

cluster-issuer-production.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-production
  namespace: default
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: <YOUR_EMAIL>
    privateKeySecretRef:
      name: letsencrypt-production
    solvers:
    - selector: {}
      http01:
        ingress:
          class: nginx

📌 Importante: El campo email, debe ser un email real no un , porque sino les dará error

Aplicamos con:

kubectl apply -f  cluster-issuer-staging.yaml

y validamos si se aplico y en que estado se encuentra:

root@localhost:~# k get ClusterIssuer -A
NAME                     READY   AGE
letsencrypt-production   True    111m
letsencrypt-staging      True    111m

Si aplicas ambos, asegura que todos tengan status TRUE

Ahora vamos a crear el certificado

certificate-staging.yaml

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: ssl-cert-staging
  namespace: default
spec:
  secretName: ssl-cert-staging
  issuerRef:
    name: letsencrypt-staging
    kind: ClusterIssuer
  commonName: <YOUR_IP>.nip.io
  dnsNames:
  - <YOUR_IP>.nip.io

certificate-production.yaml

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: ssl-cert-production
  namespace: default
spec:
  secretName: ssl-cert-production
  issuerRef:
    name: letsencrypt-production
    kind: ClusterIssuer
  commonName: <YOUR_IP>.nip.io
  dnsNames:
  - <YOUR_IP>.nip.io

Aca dependiendo cual certificado voy aplicar asegura que no tenga ambos el mismo el dominio por ejemplo en staging podemos usar otro un traefi.me o algo o dominio ya personalizando

para el caso de este Hand-On estoy trabajando con el del produccion

kubectl apply -f  certificate-production.yaml

Asi que reviso el status

root@localhost:~# k get Certificate -A
NAMESPACE   NAME                  READY   SECRET                AGE
default     ssl-cert-production   True    ssl-cert-production   110m

Todo esta muy bien,!! yes, por suerte, pero todo puede pasar, así que siempre tengan a la mano

Kubectl describe xxxxx es un gran aliado

Ya tenemos los 2 primeros pasos cubiertos

Vamos a levantar una aplicación bastante basic un nginx

Vamos a hacer un deploy muy simple con un nginx, lo expondremos como servicio y después crearemos un ingress. Así pues, vamos allá:

kubectl create deployment nginx --image nginx:alpine 
kubectl expose deployment nginx --port 80 --target-port 80

Ahora crearemos un nuevo objeto ingress para hacer accesible el servicio a través del ingress controller. Recuerda reemplazar a continuación las ocurrencias del host con tu propio dominio:

ingress.nginx.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    #cert-manager.io/cluster-issuer: letsencrypt-production
    kubernetes.io/ingress.class: "nginx"
  labels:
    app: nginx
  name: nginx
  namespace: default
spec:
  rules:
  - host: <YOUR_IP>.nip.io
    http:
      paths:
      - backend:
          service:
            name: nginx
            port: 
              number: 80
        path: /
        pathType: Prefix
  #Descomenta esto despues que este aplicado el certificado      
  # tls:
  # - hosts:
  #   - <YOUR_IP>.nip.io
  #   secretName: ssl-cert-production

Aplicamos el nuevo manifest:

kubectl apply -f ingress-nginx.yaml

Si ahora intentas acceder al host que has definido en el ingress verás un mensaje de error conforme tu certificado no es válido

Ahora para poder solventarlo tenemos que apuntar nuestro ingress al certificado que previamente y toca modificar el ingress-nginx.yaml

cert-manager.io/cluster-issuer: letsencrypt-production

y quedaria de esta manera el ingress-nginx.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-production
    kubernetes.io/ingress.class: "nginx"
  labels:
    app: nginx
  name: nginx
  namespace: default
spec:
  rules:
  - host: <YOUR_IP>.nip.io
    http:
      paths:
      - backend:
          service:
            name: nginx
            port: 
              number: 80
        path: /
        pathType: Prefix  
  tls:
  - hosts:
    - <YOUR_IP>.nip.io
    secretName: ssl-cert-production

Aplicamos de nuevo manifest:

kubectl apply -f ingress-nginx.yaml

Aplica el ingress de nuevo (o guarda los cambios si estás haciendo un edit) y revisa el estado del objeto «cert». Deberías ver algo así:

root@localhost:~# kubectl get cert -n default
NAME                  READY   SECRET                AGE
ssl-cert-production   False    ssl-cert-production   119m

Luego de un minuto pasa a True

root@localhost:~# kubectl get cert -n default
NAME                  READY   SECRET                AGE
ssl-cert-production   True    ssl-cert-production   119m

Es importante si pasa mas de 3 min y mantiene el FALSE hay algo mal, recuerden Kubectl describe es el mejor aliado

… EUREKA ¡hemos conseguido el certificado!

Haz un test refrescando la página o abriendo una nueva pestaña y deberías ver el mensaje de bienvenida de Nginx. Si inspeccionas el certificado, verás que efectivamente éste ha sido expedido por LetsEncrypt:

image.png

root@localhost:~# curl -kv https://45.79.215.27.nip.io
*   Trying 45.79.215.27:443...
* Connected to 45.79.215.27.nip.io (45.79.215.27) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2

Que genialidad

Que pasa si tenemos problemas con los Certificados Troubleshooting

Si presenta problemas con cert-manager, su mejor amigo es kubectl describe, esto le brindará información sobre los recursos, así como sobre eventos recientes. No se recomienda utilizar los registros, ya que son bastante detallados y solo deben consultarse si los siguientes pasos no brindan ayuda.

Documentación

Documentación Adicional que recomiendo:

Configurar un Ingress Controller con Nginx, Helm y nip.io

Linode cuenta con un cupon de descuento de 100$ asi que podemos hacer mucho labs alli linode.com/es

Documentación de cert manager

nip.io

Y viendo que no rompimos nada dejo esto por acá

Que vimos hoy:

  • Como instalar cert-manager
  • Como configurar un nuevo ClusterIssuer
  • Como expedir de forma sencilla un certificado

Vieron que es un proceso simple, ¿verdad?

También hay otras formas de validar DNS pero son temas mas avanzados y esas aguas hay que llevarlos con calma, lo vemos luego

Recuerden seguirme en mis redes sociales busquen como @295devops

y toda consulta en linkedin

Y para no olvidar le dejo unos pasos en vídeo por si no me entendieron en toda la historia xD

A la primera se fue todo a la m..... todo , 3 Laboratorios , pero la constancia es el éxito y salió andando , así que "Solo la Acción crea Acción"

Dejo ahora el Vídeo!