Subscribe to receive notifications of new posts:

Kubectl con Cloudflare Zero Trust

06/24/2022

6 min read
Kubectl with Cloudflare Zero Trust

Cloudflare utiliza con regularidad Kubernetes para las cargas de trabajo de ingeniería. Lo usa para activar el backend de nuestras API y para gestionar el procesamiento por lotes, como la agregación de análisis y la detección de bots, así como para las herramientas de ingeniería, como nuestros canales CI/CD. Sin embargo, entre los equilibradores de carga, los servidores de la API, etcd, los ingresos y los pods, la superficie que expone Kubernetes puede ser bastante grande.

En esta publicación, comentaremos cómo nuestro equipo de ingeniería prueba primero Cloudflare Zero Trust a nivel interno para proteger Kubernetes, y activa kubectl sin proxies.

Nuestro enfoque general para la seguridad de Kubernetes

Como parte de nuestras medidas de seguridad, limitamos considerablemente lo que puede acceder a nuestros clústeres a través de la red. Cuando se expone un servicio de red, añadimos protecciones adicionales, como exigir la autenticación de Cloudflare Access o TLS mutuo (o ambos) para acceder a los recursos de ingreso.

Estas restricciones de red incluyen el acceso al servidor de la API del clúster. Sin este acceso, los ingenieros de Cloudflare no podrían utilizar herramientas como kubectl para examinar los recursos de su equipo. Aunque creemos que las Implementaciones continuas y GitOps son buenas prácticas, permitir que los desarrolladores usen la API de Kubernetes ayuda en la solución de problemas y a aumentar la velocidad de los desarrolladores. No tener acceso hubiera sido un problema.

Usamos Cloudflare Zero Trust para satisfacer nuestros requisitos de seguridad, y queríamos contar cómo lo estamos utilizando, y el proceso que nos ha llevado hasta aquí.

Antes de Zero Trust

En el entorno anterior a Zero Trust, los ingenieros podían acceder a la API de Kubernetes conectándose a un dispositivo VPN. Aunque es algo habitual en el sector, y permite el acceso a la API, también dejaba a los ingenieros como clientes en la red interna: tenían mucho más acceso a la red del necesario.

No nos gustaba esta situación, pero ese fue el statu quo durante varios años. A principios de 2020 retiramos nuestra VPN, y entonces el equipo de Kubernetes tuvo que encontrar otra solución.

Kubernetes con Cloudflare Tunnels

En ese momento trabajamos estrechamente con el equipo que desarrolla Cloudflare Tunnels para que fuera posible gestionar las conexiones kubectl utilizando Access y los túneles cloudflared.

Aunque esto funcionaba para nuestros usuarios de ingeniería, era un obstáculo importante para la incorporación de nuevos empleados. Cada clúster de Kubernetes necesitaba su propia conexión de túnel desde el dispositivo del ingeniero, lo que hacía que el cambio entre clústeres fuera incómodo. Aunque kubectl permitía la conexión mediante proxies SOCKS, esta compatibilidad no era válida para todas las herramientas del ecosistema Kubernetes.

Seguimos usando esta solución a nivel interno mientras buscábamos una solución mejor.

Kubernetes con Zero Trust

Desde el lanzamiento de Cloudflare One, hemos estado probando primero a nivel interno el agente Zero Trust en distintas configuraciones. Al principio, lo habíamos utilizado para implementar un DNS seguro con 1.1.1.1. Con el paso del tiempo, empezamos a utilizarlo para probar primero a nivel interno funciones adicionales de Zero Trust.

Ahora estamos aprovechando el enrutamiento de la red privada en Cloudflare Zero Trust para permitir que los ingenieros accedan a las API de Kubernetes sin que haya que configurar túneles cloudflared, o configurar kubectl y otras herramientas del ecosistema Kubernetes para usar túneles. Esto no es algo específico de Cloudflare, ¡puedes hacerlo hoy mismo para tu equipo!

Configurar Zero Trust

Para habilitar la infraestructura como código, utilizamos una herramienta de gestión de la configuración para nuestra configuración Zero Trust, que hemos adaptado a continuación. Sin embargo, es posible conseguir la misma configuración mediante el panel de control de Cloudflare Zero Trust.

Lo primero que tenemos que hacer es crear un nuevo túnel. Se usará este túnel para conectar la red perimetral de Cloudflare a la API de Kubernetes. Ejecutamos los puntos de conexión del túnel en Kubernetes, utilizando la configuración que mostramos más adelante en esta publicación.

resource "cloudflare_argo_tunnel" "k8s_zero_trust_tunnel" {
  account_id = var.account_id
  name       = "k8s_zero_trust_tunnel"
  secret     = var.tunnel_secret
}

El secreto "tunnel_secret" debe ser un número aleatorio de 32 bytes, que debes guardar de forma temporal, ya que lo volveremos a usar más tarde para la configuración de Kubernetes.

Después de haber creado el túnel, tenemos que crear las rutas para que la red de Cloudflare sepa qué tráfico debe enviar por el túnel.

resource "cloudflare_tunnel_route" "k8s_zero_trust_tunnel_ipv4" {
  account_id = var.account_id
  tunnel_id  = cloudflare_argo_tunnel.k8s_zero_trust_tunnel.id
  network    = "198.51.100.101/32"
  comment    = "Kubernetes API Server (IPv4)"
}
 
resource "cloudflare_tunnel_route" "k8s_zero_trust_tunnel_ipv6" {
  account_id = var.account_id
  tunnel_id  = cloudflare_argo_tunnel.k8s_zero_trust_tunnel.id
  network    = "2001:DB8::101/128"
  comment    = "Kubernetes API Server (IPv6)"
}

Ofrecemos compatibilidad con el acceso a la API de Kubernetes mediante direcciones IPv4 e IPv6, así que configuramos rutas para ambas. Si te conectas a tu servidor de la API mediante un nombre de host, estas direcciones IP deben coincidir con lo que se devuelve a través de una búsqueda de DNS.

A continuación, configuraremos los parámetros de Cloudflare Gateway para que sea compatible con los servidores y clientes de la API.

resource "cloudflare_teams_list" "k8s_apiserver_ips" {
  account_id = var.account_id
  name       = "Kubernetes API IPs"
  type       = "IP"
  items      = ["198.51.100.101/32", "2001:DB8::101/128"]
}
 
resource "cloudflare_teams_rule" "k8s_apiserver_zero_trust_http" {
  account_id  = var.account_id
  name        = "Don't inspect Kubernetes API"
  description = "Allow connections from kubectl to API"
  precedence  = 10000
  action      = "off"
  enabled     = true
  filters     = ["http"]
  traffic     = format("any(http.conn.dst_ip[*] in $%s)", replace(cloudflare_teams_list.k8s_apiserver_ips.id, "-", ""))
}

Como utilizamos TLS mutuo entre los clientes y el servidor de la API, y no todo el tráfico entre kubectl y los servidores de la API es HTTP, hemos desactivado la inspección de HTTP para estas conexiones.

Para personalizar aún más tu seguridad, puedes emparejar estas reglas con otras de Zero Trust, como confirmación de dispositivos, duración de la sesión y políticas de acceso de usuarios y grupos.

Implementar túneles

Una vez que hayas creado y configurado tus túneles, puedes implementar sus puntos de conexión en tu red. Hemos optado por implementar los túneles como pods, ya que esto nos permite utilizar las estrategias de implementación de Kubernetes para desplegar las actualizaciones y gestionar los fallos de nodos.

apiVersion: v1
kind: ConfigMap
metadata:
  name: tunnel-zt
  namespace: example
  labels:
    tunnel: api-zt
data:
  config.yaml: |
    tunnel: 8e343b13-a087-48ea-825f-9783931ff2a5
    credentials-file: /opt/zt/creds/creds.json
    metrics: 0.0.0.0:8081
    warp-routing:
        enabled: true

Esto crea un ConfigMap de Kubernetes con una configuración básica, que permite el enrutamiento WARP para el ID del túnel especificado. Puedes obtener este ID de túnel desde tu sistema de gestión de configuración, desde el panel de control de Cloudflare Zero Trust, o ejecutando el siguiente comando desde otro dispositivo conectado a la misma cuenta.

cloudflared tunnel list

A continuación, tendremos que crear un secreto para nuestras credenciales del túnel. Aunque deberías utilizar un sistema de gestión de secretos, para simplificar crearemos uno directamente aquí.

jq -cn --arg accountTag $CF_ACCOUNT_TAG \
       --arg tunnelID $CF_TUNNEL_ID \
       --arg tunnelName $CF_TUNNEL_NAME \
       --arg tunnelSecret $CF_TUNNEL_SECRET \
   '{AccountTag: $accountTag, TunnelID: $tunnelID, TunnelName: $tunnelName, TunnelSecret: $tunnelSecret}' | \
kubectl create secret generic -n example tunnel-creds --from-file=creds.json=/dev/stdin

Esto crea un nuevo secreto "tunnel-creds" en el espacio de nombres "example" con el archivo de credenciales que espera el túnel.

Ahora podemos implementar los túneles. Implementamos varias réplicas para garantizar que algunas estén siempre disponibles, incluso mientras se vacían los nodos.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    tunnel: api-zt
  name: tunnel-api-zt
  namespace: example
spec:
  replicas: 3
  selector:
    matchLabels:
      tunnel: api-zt
  strategy:
    rollingUpdate:
      maxSurge: 0
      maxUnavailable: 1
  template:
    metadata:
      labels:
        tunnel: api-zt
    spec:
      containers:
        - args:
            - tunnel
            - --config
            - /opt/zt/config/config.yaml
            - run
          env:
            - name: GOMAXPROCS
              value: "2"
            - name: TZ
              value: UTC
          image: cloudflare/cloudflared:2022.5.3
          livenessProbe:
            failureThreshold: 1
            httpGet:
              path: /ready
              port: 8081
            initialDelaySeconds: 10
            periodSeconds: 10
          name: tunnel
          ports:
            - containerPort: 8081
              name: http-metrics
          resources:
            limits:
              cpu: "1"
              memory: 100Mi
          volumeMounts:
            - mountPath: /opt/zt/config
              name: config
              readOnly: true
            - mountPath: /opt/zt/creds
              name: creds
              readOnly: true
      volumes:
        - secret:
            name: tunnel-creds
          name: creds
        - configMap:
            name: tunnel-api-zt
          name: config

Uso de Kubectl con Cloudflare Zero Trust

Screenshot of the Cloudflare WARP app showing it connected to Teams

Después de implementar el agente Cloudflare Zero Trust, los miembros de tu equipo podrán acceder a la API de Kubernetes sin tener que configurar ningún túnel SOCKS especial.

kubectl version --short
Client Version: v1.24.1
Server Version: v1.24.1

¿Y ahora qué?

Si lo pruebas, envíanos tus comentarios. Seguimos mejorando Zero Trust para los flujos de trabajo que no usen HTTP.

We protect entire corporate networks, help customers build Internet-scale applications efficiently, accelerate any website or Internet application, ward off DDoS attacks, keep hackers at bay, and can help you on your journey to Zero Trust.

Visit 1.1.1.1 from any device to get started with our free app that makes your Internet faster and safer.

To learn more about our mission to help build a better Internet, start here. If you're looking for a new career direction, check out our open positions.
Cloudflare One Week (ES)Security (ES)Cloudflare Zero Trust (ES)Kubernetes (ES)Español

Follow on X

Terin Stock|@terinjokes
Cloudflare|@cloudflare

Related posts