Skip to main content

Implementar TLS en Kubernetes

Escrito por
Headshot of Rubaiat Hossain

Rubaiat Hossain

feature kubernetes polp

31 de julio de 2023

0 minutos de lectura

A medida que la tecnología en la nube sigue evolucionando, la demanda de Kubernetes se dispara. Como resultado, la seguridad se ha convertido en una prioridad para los desarrolladores que buscan proteger los datos de sus aplicaciones. Aquí es donde entra en juego Transport Layer Security (TLS). TLS es esencial para garantizar una conexión segura entre tus aplicaciones e Internet.

TLS aprovecha la criptografía asimétrica y simétrica para mantener tus datos seguros durante la transmisión y cuando están almacenados. El certificado TLS que se usa en Kubernetes suele ser un certificado de clave pública emitido por una autoridad de certificación (CA) de confianza. Este certificado contiene información sobre la identidad del servidor, la clave pública que se usa para el cifrado y la firma digital de la CA que lo emitió.

Este artículo te guiará en la implementación de una conexión TLS para tus aplicaciones en un clúster de Kubernetes y te ayudará a comprender a fondo TLS y su importancia para proteger tus aplicaciones y datos.

Cómo se implementa TLS para las cargas de trabajo de Kubernetes

Cuando llegan solicitudes a una aplicación que se ejecuta en un clúster de Kubernetes, pasan por un componente de red que funciona como puerta de enlace para el tráfico entrante. Según cómo configures tu aplicación, este componente de red puede ser un controlador de Ingress de Kubernetes, un servicio de balanceador de carga, un servicio ClusterIP o un servicio NodePort.

Kubernetes no ofrece una implementación predeterminada del cifrado TLS para la comunicación entre el cliente y el componente de red. Esto significa que las solicitudes se atienden mediante HTTP, no HTTPS. Sin embargo, puedes configurar fácilmente tu aplicación de Kubernetes para que use HTTPS y lograr una comunicación segura con TLS.

Kubernetes también ofrece funciones como Secrets y ConfigMaps, que puedes usar para administrar de forma segura tus certificados TLS y otros datos confidenciales que necesita tu aplicación.

Históricamente, TLS (y su predecesor, SSL) se implementaba entre sistemas y usuarios que necesitaban comunicaciones seguras. Con la proliferación de los sistemas distribuidos y la enorme reducción del costo y el impacto en el rendimiento de implementar TLS —por no mencionar las crecientes preocupaciones sobre la privacidad—, la mayoría de los expertos ahora recomienda cifrar todo el tráfico. Estos son algunos casos de uso comunes del cifrado de red:

  • Sistemas de pago: Si tu aplicación maneja datos de pago, como cuentas bancarias y tarjetas de crédito, debes implementar TLS. Es un requisito normativo y es necesario para garantizar la seguridad de los datos de los usuarios durante la transmisión. Cifrar los datos de pago también genera confianza en tus clientes y les permite sentirse seguros al usar tus servicios.

  • Cifrado de datos de extremo a extremo con una malla de servicios: El uso de un mecanismo de cifrado de datos de extremo a extremo con una malla de servicios como Istio permite que TLS proteja la comunicación entre distintos microservicios dentro de un clúster de Kubernetes. Este es un enfoque popular para las arquitecturas modernas de microservicios distribuidos.

  • IoT y computación en el borde: Las aplicaciones de Kubernetes que interactúan con dispositivos de IoT o sistemas de computación en el borde deben implementar TLS para proteger la transmisión de datos entre los dispositivos y la nube, y evitar el acceso no autorizado a los datos generados por los dispositivos de IoT.

  • Redes de distribución de contenido (CDN): Si tus aplicaciones usan CDN para almacenar en caché y entregar contenido, implementar TLS puede ayudarte a garantizar que el contenido se transmita de forma segura y evitar la manipulación de datos o el acceso no autorizado.

Implementar una configuración de TLS en Kubernetes

En las siguientes secciones, implementarás TLS para una aplicación sencilla de Kubernetes con un proyecto de Node.js que simula una aplicación de procesamiento de pagos. El código de la aplicación y la configuración necesaria de Kubernetes están disponibles en este repositorio de GitHub.

Requisitos previos

Para seguir este tutorial, necesitas lo siguiente:

  • Un motor de ejecución de contenedores: Para este artículo, supondremos que tienes Docker instalado y configurado en tu equipo.

  • Una distribución de Kubernetes: Debes instalar una distribución de Kubernetes para crear el clúster de Kubernetes y otros recursos necesarios, como implementaciones y servicios. En este tutorial se usa kind (v0.18.0), pero puedes usar cualquier otra distribución de Kubernetes, como minikube o K3s.

  • kubectl: Esta interfaz de línea de comandos se usa para comunicarse con tu clúster de Kubernetes y ejecutar comandos. En este tutorial se usa la versión 1.26.

  • mkcert: Se usa para obtener un certificado TLS de confianza con un nombre de dominio personalizado para tu equipo de desarrollo. Puedes instalar mkcert en tu equipo de desarrollo siguiendo las instrucciones oficiales.

  • Git y Helm: Necesitas tener Git instalado para usar el proyecto de demostración de forma local y el administrador de paquetes Helm para Kubernetes. En esta guía se usa Helm v3.11.2.

En las siguientes secciones, te guiaremos en la implementación de TLS para una aplicación de pagos de demostración que se ejecuta en un clúster local de Kubernetes. Primero, implementarás la aplicación en tu clúster de kind y verificarás que use HTTP en lugar de HTTPS. Luego, generarás un certificado TLS autofirmado y configurarás la aplicación de pagos para que lo use. Por último, crearás un certificado TLS de confianza con mkcert y verificarás que puedas acceder a tu aplicación de Kubernetes mediante HTTPS.

Implementar la aplicación de pagos en Kubernetes

Para comenzar a implementar TLS en tu aplicación de ejemplo basada en Kubernetes, debes clonar la aplicación en tu equipo local ejecutando el siguiente comando:

git clone https://github.com/snyk-snippets/tls-in-k8s.git

Luego, cambia al directorio del proyecto con este comando:

cd k8s-tls-demo

Una vez que estés en el directorio del proyecto, podrás implementar la aplicación en tu clúster de Kubernetes.

Usa el siguiente comando para crear tu clúster de kind:

kind create cluster --config=config.yaml

Nota: El archivo config.yaml vincula un par de puertos de los nodos de kind a tu equipo local. Esto es necesario en las instalaciones de Docker Desktop, ya que los contenedores de kind se ejecutan dentro de una máquina virtual (VM). Si usas una estación de trabajo Linux con Docker instalado de forma nativa (sin la VM de Docker Desktop), puedes omitir aquí la opción --config.

A continuación, compilaremos la imagen del contenedor y la cargaremos en nuestro clúster de kind.

docker build -t demo-payment-app .
kind load docker-image demo-payment-app

Nota: Si lo prefieres, puedes subir esa imagen a un registro en lugar de usar kind load. En ese caso, también tendrás que editar el archivo deployment.yaml (que se usa más adelante) con la información de tu registro y actualizar imagePullPolicy a “Always” para que descargue esa imagen.

Una vez creado el clúster, implementa la aplicación en él con estos comandos:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

Espera unos minutos a que Kubernetes cree los pods y otros recursos necesarios. Puedes comprobar el estado de tus recursos con estos comandos:

kubectl get deployments
kubectl get pods

El proyecto de demostración expone la aplicación de pagos mediante un servicio nodePort en el puerto 30080. Si defines un servicio de Kubernetes sin especificar el campo de tipo, Kubernetes asigna el tipo de servicio predeterminado: ClusterIP.

Sin embargo, solo se puede acceder a la dirección IP expuesta por ClusterIP desde la red interna del clúster. Esto significa que no puedes ver la aplicación que se ejecuta en tu clúster desde un cliente externo, como tu navegador web. En producción, quizá quieras usar un servicio LoadBalancer para que tu proveedor de nube pueda ofrecer un balanceador de carga externo con una dirección IP de acceso público.

Usa estos comandos para ver los servicios de esta aplicación de demostración:

kubectl get services

Según tu entorno de ejecución, puedes acceder a la aplicación de demostración de una de estas dos maneras:

Basado en VM (por ejemplo, Docker Desktop):

Para acceder a la aplicación de demostración desde tu navegador, usarás la vinculación de puertos de kind configurada en el archivo config.yaml y simplemente ingresarás localhost:30080.

Sin VM (por ejemplo, Linux sin Docker Desktop):

Para acceder a la aplicación de demostración desde tu navegador, debes encontrar la dirección IP expuesta por nodePort con el siguiente comando:

kubectl get nodes -o wide

Debería mostrarse la INTERNAL-IP del plano de control de Kubernetes (es decir, 172.18.0.2). Ahora puedes acceder a la aplicación de pagos con lo siguiente:

http://172.18.0.2:30080

Asegúrate de reemplazar la dirección IP por la INTERNAL-IP real del plano de control de Kubernetes o por localhost, según las instrucciones anteriores.

Al abrir en el navegador la dirección IP y el puerto anteriores, se muestra la Página de pago, donde puedes ingresar los datos de la tarjeta. Como esta es una aplicación de ejemplo, no se procesa ningún pago y los datos no se guardan en ningún lugar:

Ventana del navegador que muestra un formulario de página de pago con campos para el número de tarjeta, la fecha de vencimiento y el CVV, además de un botón para enviar el pago.

Según el navegador, es posible que veas algún indicador junto a la barra de URL que diga No es seguro. Esto indica que la aplicación se sirve mediante HTTP, no HTTPS. Puedes verificarlo haciendo clic en el aviso:

El navegador muestra un formulario de pago mientras una advertencia de seguridad indica que la conexión al sitio no es segura.

Implementar un certificado TLS autofirmado para tu aplicación

Ahora, implementa TLS para la aplicación de ejemplo de Kubernetes. Crea un certificado autofirmado y una clave privada:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=my-demo-app.local"

Luego, crea un Secret de Kubernetes que contenga el certificado y la clave privada:

kubectl create secret tls my-demo-app-tls --key tls.key --cert tls.crt

Ahora debes instalar el controlador Nginx Ingress para que pueda redirigir las solicitudes entrantes a tu aplicación de pagos y usar HTTPS. Como expusiste la aplicación con nodePort, debes instalar Ingress mediante un archivo de valores personalizado que especifique el tipo de servicio como NodePort.

Crea un archivo llamado ingress-values.yaml con el siguiente contenido:

controller:
  service:
    type: NodePort
    nodePorts:
      http: 32080
      https: 32443

Luego, instala el controlador Nginx Ingress con Helm y el archivo de valores personalizado:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx -f ingress-values.yaml

Crea un archivo ingress.yaml con el siguiente contenido:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-payment-app-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
  - hosts:
    - my-demo-app.local
    secretName: my-demo-app-tls
  rules:
  - host: my-demo-app.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: demo-payment-app
            port:
              number: 80

Y aplica este archivo de manifiesto con el siguiente comando:

kubectl apply -f ingress.yaml

Actualiza tu archivo /etc/hosts con la siguiente entrada:

<control_plane_IP> my-demo-app.local

Asegúrate de reemplazar <control_plane_IP> por 127.0.0.1 si usas Docker Desktop, o por la dirección IP que obtuviste al ejecutar kubectl get nodes -o wide si no lo usas.

Ahora puedes acceder a la aplicación de pagos mediante HTTPS. Ve a https://my-demo-app.local:32443 en tu navegador. La primera vez que visites la aplicación, el navegador debería mostrar una página de advertencia que te permitirá aceptar el riesgo y continuar. Después de hacerlo, podrás acceder al sitio mediante HTTPS:

Navegador que muestra un formulario de pago con campos para el número de tarjeta, la fecha de vencimiento y el CVV; la barra de direcciones muestra una advertencia HTTPS de «No seguro».

El navegador muestra este error porque el certificado TLS es autofirmado. Esto se nota porque la parte HTTPS de la URL aparece tachada.

Implementar un certificado TLS de confianza para tu aplicación

Para resolverlo, puedes usar mkcert y crear un certificado de confianza para tu entorno de desarrollo. Para ello, crea una CA local y genera un certificado de confianza para tu dominio local:

mkcert -install
mkcert my-demo-app.local

Elimina el Secret anterior y crea uno nuevo para mkcert:

kubectl delete secret my-demo-app-tls
kubectl create secret tls my-demo-app-tls --key 
my-demo-app.local-key.pem --cert my-demo-app.local.pem

Por último, vuelve a implementar el recurso Ingress ejecutando lo siguiente:

kubectl delete ingress demo-payment-app-ingress
kubectl apply -f ingress.yaml

Verificar TLS en tu aplicación de Kubernetes

En este punto, deberías poder visitar tu aplicación de pagos con un certificado TLS de confianza. Reinicia el navegador y luego ve a https://my-demo-app.local:32443 para que funcione el nuevo certificado. Esta vez no debería aparecer ninguna advertencia y la parte HTTPS de la URL no estará tachada, como ocurre en los sitios web protegidos normalmente con TLS:

Ventana del navegador que muestra una página de pago con campos para el número de tarjeta, la fecha de vencimiento y el CVV, además de un botón para enviar el pago.

Haz clic en el ícono del candado en la barra de URL para verificar que el navegador confía en el certificado TLS y que la conexión es segura:

Navegador que muestra un formulario de pago con campos para el número de tarjeta, la fecha de vencimiento y el CVV, junto a un panel de seguridad que confirma que la conexión es segura.

Puedes encontrar los ejemplos de código actualizados en la rama solution de nuestro repositorio del proyecto en GitHub.

Conclusión

Al trabajar con datos confidenciales, TLS te brinda la seguridad que necesitas. Sin embargo, implementar TLS puede ser difícil si no sabes cómo hacerlo.

En este tutorial, aprendiste a implementar TLS para una aplicación implementada en un clúster local de Kubernetes. También puedes aplicar estos principios para implementar TLS en aplicaciones alojadas en tus instalaciones o en un proveedor de nube.

Al implementar TLS para un sistema de producción, considera usar un certificado público de una autoridad certificadora (CA) de confianza, como Let's Encrypt. Aunque para esto necesitas tener acceso al dominio de tu sitio, puedes implementar configuraciones adicionales, como usar un servicio de balanceador de carga para exponer tu aplicación o administrar varios certificados mediante un administrador de certificados como cert-manager. Entre las ventajas de exponer tu aplicación mediante un balanceador de carga se encuentran una mayor disponibilidad, escalabilidad y resiliencia. Además, usar un administrador de certificados facilita el aprovisionamiento y la administración de los certificados de tu clúster en el futuro.

Protege la infraestructura desde el origen

Snyk automatiza la seguridad y el cumplimiento de IaC en los flujos de trabajo, y detecta recursos con desviaciones de configuración y recursos faltantes.

Leer más

feature customer snowflake
Article

Seguridad desde el inicio: presentamos la integración de Snyk Studio con Snowflake Cortex Code

Snyk Studio se integra con Snowflake Cortex Code para analizar código generado por IA, dependencias y contenedores en busca de vulnerabilidades durante el desarrollo.

feature insights announcement
Blog

Compromiso de la cadena de suministro de node-gyp: un gusano de npm que se propaga solo y se oculta en binding.gyp

Un nuevo gusano de npm abusa de binding.gyp para activar node-gyp durante la instalación y permitir que paquetes maliciosos ejecuten código sin scripts del ciclo de vida. Roba credenciales, persiste en GitHub y se propaga entre mantenedores.

Article

Ataque a la cadena de suministro Miasma: código malicioso detectado en paquetes npm de @redhat-cloud-services

Un gusano de cadena de suministro llamado Miasma fue detectado en decenas de versiones npm de @redhat-cloud-services. El hook malicioso preinstall roba credenciales, sondea identidades en la nube y puede volver a publicar otros paquetes.