9

Authelia en profundidad

Vistas: 6
Authelia en profundidad

En el capítulo anterior viste cómo integrar Authelia con Traefik a través de ForwardAuth. Fue una introducción rápida: el middleware, el router, las políticas básicas. Justo lo necesario para que Traefik y Authelia hablaran entre sí. Pero Authelia da mucho más de sí. En este capítulo vas a dejar de lado las configuraciones mínimas. Vas a montar Authelia desde cero con Docker Compose y Traefik, configurar usuarios con contraseñas hasheadas con Argon2, definir políticas de acceso granulares, habilitar segundo factor con TOTP y WebAuthn, personalizar el portal de usuario, y gestionar la recuperación de contraseñas y el reseteo de 2FA.

¿Suena a mucho? No te preocupes. Vamos paso a paso, como siempre.

Al final del capítulo, Authelia no será solo un componente más de tu infraestructura. Será el guardián de todas tus aplicaciones self-hosted, configurado a tu medida, sin depender de servicios externos.

Instalación completa con Docker Compose y Traefik

Vamos a desplegar Authelia con todo lo que necesita. No es solo el contenedor de Authelia. Necesitas Redis para la sesión y PostgreSQL o SQLite para el almacenamiento persistente.

Authelia usa Redis para gestionar las sesiones de usuario. Las sesiones se almacenan en Redis porque es rápido y permite expiración automática. Sin Redis, las sesiones se perderían al reiniciar Authelia y todos los usuarios tendrían que volver a iniciar sesión.

Para el almacenamiento persistente, tienes dos opciones: SQLite (más simple, sin base de datos externa) o PostgreSQL (más robusto, mejor para múltiples instancias). Para un servidor personal, SQLite es suficiente. Para un equipo o producción, usa PostgreSQL.

Estructura de directorios

/home/lorenzo/docker/authelia/
├── docker-compose.yml
├── config/
│   ├── configuration.yml
│   └── users_database.yml
└── data/
    └── redis/

Creas la estructura con:

mkdir -p /home/lorenzo/docker/authelia/{config,data/redis}
cd /home/lorenzo/docker/authelia

docker-compose.yml

services:
  authelia:
    image: authelia/authelia:latest
    container_name: authelia
    restart: unless-stopped
    volumes:
      - ./config:/config
    environment:
      - TZ=Europe/Madrid
    networks:
      - traefik
    labels:
      # Router para el portal de Authelia
      - "traefik.enable=true"
      - "traefik.http.routers.authelia.rule=Host(`auth.tudominio.com`)"
      - "traefik.http.routers.authelia.entrypoints=websecure"
      - "traefik.http.routers.authelia.tls=true"
      - "traefik.http.routers.authelia.tls.certresolver=letsencrypt"
      - "traefik.http.services.authelia.loadbalancer.server.port=9091"

      # Router interno para forward-auth (sin redirección a portal)
      - "traefik.http.routers.authelia-forwardauth.rule=Host(`auth.tudominio.com`) && PathPrefix(`/api/authz/forward-auth`)"
      - "traefik.http.routers.authelia-forwardauth.entrypoints=websecure"
      - "traefik.http.routers.authelia-forwardauth.tls=true"
      - "traefik.http.routers.authelia-forwardauth.tls.certresolver=letsencrypt"
      - "traefik.http.routers.authelia-forwardauth.middlewares=authelia-forwardauth"
      - "traefik.http.services.authelia-forwardauth.loadbalancer.server.port=9091"

      # Middleware forward-auth que apunta al propio Authelia
      - "traefik.http.middlewares.authelia-forwardauth.forwardauth.address=http://authelia:9091/api/authz/forward-auth"
      - "traefik.http.middlewares.authelia-forwardauth.forwardauth.trustforwardheader=true"
      - "traefik.http.middlewares.authelia-forwardauth.forwardauth.authresponseheaders=Remote-User,Remote-Groups,Remote-Email,Remote-Name"

  redis:
    image: redis:alpine
    container_name: authelia-redis
    restart: unless-stopped
    volumes:
      - ./data/redis:/data
    command: "redis-server --appendonly yes --save 900 1 --save 300 10 --save 60 10000"
    networks:
      - traefik
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

networks:
  traefik:
    external: true

Fíjate en dos detalles importantes.

Primero, el router authelia-forwardauth tiene su propio middleware. El endpoint /api/authz/forward-auth está protegido por el mismo middleware forward-auth que usan los demás servicios. Cuando Authelia recibe una petición de forward-auth, comprueba la cookie de sesión. Si el usuario ya ha iniciado sesión, responde con 200 OK. Si no, redirige al portal de login.

Segundo, el middleware authelia-forwardauth se define como label del contenedor de Authelia. Esto significa que otros contenedores pueden usarlo referenciándolo como authelia-forwardauth@docker en sus propios labels.

El middleware en Traefik (archivo dinámico)

Si prefieres gestionar los middlewares desde el archivo dinámico de Traefik en lugar de labels, crea un archivo en tu directorio de reglas:

# /home/lorenzo/docker/traefik/rules/authelia-middleware.yml
http:
  middlewares:
    authelia-auth:
      forwardAuth:
        address: "http://authelia:9091/api/authz/forward-auth"
        trustForwardHeader: true
        authResponseHeaders:
          Remote-User: username
          Remote-Groups: groups
          Remote-Email: email
          Remote-Name: preferred_username

Este archivo lo cargas desde el traefik.yml estático de Traefik:

providers:
  file:
    directory: /rules
    watch: true

Ahora cualquier servicio puede protegerse añadiendo este middleware:

labels:
  - "traefik.http.routers.mi-servicio.middlewares=authelia-auth@file"

Precauciones con el router de forward-auth

Hay una trampa en la que caen muchos principiantes. Si proteges el router principal de Authelia con el middleware forward-auth, creas un bucle. El usuario no puede llegar al portal de login porque el portal de login redirige al portal de login.

La solución es la que ves arriba: dos routers. El router principal (authelia) no tiene el middleware forward-auth. El router de la API (authelia-forwardauth) sí lo tiene. Así:

  • Cuando un usuario visita auth.tudominio.com, ve el portal de login sin ninguna barrera.
  • Cuando un usuario ya autenticado accede a un servicio protegido, Traefik envía la petición a http://authelia:9091/api/authz/forward-auth (router protegido). Authelia ve la cookie de sesión, responde 200, y el usuario pasa.
  • Cuando un usuario no autenticado accede a un servicio protegido, Authelia responde 401, y Traefik redirige al portal de login en auth.tudominio.com.

Limpio, elegante, sin bucles.

Configuración de usuarios: users_database.yml

Authelia almacena los usuarios en un archivo YAML. La ruta se define en configuration.yml:

authentication_backend:
  file:
    path: /config/users_database.yml
    password:
      algorithm: argon2id
      iterations: 1
      salt_length: 16
      parallelism: 8
      memory: 64

El algoritmo de hash es Argon2id, que es el estándar actual de hash de contraseñas. Es resistente a ataques de fuerza bruta tanto por GPU como por ASIC. Los parámetros que ves arriba (64 MB de memoria, 8 en paralelismo) son los recomendados por Authelia para un servidor doméstico. Si tu servidor tiene poca RAM, puedes bajar memory a 32 o 16.

Generar el hash de la contraseña

No escribas la contraseña en texto plano. Usa el propio Authelia para generar el hash:

docker run --rm authelia/authelia:latest \
  authelia crypto hash generate argon2 \
  --password 'TuContraseñaSegura'

El comando devuelve algo como:

Digest: $argon2id$v=19$m=65536,t=1,p=8$abcd1234...$abcdefghijklmnopqrstuvwxyz1234567890abcdef

Ese es el hash que pones en users_database.yml.

Si prefieres generarlo de forma interactiva (sin que la contraseña quede en el historial del shell):

docker run --rm -it authelia/authelia:latest authelia crypto hash generate argon2

Te pedirá la contraseña sin mostrarla en pantalla.

Estructura de users_database.yml

users:
  lorenzo:
    displayname: "Lorenzo"
    password: "$argon2id$v=19$m=65536,t=1,p=8$abcd1234...$abcdefghijklmnopqrstuvwxyz1234567890abcdef"
    email: lorenzo@tudominio.com
    groups:
      - admins
      - users

  ana:
    displayname: "Ana García"
    password: "$argon2id$v=19$m=65536,t=1,p=8$xyz..."
    email: ana@tudominio.com
    groups:
      - users

  invitado:
    displayname: "Invitado"
    password: "$argon2id$v=19$m=65536,t=1,p=8$..."
    email: invitado@tudominio.com
    groups:
      - invitados

Cada usuario tiene:

  • displayname: el nombre que se muestra en el portal.
  • password: el hash Argon2 de la contraseña. Nunca la contraseña en texto plano.
  • email: obligatorio. Se usa para notificaciones, reseteo de contraseña y registro de dispositivos 2FA.
  • groups: lista de grupos a los que pertenece el usuario. Los grupos se usan en las políticas de acceso.

Los grupos son importantes. Te permiten aplicar políticas diferentes según el rol del usuario. Por ejemplo, los usuarios del grupo admins pueden necesitar 2FA para todo, mientras que los del grupo users solo necesitan 1FA para servicios básicos.

Añadir o modificar usuarios

Para añadir un usuario nuevo, solo tienes que añadir una entrada en users_database.yml con su hash de contraseña. Authelia recarga el archivo automáticamente sin necesidad de reiniciar el contenedor.

Para cambiar la contraseña de un usuario, generas un nuevo hash y lo reemplazas en el archivo. La próxima vez que el usuario inicie sesión, la nueva contraseña es válida.

Para deshabilitar temporalmente un usuario, puedes comentar su entrada o cambiar su contraseña por un hash inválido. No hay un campo disabled, pero marcar la contraseña con un valor erróneo consigue el mismo efecto.

Políticas de acceso en configuration.yml

Aquí está el corazón de Authelia. Las políticas de acceso definen qué usuarios pueden acceder a qué servicios y con qué nivel de autenticación.

Las cuatro políticas disponibles

Authelia ofrece cuatro políticas, de menos a más restrictivas:

bypass: el usuario accede sin autenticación. Útil para servicios públicos o para el propio portal de Authelia. Sin autenticación, sin barreras.

one_factor: el usuario necesita autenticarse con su primer factor (usuario y contraseña). No se requiere 2FA. Perfecto para servicios internos de bajo riesgo.

two_factor: el usuario necesita autenticarse con ambos factores. Primero usuario y contraseña, luego un código TOTP, WebAuthn o código de respaldo. Para servicios sensibles.

deny: denegado para todos. Siempre devuelve 403. Útil como política por defecto o para bloquear rutas específicas.

La política por defecto

access_control:
  default_policy: deny

Siempre, siempre, siempre usa deny como política por defecto. Es el enfoque de mínimos privilegios. Todo está bloqueado a menos que lo permitas explícitamente. Si pones one_factor o bypass como defecto, cualquier servicio nuevo que despliegues quedará automáticamente expuesto si olvidas añadir una regla.

Reglas básicas por dominio

access_control:
  default_policy: deny

  rules:
    # El portal de Authelia debe ser público
    - domain: "auth.tudominio.com"
      policy: bypass

    # Servicio público sin autenticación
    - domain: "public.tudominio.com"
      policy: bypass

    # Servicios internos con usuario y contraseña
    - domain: "app.tudominio.com"
      policy: one_factor

    # Servicios sensibles con doble factor
    - domain: "admin.tudominio.com"
      policy: two_factor

    # Comodín para subdominios
    - domain: "*.tudominio.com"
      policy: one_factor

Las reglas se evalúan en orden. La primera regla que coincide con la petición es la que se aplica. Por eso las reglas más específicas van primero y las más generales al final.

¿Por qué auth.tudominio.com tiene bypass? Porque si el portal de login estuviera protegido, nadie podría hacer login. Es la excepción necesaria.

Reglas por usuario y grupo

Puedes restringir el acceso a usuarios o grupos específicos:

access_control:
  default_policy: deny

  rules:
    # Solo el usuario lorenzo puede acceder a servicios críticos
    - domain: "docker.tudominio.com"
      policy: two_factor
      subject:
        - "user:lorenzo"

    # Los administradores usan 2FA
    - domain: "*.tudominio.com"
      policy: two_factor
      subject:
        - "group:admins"

    # Los usuarios normales usan 1FA
    - domain: "*.tudominio.com"
      policy: one_factor
      subject:
        - "group:users"

Los sujetos se prefijan con user: o group:. Puedes combinar varios sujetos en una regla. Si pones varios en una lista, se evalúan con OR (cualquiera de ellos coincide):

    - domain: "admin.tudominio.com"
      policy: two_factor
      subject:
        - "user:lorenzo"
        - "group:admins"

Si necesitas AND (todos deben coincidir), agrupas los sujetos en listas anidadas:

    - domain: "super-secreto.tudominio.com"
      policy: two_factor
      subject:
        - ["group:admins", "user:lorenzo"]

Esto solo permite el acceso si el usuario es lorenzo Y pertenece al grupo admins.

Reglas por ruta (resources)

Aquí es donde Authelia muestra su potencia. Puedes definir políticas diferentes para distintas rutas dentro del mismo dominio:

access_control:
  default_policy: deny

  rules:
    # El endpoint de webhook no necesita autenticación
    - domain: "app.tudominio.com"
      resources:
        - "^/webhook/.*$"
      policy: bypass

    # La API de monitoreo solo necesita 1FA
    - domain: "app.tudominio.com"
      resources:
        - "^/api/health$"
        - "^/api/metrics$"
      policy: one_factor

    # El panel de administración necesita 2FA
    - domain: "app.tudominio.com"
      resources:
        - "^/admin/.*$"
      policy: two_factor
      subject:
        - "group:admins"

    # El resto de la aplicación para usuarios normales
    - domain: "app.tudominio.com"
      policy: one_factor

Las resources son expresiones regulares. Las rutas se evalúan contra la URL completa después del dominio, incluyendo el slash inicial.

Fíjate en el orden. Las reglas específicas (rutas concretas) van primero. La regla genérica de catch-all va al final. Si pusieras la genérica primero, nunca se evaluarían las específicas.

Reglas por método HTTP

Puedes ser aún más granular y restringir por método HTTP:

access_control:
  default_policy: deny

  rules:
    # GET sin autenticación (lectura pública)
    - domain: "blog.tudominio.com"
      methods:
        - GET
        - HEAD
      policy: bypass

    # POST, PUT, DELETE requieren 2FA (escritura)
    - domain: "blog.tudominio.com"
      methods:
        - POST
        - PUT
        - DELETE
      policy: two_factor

Esto permite que cualquiera lea el blog, pero solo usuarios autenticados con 2FA puedan publicar o modificar contenido.

Reglas por red de origen

Si tus usuarios se conectan desde redes conocidas (VPN, red local), puedes rebajar los requisitos de autenticación:

access_control:
  default_policy: deny

  networks:
    - name: vpn
      networks:
        - "10.8.0.0/16"
    - name: local
      networks:
        - "192.168.1.0/24"
        - "172.16.0.0/12"

  rules:
    # Desde la VPN, solo 1FA para servicios internos
    - domain: "*.tudominio.com"
      policy: one_factor
      networks:
        - vpn
        - local

    # Desde fuera, 2FA para todo
    - domain: "*.tudominio.com"
      policy: two_factor

Desde la red local o la VPN solo necesitas usuario y contraseña. Desde Internet, necesitas 2FA. Es un buen equilibrio entre seguridad y comodidad.

Combinación de todos los filtros

Una regla puede combinar dominio, recursos, métodos, redes y sujetos. Todas las condiciones deben cumplirse para que la regla se active:

access_control:
  default_policy: deny

  rules:
    - domain: "api.tudominio.com"
      resources:
        - "^/v1/.*$"
      methods:
        - GET
      policy: bypass

    - domain: "api.tudominio.com"
      resources:
        - "^/v1/admin/.*$"
      methods:
        - POST
        - PUT
        - DELETE
      policy: two_factor
      subject:
        - "group:admins"
      networks:
        - vpn

Solo los administradores desde la VPN pueden hacer POST/PUT/DELETE en /v1/admin/. El resto de peticiones GET a la API son públicas. Así de granular.

Segundo factor: TOTP, WebAuthn y códigos de respaldo

Una de las razones principales para usar Authelia es el segundo factor de autenticación. Vamos a ver los tres métodos que soporta.

TOTP (Time-based One-Time Password)

TOTP es el método más común. Usas una aplicación como Google Authenticator, Authy o Aegis para generar códigos de 6 dígitos que cambian cada 30 segundos.

Configuración en configuration.yml:

totp:
  issuer: tudominio.com
  period: 30
  digits: 6
  algorithm: sha1
  skew: 1
  • issuer: el nombre que aparece en la aplicación de autenticación. Pon tu dominio.
  • period: cada cuántos segundos cambia el código. 30 es el estándar.
  • digits: 6 dígitos. No cambies esto a menos que tengas una razón muy concreta.
  • algorithm: SHA-1 es el estándar TOTP (RFC 6238). SHA-256 y SHA-512 también están soportados.
  • skew: cuántos intervalos de tolerancia. Con skew 1, acepta el código actual, el anterior y el siguiente. Útil para compensar diferencias de hora entre el servidor y el dispositivo.

¿Y cómo registra el usuario su primer dispositivo TOTP?

Cuando un usuario inicia sesión por primera vez y la política requiere two_factor, Authelia le muestra la pantalla de registro. El usuario escanea el código QR con su aplicación de autenticación, introduce el código generado, y ya está.

Pero hay un problema: para mostrar el código QR, Authelia necesita enviar un correo de verificación. Si no tienes servidor SMTP configurado, el usuario no puede registrar su TOTP.

Solución: usa la identidad de verificación local. Authelia puede escribir el enlace de verificación en un archivo del contenedor en lugar de enviar un email.

identity_validation:
  reset_password:
    jwt_secret: "un-secreto-muy-largo-de-32-caracteres"
  identity:
    files:
      - path: /config/identity
        secret: "otro-secreto"

Pero la forma más práctica es configurar un servidor SMTP. Incluso un servicio transaccional gratuito como SendGrid o un relay SMTP local funciona.

notifier:
  filesystem:
    filename: /config/notifications.yml

Si usas el notificador por archivo, Authelia escribe las notificaciones en un archivo YAML en lugar de enviarlas por correo. Cada vez que un usuario necesita verificar su identidad, el código aparece en ese archivo. No es automático, pero funciona para entornos de prueba o personales.

Para producción, configura SMTP:

notifier:
  smtp:
    host: smtp.tudominio.com
    port: 587
    username: authelia@tudominio.com
    password: "contraseña-del-correo"
    sender: "Authelia <authelia@tudominio.com>"

WebAuthn (llave de seguridad física)

WebAuthn es el método más seguro. Usa una llave física (YubiKey, soloKey, Nitrokey) o el propio dispositivo del usuario (huella dactilar, Face ID, PIN) como segundo factor.

La gran ventaja sobre TOTP: WebAuthn es resistente a phishing. El código TOTP se puede robar con un sitio falso. La llave física no: el navegador verifica que el dominio es el auténtico antes de firmar la petición.

Configuración en configuration.yml:

webauthn:
  display_name: "tudominio.com"
  attestation_conveyance_preference: indirect
  user_verification: preferred
  timeout: 60000
  • display_name: el nombre que ve el usuario cuando registra su llave.
  • attestation_conveyance_preference: cómo maneja la atestación (certificado de la llave). indirect permite al navegador decidir. none no solicita atestación. direct solicita el certificado completo.
  • user_verification: si requiere verificación del usuario (huella, PIN). preferred intenta usar verificación pero permite continuar sin ella.
  • timeout: milisegundos para completar el registro o autenticación. 60 segundos es suficiente.

El usuario puede registrar tantas llaves como quiera. Desde el portal de usuario, en la sección de Autenticación, puede añadir, renombrar o eliminar dispositivos WebAuthn.

Códigos de respaldo (backup codes)

¿Qué pasa si pierdes el móvil con la aplicación TOTP y la llave física está en la oficina?

Authelia genera códigos de respaldo de un solo uso. Cada código es una cadena de 8 caracteres que el usuario puede usar para autenticarse cuando no tiene acceso a su segundo factor principal.

Los códigos de respaldo se generan cuando el usuario configura el 2FA por primera vez. Authelia muestra una lista de 16 códigos. El usuario debe guardarlos en un lugar seguro: gestor de contraseñas, caja fuerte, impresos en papel.

Configuración:

webauthn:
  # ...

  backup_codes:
    number: 16
    length: 8
  • number: cuántos códigos se generan. 16 es buena cantidad.
  • length: longitud de cada código. 8 caracteres alfanuméricos.

Cada código solo se puede usar una vez. Cuando se gasta un código, Authelia lo marca como usado. Cuando al usuario le quedan pocos códigos (por ejemplo, 3), Authelia le avisa para que genere nuevos.

Para generar nuevos códigos de respaldo, el usuario va al portal de Authelia, a la sección de Autenticación, y pulsa «Regenerar códigos de respaldo». Los códigos anteriores dejan de ser válidos.

¿Cuál elegir?

Mi recomendación:

  • TOTP para empezar. Todos los usuarios tienen un móvil. Google Authenticator, Aegis o 2FAS son gratuitos.
  • WebAuthn para servicios críticos. Si tienes una YubiKey, úsala para el acceso a admin.tudominio.com.
  • Códigos de respaldo siempre. Son el seguro de vida para cuando todo lo demás falla.

Puedes tener los tres métodos activos a la vez. El usuario elige cuál usar en cada inicio de sesión.

Portal de usuario personalizable

Authelia incluye un portal de usuario que se ve decente nada más instalarlo. Pero puedes personalizarlo para que se parezca a tu marca.

Tema (claro/oscuro)

theme: dark

Las opciones: light, dark o auto (sigue la preferencia del sistema del usuario). Si quieres consistencia entre todos los usuarios, elige uno y mantenlo.

Logotipo

Puedes cambiar el logo de Authelia por el tuyo propio. El logo debe ser un archivo PNG o SVG de 240×80 píxeles aproximadamente.

El logo se sirve desde el propio Authelia. La ruta es relativa al directorio /config:

/config/logo.png

Opcionalmente, puedes configurar la ruta en configuration.yml:

theme: dark
logo_url: /config/logo.png

Si usas SVG, asegúrate de que esté optimizado y no tenga referencias externas. Los SVG con vulnerabilidades XSS podrían ser un vector de ataque, aunque Authelia los sirve con cabeceras de seguridad.

Título y textos

portal:
  name: "Tu Homelab Seguro"
  button_text: "Entrar"
  display_name: "Autenticación requerida"
  • name: el nombre que aparece en la página de login.
  • button_text: texto del botón de inicio de sesión.
  • display_name: texto que aparece en la cabecera del portal.

Términos y condiciones

Si quieres mostrar un enlace a tus términos de uso:

portal:
  terms_url: "https://tudominio.com/terminos"

Opcional, pero útil si tienes usuarios externos.

Personalización avanzada con CSS

Authelia no expone una opción directa para CSS personalizado. Pero puedes sobreescribir estilos inyectando CSS en el contenedor.

Crea un archivo custom.css:

.authelia-logo {
  border-radius: 8px;
}

.btn-primary {
  background-color: #ff6600;
  border-color: #ff6600;
}

.btn-primary:hover {
  background-color: #e55c00;
}

body {
  font-family: 'Inter', system-ui, sans-serif;
}

Luego monta el CSS en el contenedor y configura la variable de entorno:

services:
  authelia:
    volumes:
      - ./config/custom.css:/config/custom.css
    environment:
      - AUTHELIA_PORTAL_CUSTOM_CSS=/config/custom.css

O, si prefieres no modificar el docker-compose, puedes usar un reverse proxy delante de Authelia que inyecte el CSS. Pero la opción anterior es más limpia.

Configuración completa del portal

portal:
  name: "Acceso Seguro"
  button_text: "Iniciar sesión"
  display_name: "Autenticación requerida"
  terms_url: "https://ejemplo.com/terminos"
  custom_css: /config/custom.css

theme: dark
logo_url: /config/logo.png

Reset de contraseña y recuperación de 2FA

Tus usuarios van a perder la contraseña. O van a cambiar de móvil sin haber exportado los códigos TOTP. Authelia tiene mecanismos para ambos casos.

Reset de contraseña

Authelia permite al usuario resetear su contraseña si ha olvidado la actual. El flujo es:

  1. El usuario pulsa «¿Has olvidado tu contraseña?» en la pantalla de login.
  2. Introduce su email.
  3. Authelia envía un enlace de reseteo por correo.
  4. El usuario pulsa el enlace, introduce su nueva contraseña dos veces, y confirma.

Para que esto funcione, necesitas:

  1. Un notificador SMTP configurado (o el notificador por archivo si es para pruebas).
  2. Un jwt_secret para firmar los enlaces de reseteo.
identity_validation:
  reset_password:
    jwt_secret: "un-secreto-muy-largo-de-32-caracteres-mas-para-seguridad"

El jwt_secret es crítico. Si alguien obtiene este secreto, puede generar enlaces de reseteo falsos y cambiar la contraseña de cualquier usuario. Guárdalo como un secreto y no lo compartas.

Recuperación de 2FA

Perder el acceso al segundo factor es más grave que perder la contraseña. Sin el segundo factor, el usuario no puede iniciar sesión aunque sepa la contraseña.

Authelia ofrece dos métodos de recuperación:

1. Códigos de respaldo (el recomendado). Si el usuario guardó sus códigos de respaldo, puede usarlos para iniciar sesión. Una vez dentro, va al portal de usuario y configura un nuevo dispositivo TOTP o WebAuthn.

2. Reseteo administrativo. Si el usuario no tiene códigos de respaldo, un administrador debe intervenir. Desde la línea de comandos del contenedor de Authelia:

docker exec authelia authelia admin reset-totp lorenzo

Este comando elimina todos los dispositivos TOTP del usuario lorenzo. La próxima vez que inicie sesión, Authelia le pedirá que registre un nuevo dispositivo.

Para WebAuthn:

docker exec authelia authelia admin reset-webauthn lorenzo

Para ambos a la vez:

docker exec authelia authelia admin reset-mfa lorenzo

Estos comandos son de administración. Solo accesibles desde el host Docker, no desde la web.

Prevención: la sesión de recuperación

Authelia puede configurar una «sesión de elevación» que permite al usuario configurar su 2FA sin tener que verificarlo inmediatamente después del primer login:

session:
  elevation:
    require_second_factor_on_login: false

Con esta configuración, un usuario sin 2FA configurado puede iniciar sesión con solo usuario y contraseña, y Authelia le redirige automáticamente a la página de configuración de 2FA. Una vez configurado, ya no puede volver a entrar sin el segundo factor.

Es útil para el primer inicio de sesión de un usuario nuevo. El administrador crea el usuario, el usuario inicia sesión con su contraseña temporal, y Authelia le obliga a configurar el 2FA antes de poder acceder a ningún servicio.

Integración con Traefik

Aunque viste la integración básica en el capítulo 8, aquí la completamos con todos los detalles.

Middleware ForwardAuth definitivo

http:
  middlewares:
    authelia-auth:
      forwardAuth:
        address: "http://authelia:9091/api/authz/forward-auth"
        trustForwardHeader: true
        authResponseHeaders:
          Remote-User: username
          Remote-Groups: groups
          Remote-Email: email
          Remote-Name: preferred_username

Los authResponseHeaders son importantes. Cuando Authelia autoriza una petición, incluye información del usuario en la respuesta. Traefik pasa estas cabeceras al backend. Así el servicio sabe quién es el usuario sin tener que preguntar a Authelia.

  • Remote-User → el nombre de usuario (lorenzo).
  • Remote-Groups → los grupos del usuario separados por coma (admins,users).
  • Remote-Email → el email del usuario.
  • Remote-Name → el nombre visible.

Algunos servicios leen estas cabeceras para personalizar la experiencia. Por ejemplo, Grafana puede usar Remote-User para identificar al usuario sin necesidad de un segundo login.

Proteger un servicio con la cadena completa

services:
  quien-soy:
    image: containous/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.tudominio.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls=true"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
      - "traefik.http.routers.whoami.middlewares=chain-authelia"

Y la cadena de middlewares en el archivo dinámico de Traefik:

http:
  middlewares:
    chain-authelia:
      chain:
        middlewares:
          - whitelist-vpn
          - ratelimit-global
          - authelia-auth
          - headers-seguridad
          - compress-gzip

Excepciones para servicios específicos

Algunos servicios necesitan que ciertas rutas no estén autenticadas. Por ejemplo, los webhooks de GitHub necesitan ser públicos.

Tienes dos opciones:

Opción 1: Directamente en Authelia (recomendada)

access_control:
  rules:
    # Webhooks públicos
    - domain: "app.tudominio.com"
      resources:
        - "^/webhook/github/.*$"
      policy: bypass

    # El resto protegido
    - domain: "app.tudominio.com"
      policy: two_factor

Opción 2: Dos routers en Traefik

services:
  app-webhook:
    image: miapp
    labels:
      # Router para webhooks (sin autenticación)
      - "traefik.http.routers.app-webhook.rule=Host(`app.tudominio.com`) && PathPrefix(`/webhook`)"
      - "traefik.http.routers.app-webhook.middlewares=chain-publico"

      # Router para el resto (con autenticación)
      - "traefik.http.routers.app.rule=Host(`app.tudominio.com`)"
      - "traefik.http.routers.app.middlewares=chain-authelia"

La opción 1 es más limpia porque toda la lógica de acceso está centralizada en Authelia. La opción 2 puede ser necesaria si el servicio necesita rutas públicas sin pasar por Authelia por temas de latencia.

Múltiples dominios y Authelia

Authelia puede proteger servicios en diferentes dominios (o subdominios). Siempre que las cookies de sesión compartan el dominio raíz, todo funciona.

Si tienes:

  • auth.tudominio.com (portal de Authelia)
  • app.tudominio.com (servicio protegido)
  • admin.tudominio.com (otro servicio protegido)

La cookie de sesión de Authelia se establece para .tudominio.com. Todos los subdominios pueden leerla. Cuando el usuario se autentica en app.tudominio.com, la sesión es válida también para admin.tudominio.com.

Configuración de sesión para múltiples subdominios:

session:
  name: authelia_session
  domain: tudominio.com
  secret: "un-secreto-muy-largo-de-64-caracteres-aleatorios"
  expiration: 3600  # 1 hora
  inactivity: 300   # 5 minutos de inactividad
  remember_me_duration: 2592000  # 30 días
  • domain: el dominio para el que es válida la cookie. Pon el dominio raíz sin subdominio para que todos los subdominios la compartan.
  • expiration: tiempo máximo de sesión. 1 hora es razonable.
  • inactivity: tiempo de inactividad antes de que la sesión expire. 5 minutos es seguro pero puede ser molesto. 15 minutos es buen compromiso.
  • remember_me_duration: cuánto dura la sesión si el usuario marcó «Recordarme». 30 días.

Verificación: probar acceso con 1FA y 2FA

Has configurado todo. Ahora toca comprobar que funciona.

Probar que el portal de login responde

curl -s -o /dev/null -w "%{http_code}" https://auth.tudominio.com

Respuesta esperada: 200. El portal de login debe ser accesible sin autenticación.

Probar que un servicio protegido redirige al login

curl -s -o /dev/null -w "%{http_code}" https://whoami.tudominio.com

Respuesta esperada: 302 (redirección a auth.tudominio.com).

O si prefieres ver la redirección:

curl -v https://whoami.tudominio.com 2>&1 | grep -i location

Deberías ver algo como:

< location: https://auth.tudominio.com/?rd=https://whoami.tudominio.com/

Iniciar sesión desde línea de comandos

Authelia usa cookies de sesión. Para simular un login completo desde terminal:

# Obtener la página de login (obtiene cookie de sesión y nonce)
curl -v -c cookies.txt https://auth.tudominio.com 2>&1 | grep 'set-cookie'

# La cookie se llama authelia_session
# Envía las credenciales (esto es más complejo, normalmente necesitas extraer el nonce del HTML)

Lo más práctico para pruebas rápidas es usar el navegador. Abre https://whoami.tudominio.com, deberías ser redirigido a auth.tudominio.com. Inicia sesión con tu usuario y contraseña. Si la política es one_factor, ya estás dentro. Si es two_factor, te pedirá el código TOTP o la llave WebAuthn.

Probar una política de dos factores

Configura un servicio con política two_factor y accede desde el navegador:

  1. Abre https://whoami.tudominio.com.
  2. Authelia te redirige a https://auth.tudominio.com.
  3. Introduce usuario y contraseña. Pulsa «Iniciar sesión».
  4. Authelia te pide el segundo factor.
  5. Abre tu aplicación de autenticación (Google Authenticator, Aegis).
  6. Introduce el código de 6 dígitos.
  7. Estás dentro. El servicio whoami te muestra tus cabeceras HTTP, incluyendo Remote-User: lorenzo.

Probar una política de bypass

Configura un servicio con política bypass y accede desde el navegador:

  1. Abre https://public.tudominio.com.
  2. Deberías ver el contenido directamente, sin redirección al login.

Si ves el contenido sin autenticación, el bypass funciona.

Probar una política de denegación

Configura un servicio con política deny:

  1. Abre https://denegado.tudominio.com.
  2. Deberías recibir un 403 Forbidden directamente, sin pasar por el login.

Ni siquiera los administradores pueden acceder. Es una denegación absoluta.

Probar el cierre de sesión

Accede al portal de Authelia, busca el botón de «Cerrar sesión» (normalmente en la esquina superior derecha). Al cerrar sesión, la cookie se invalida. Si vuelves a intentar acceder a un servicio protegido, te pedirá login de nuevo.

Probar la expiración de sesión

Configura la inactividad en 60 segundos para pruebas:

session:
  inactivity: 60

Inicia sesión, accede a un servicio, espera 60 segundos sin hacer nada, recarga la página. Authelia debería pedirte login de nuevo.

No olvides devolver la inactividad a un valor razonable después de la prueba.

Probar el acceso desde redes no autorizadas

Si tienes reglas por red, prueba desde fuera de la VPN:

# Desde un VPS externo
curl -s -o /dev/null -w "%{http_code}" https://whoami.tudominio.com

Si hay una regla que requiere 2FA desde fuera de la VPN, verás la redirección al portal de login. Sin VPN, no puedes acceder con solo 1FA.

Buenas prácticas de seguridad

Un par de consejos para que tu Authelia sea realmente seguro.

Secrets y contraseñas

No pongas los secretos en texto plano en el configuration.yml. Usa variables de entorno o un archivo de secretos externo.

# En configuration.yml
session:
  secret: ${SESSION_SECRET}

identity_validation:
  reset_password:
    jwt_secret: ${JWT_SECRET}

Y en el docker-compose.yml:

services:
  authelia:
    environment:
      - SESSION_SECRET=/run/secrets/session_secret
      - JWT_SECRET=/run/secrets/jwt_secret
    secrets:
      - session_secret
      - jwt_secret

secrets:
  session_secret:
    file: ./secrets/session_secret.txt
  jwt_secret:
    file: ./secrets/jwt_secret.txt

HTTPS obligatorio

Authelia debe ejecutarse siempre detrás de Traefik con TLS. Sin HTTPS, la cookie de sesión viaja en texto plano y cualquiera puede interceptarla.

Asegúrate de que Traefik redirige HTTP a HTTPS:

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https

Logs y monitorización

Configura el nivel de log para detectar intentos de acceso sospechosos:

log:
  level: info
  format: json

Con formato JSON, puedes enviar los logs a un sistema centralizado (Loki, Elasticsearch, etc.) y crear alertas para:

  • Múltiples intentos fallidos de login desde la misma IP.
  • Intentos de acceso a rutas denegadas.
  • Registro de nuevos dispositivos 2FA.

Actualizaciones

Authelia se actualiza con frecuencia. Mantente al día para recibir parches de seguridad y nuevas funcionalidades.

services:
  authelia:
    image: authelia/authelia:latest

Si prefieres no usar latest por posibles roturas, usa una versión específica y actualízala manualmente cuando revises las release notes:

services:
  authelia:
    image: authelia/authelia:4.39

Conclusión

Has recorrido Authelia de arriba a abajo. No es solo un portal de login bonito. Es un sistema de autenticación completo que te permite:

  • Centralizar la autenticación de todos tus servicios en un solo punto.
  • Definir políticas de acceso granulares por dominio, ruta, método, usuario, grupo y red.
  • Exigir segundo factor con TOTP (aplicación de autenticación), WebAuthn (llave física) o códigos de respaldo.
  • Personalizar el portal de usuario con tu logo, colores y textos.
  • Recuperar contraseñas y 2FA sin depender de servicios externos.
  • Integrar con Traefik mediante ForwardAuth de forma limpia y eficiente.

Con el despliegue completo que has montado en este capítulo, tienes un guardián para todas tus aplicaciones self-hosted. Configuras una vez y proteges todo. Nuevos servicios se despliegan con una línea de middleware y ya están autenticados.

En el próximo capítulo veremos Authentik, el hermano mayor de Authelia. Más completo, más complejo, con flujos personalizables, catálogo de aplicaciones y soporte OIDC/SAML nativo. Pero eso es para cuando Authelia se te quede pequeño.

De momento, disfruta de tener un sistema de autenticación de dos factores auto-gestionado, sin depender de Google, Microsoft ni de ningún servicio externo. Tus datos, tu control, tu seguridad.


Más información,

  • Documentación oficial de Authelia: https://www.authelia.com/docs/ — guía completa de instalación, configuración y despliegue.
  • Página oficial de Authelia: https://www.authelia.com/ — portal principal del proyecto.
  • ForwardAuth en Traefik v3: https://doc.traefik.io/traefik/middlewares/http/forwardauth/ — documentación oficial del middleware ForwardAuth.
  • Tutorial de Traefik v3 en atareao.es: https://atareao.es/tutorial/traefik/ — guía práctica en español sobre Traefik v3.
  • Documentación de WebAuthn (W3C): https://www.w3.org/TR/webauthn/ — especificación oficial del estándar WebAuthn.

Deja una respuesta