Cloudflare Access: autenticación delante de cualquier servicio, sin VPN

Cloudflare Access: autenticación delante de cualquier servicio, sin VPN

Un Jedi no muestra su posición. Ya lo vimos con Cloudflare Tunnel: sin puertos abiertos, sin IP expuesta, invisible desde internet.

Pero invisible no es sinónimo de inaccesible. La URL existe. Cloudflare la atiende. Y cualquiera que la conozca puede llamar a esa puerta.

Sun Tzu lo escribió hace dos mil quinientos años: defender la posición no es suficiente. Hay que controlar quién entra.

Cloudflare Access es esa capa de control. Antes de que una sola petición llegue a tu servicio, el usuario tiene que identificarse — con Google, GitHub o un código de un solo uso enviado al email. Sin contraseña compartida. Sin VPN. Sin cuenta local que gestionar.

Solo: demuestra quién eres. Y si tu identidad cumple la política, entras. Con el plan gratuito, hasta 50 usuarios.

Índice


Qué resuelve Access y qué no resuelve Tunnel

Tunnel resuelve el problema de la exposición: el servicio no es alcanzable directamente desde internet, el router no abre ningún puerto, tu IP real no aparece en ningún sitio. El vector de ataque de red desaparece.

Pero Tunnel no tiene opinión sobre quién se conecta. Si expones proxmox.tudominio.com sin nada más, cualquiera que conozca esa URL puede intentar autenticarse en Proxmox directamente. La autenticación que protege el servicio en ese caso es la del propio Proxmox — contraseña root, o lo que tengas configurado.

Access añade una capa de autenticación delante del servicio, antes de que la petición llegue a él. El flujo pasa a ser:

Usuario → Cloudflare Access (¿quién eres?) → ✓ identidad válida → Tunnel → servicio

Si el usuario no supera el check de identidad, la petición no llega al servicio. No hay contraseña de Proxmox que forzar. No hay interfaz de login que atacar. La superficie de ataque se reduce a cero para cualquier usuario no autorizado.


Cómo funciona Access por dentro

El mecanismo es sencillo. Cuando un usuario accede a un subdominio protegido por Access:

  1. Cloudflare detecta que hay una política de Access asociada a ese hostname
  2. Redirige al usuario a la pantalla de login de Cloudflare (cloudflareaccess.com)
  3. El usuario se autentica con el proveedor configurado (Google, GitHub, email OTP…)
  4. Cloudflare valida la identidad contra las reglas de la política
  5. Si la identidad cumple las condiciones: Cloudflare emite una cookie JWT (CF_Authorization) y redirige al servicio
  6. En peticiones posteriores, Cloudflare verifica la cookie. Si sigue siendo válida, pasa directo al servicio sin pedir login de nuevo

La cookie tiene una duración configurable (por defecto 24 horas). Cuando expira, el usuario tiene que volver a autenticarse — pero si ya está autenticado en el proveedor (Google, GitHub), el flujo es transparente: un redirect y ya está.

El servicio no sabe nada de todo esto. Solo recibe peticiones HTTP que ya han superado el check de identidad.


Configurar el primer proveedor de identidad

Antes de crear aplicaciones hay que configurar al menos un proveedor de identidad (IdP). Access soporta Google, GitHub, Microsoft, Okta, SAML genérico y varias opciones más. El más simple para empezar sin cuentas de empresa es Email OTP o Google OAuth.

Ve a one.dash.cloudflare.comSettings → Authentication → Add new.

Email OTP (sin configuración externa)

El proveedor más simple: el usuario introduce su email, Cloudflare envía un código de un solo uso, el usuario lo introduce y entra. No requiere cuenta en ningún servicio externo.

Selecciona One-time PIN y guarda. No hay credenciales que configurar — Cloudflare gestiona el envío del PIN.

Ideal para dar acceso puntual a alguien sin cuenta de Google ni GitHub.

Google OAuth

Selecciona Google e introduce:

  • App ID (Client ID) y Client Secret — se obtienen en Google Cloud Console creando un proyecto OAuth 2.0
  • Authorized redirect URI: https://[TU_TEAM].cloudflareaccess.com/cdn-cgi/access/callback

El team name es el nombre que elegiste al configurar Cloudflare Zero Trust (aparece en la URL del panel).

Con Google configurado puedes crear políticas que restrinjan por dominio de correo (@tuempresa.com), lo que es útil si tienes G Suite.

GitHub OAuth

Selecciona GitHub e introduce el Client ID y Client Secret de una OAuth App en GitHub. Útil para dar acceso a colaboradores por su cuenta de GitHub sin gestionar usuarios manualmente.

Puedes tener varios proveedores activos a la vez — cada política decide cuáles acepta.


Crear la primera aplicación y política

Una aplicación en Access es la combinación de hostname + política. Por cada servicio que quieras proteger creas una aplicación.

Ve a Access → Applications → Add an application → Self-hosted.

Paso 1 — Nombre y dominio

  • Application name: nombre descriptivo (ej: Proxmox)
  • Session Duration: cuánto tiempo dura la sesión tras autenticarse (por defecto 24h, configurable hasta 1 mes)
  • Application domain: el subdominio público (ej: proxmox.tudominio.com)

El dominio tiene que estar ya en Cloudflare y tener un túnel o CNAME apuntando a él. Si aún no tienes dominio propio, en DDNS gratuito en Linux explico cómo conseguir uno sin coste y añadirlo a Cloudflare.

Paso 2 — Proveedores de identidad

Selecciona qué IdPs acepta esta aplicación. Si solo tienes Email OTP configurado, es la única opción. Si tienes Google y GitHub, puedes activar ambos y el usuario elige.

Paso 3 — Crear la política

Cada aplicación tiene al menos una política. Una política tiene:

  • Nombre: identificador de la regla
  • Decisión: Allow (dejar pasar), Block (bloquear siempre), Bypass (saltarse Access para ese grupo)
  • Reglas de inclusión: condiciones que el usuario tiene que cumplir para que la política aplique

Las condiciones más útiles:

Condición Ejemplo Para qué
Emails [email protected] Lista blanca de emails exactos
Email domain @tuempresa.com Cualquiera con ese dominio de correo
GitHub organization mi-org Miembros de una org de GitHub
Country ES Solo desde España
Everyone Cualquier usuario autenticado

Para un homelab personal, la configuración más común es una política con tu email exacto en Emails:

Policy name: Solo Jaime
Decision: Allow
Include: Emails → [email protected]

Así solo tu cuenta puede acceder, independientemente de qué proveedor uses para autenticarte.

Paso 4 — Guardar

Con la aplicación guardada, accede a proxmox.tudominio.com desde una ventana privada. Deberías ver la pantalla de login de Cloudflare antes de llegar a Proxmox. Si la identidad no está en la lista, Cloudflare devuelve un error 403 — el servicio no llega a ver la petición.


Ejemplo completo: Jellyfin protegido con Access

Escenario de partida: Jellyfin corriendo en un LXC de Proxmox, expuesto en jellyfin.tudominio.com vía Cloudflare Tunnel. Accesible desde internet, pero sin Access — cualquiera que conozca la URL llega directamente a la pantalla de login de Jellyfin.

El objetivo: añadir Access delante para que solo entren las cuentas que yo autorice. Sin tocar Jellyfin, sin instalar nada en el servidor.

Paso 1 — Email OTP como proveedor

El más rápido, no requiere cuentas externas. En Settings → Authentication → Add new → One-time PIN. Sin credenciales, sin OAuth app, guardar.

Paso 2 — Crear la aplicación

Access → Applications → Add an application → Self-hosted

Campo Valor
Application name Jellyfin
Session Duration 7 days
Application domain jellyfin.tudominio.com
Identity providers One-time PIN

Con Session Duration: 7 days no hace falta volver a autenticarse durante una semana — útil para un servicio de uso diario.

Paso 3 — Política: solo mi email

En la sección de políticas → Add a policy:

Campo Valor
Policy name Acceso personal
Action Allow
Include Emails: [email protected]

Guardar la aplicación.

Paso 4 — Verificar

Abrir una ventana de incógnito y navegar a jellyfin.tudominio.com. En lugar de la pantalla de Jellyfin, aparece la pantalla de Cloudflare Access:

  1. Introducir el email autorizado
  2. Cloudflare envía un PIN de 6 dígitos al correo
  3. Introducir el PIN → autenticado
  4. Cloudflare redirige a Jellyfin, que carga directamente

Cualquier otra dirección recibe un 403. Los bots que intenten forzar el login de Jellyfin ni siquiera llegan a verlo — Cloudflare los corta antes de que la petición entre al túnel.


Combinar Access con Cloudflare Tunnel

Access y Tunnel son independientes pero se complementan. Tunnel gestiona el canal de transporte (cómo llega el tráfico a tu servidor). Access gestiona la autenticación (quién puede usar ese canal).

La integración es automática cuando los dos apuntan al mismo hostname. Si tienes en Tunnel una regla:

proxmox.tudominio.com → https://localhost:8006

Y en Access una aplicación para proxmox.tudominio.com, Cloudflare aplica Access primero. La petición no llega al túnel hasta que el usuario ha superado el check de identidad.

Cloudflare Tunnel y Access: flujo completo con autenticación

El flujo completo:

Usuario
  → Cloudflare Access (¿quién eres?)
    → login con Google / GitHub / OTP
      → identidad válida
        → Tunnel
          → cloudflared en tu servidor
            → servicio en localhost

Ningún paso requiere abrir un puerto ni gestionar un certificado. Cloudflare gestiona el TLS externo. El túnel es la conexión saliente de tu servidor. Access es la verificación de identidad antes del túnel.

Si aún no tienes Tunnel configurado, el artículo anterior de esta serie cubre la instalación completa en Linux: Cloudflare Tunnel: expón servicios locales sin abrir puertos.


MFA y service tokens para automatización

MFA

Si el proveedor de identidad que usas (Google, GitHub) ya tiene MFA activado en esa cuenta, Access hereda esa protección automáticamente — no hay configuración adicional. El usuario se autentica en Google con su segundo factor, y Cloudflare acepta esa sesión.

Access también puede requerir explícitamente que el usuario use WARP (el cliente de red de Cloudflare) con postura de dispositivo verificada — pero eso requiere el plan Teams, que es de pago. Para un homelab con el plan gratuito, confiar en el MFA del IdP es suficiente.

Service Tokens: autenticación para scripts y APIs

La autenticación OAuth está pensada para humanos: hay una pantalla de login, un proveedor, una cookie. Pero si tienes un script, un cron job o una integración que necesita acceder a un servicio protegido por Access, no puede hacer click en “Iniciar sesión con Google”.

Para eso existen los Service Tokens: credenciales de máquina que Access acepta directamente en la cabecera HTTP.

En el panel: Access → Service Auth → Service Tokens → Create Service Token.

Introduce un nombre (ej: backup-script) y Cloudflare genera:

  • Client ID: xxxxxxxx.access
  • Client Secret: una cadena larga — cópiala ahora, no se vuelve a mostrar

En tu script o herramienta, añade estas cabeceras a cada petición:

curl https://proxmox.tudominio.com/api2/json/version \
  -H "CF-Access-Client-Id: xxxxxxxx.access" \
  -H "CF-Access-Client-Secret: tu-secret-aqui"

Cloudflare reconoce el service token y deja pasar la petición sin redirigir al login.

En la política de la aplicación, añade una regla que permita el token:

Include: Service Token → backup-script

Puedes combinar: la regla principal permite tu email, la regla adicional permite el service token. Así tanto tú (navegador) como el script tienen acceso.


Límites del plan gratuito

Límite Valor
Usuarios (asientos) 50
Aplicaciones Sin límite
Proveedores de identidad Sin límite
Service tokens Sin límite
Retención de logs de acceso 24 horas
Postura de dispositivo (WARP) No disponible (requiere Teams de pago)

El límite de 50 usuarios es el más relevante. Cada dirección de email única que se autentica consume un asiento — independientemente de cuántas aplicaciones use. Si alguien se autentica y luego borras su entrada, el asiento se libera.

Para un homelab personal o una PYME pequeña, 50 usuarios es más que suficiente.

La retención de logs de 24 horas es el límite que más duele en la práctica. Si quieres auditar quién accedió hace tres días, no está disponible en el plan gratuito. Para un homelab es aceptable; para un entorno de empresa puede ser un bloqueante.


Cuándo usar Access y cuándo no

Tiene sentido cuando:

  • Expones servicios con Tunnel y quieres que solo tú (o un grupo concreto) pueda acceder
  • El servicio tiene autenticación débil (interfaz de admin con usuario/contraseña sencilla)
  • Quieres centralizar la autenticación en lugar de gestionar usuarios en cada servicio por separado
  • Necesitas un log de quién accede a qué, aunque sea solo 24 horas
  • Quieres dar acceso puntual a alguien sin crearle una cuenta en el servicio

No tiene sentido cuando:

  • El servicio ya tiene autenticación fuerte con MFA (Proxmox con TOTP configurado, por ejemplo) y no quieres añadir otro step
  • El servicio es de uso puramente interno, solo accesible desde la LAN — Access está pensado para lo que pasa por Cloudflare
  • Necesitas acceso a protocolos que no sean HTTP/HTTPS (SSH directo, bases de datos) — para eso hay Service Auth SSH de Cloudflare, que ya es un caso más avanzado

El stack completo — Tunnel para el canal, Access para la identidad — cubre el caso de uso de acceso remoto seguro para la mayoría de servicios de homelab sin coste y sin mantenimiento. Sin puertos abiertos, sin certificados que gestionar, sin contraseñas compartidas.

Un Jedi no solo oculta su posición — también sabe exactamente quién llama antes de abrir.