Identidad, acceso y seguridad

Donde se decide quién entra, cómo y con qué dolor.

Authentik

Parcheando lo que Authentik no explica hasta que ya estás logueado fuera y cagándote en todo.

Authentik

Actualizar el fondo de todos los flows en Authentik (vía SQL)


Cambiar los fondos de todos los flows de Authentik (pantalla de login, registro, recuperación de contraseña, etc.) desde la interfaz puede ser lento y tedioso si se hace uno a uno. Para evitar ese paseo clic por clic, lo más práctico es lanzar una consulta SQL que los actualice todos de golpe.


Características


Paso a paso

1. Entra en el contenedor de la base de datos

Asumiendo que usas Docker, el primer paso es meterse dentro del contenedor de PostgreSQL:

docker exec -it <nombre_del_contenedor_postgres> bash

Sustituye <nombre_del_contenedor_postgres> por el nombre real de tu contenedor. Si usas docker ps, lo verás fácil.


2. Conéctate a PostgreSQL

Normalmente, el usuario y la base de datos se llaman igual: authentik. Si no has tocado nada raro, este comando debería bastar:

psql -U authentik -d authentik

Cuando te lo pida, mete la contraseña. Es la misma que tienes en el .env, bajo PG_PASS.


3. Cambia los fondos de todos los flows

Aquí viene la línea mágica:

UPDATE authentik_flows_flow SET background = 'https://w.wallhaven.cc/full/2y/wallhaven-2yp6gg.png';

Obviamente, puedes poner cualquier URL de imagen que te guste. Yo suelo usar Wallhaven, clic derecho en la imagen y “copiar enlace”.


4. Sal de la base de datos

Cuando termines, escribe:

\q

Y luego exit para salir del contenedor.


5. Prueba si ha funcionado

Abre una ventana en modo incógnito (para evitar cacheos raros) y accede a tu pantalla de login. Si todo ha ido bien, el cambio es instantáneo. No hace falta reiniciar nada.


Conclusión

Así de fácil es dejar tu Authentik con estilo. Este truco no está en la documentación oficial, pero funciona perfecto si sabes por dónde meterle mano. Y si un día te aburres del fondo… repite el proceso con otra URL.


Referencias

Authentik

Cloudflare Turnstile en Authentik - Captcha previo a la autenticación


Introducción

Este artículo documenta la integración de Cloudflare Turnstile como etapa de captcha previa al proceso de autenticación en Authentik, con el objetivo de filtrar tráfico automatizado antes incluso de mostrar el formulario de login.

La integración se sitúa directamente dentro del authentication flow de Authentik, actuando como una barrera inicial que reduce ruido, ataques de fuerza bruta y automatización maliciosa sin introducir fricción innecesaria para usuarios legítimos. No sustituye otros mecanismos (MFA, rate‑limit, CrowdSec), sino que los refuerza desde el primer punto de entrada.


Enfoque general / Arquitectura

El enfoque se basa en insertar una Captcha Stage como primera etapa del default-authentication-flow:

Cliente → Captcha (Cloudflare Turnstile) → Formulario de login → MFA / resto de etapas

Características clave del enfoque:

Este planteamiento reduce carga en Authentik y en servicios posteriores, descartando tráfico basura desde el primer renderizado de la página.


Requisitos previos


Desarrollo

Qué se hizo y por qué

Se opta por Cloudflare Turnstile frente a reCAPTCHA por varios motivos:

La decisión de colocarlo antes del login es deliberada: cualquier captcha posterior ya implica haber servido HTML sensible (formularios, endpoints, lógica de sesión).


Configuración utilizada (solo enlaces)


Configuración en Authentik (conceptual)

  1. Crear una Captcha Stage desde: Admin → Flows and Stages → Stages → Create → Captcha Stage

  2. Parámetros relevantes de la etapa:

    • Public KeyTurnstile Site Key
    • Private KeyTurnstile Secret Key
    • Enable Interactive → Activado si el widget está en modo Managed o Invisible
    • JS URL https://challenges.cloudflare.com/turnstile/v0/api.js
    • API URL https://challenges.cloudflare.com/turnstile/v0/siteverify

    Las opciones de score se dejan por defecto, ya que no aplican a Turnstile.

  3. Inserción en el flujo: Admin → Flows and Stages → Flows → default-authentication-flow

    En Stage Bindings:

    • Añadir la Captcha Stage.
    • Asignarle el orden más bajo del flujo para que se ejecute antes que cualquier otra etapa.

Validación

Comprobaciones mínimas tras la integración:


Decisiones importantes o problemas detectados


Resumen breve


Referencias

Authentik

Creación de aplicaciones, providers y outposts en Authentik


Introducción

Authentik es una plataforma open source pensada para gestionar la autenticación y los accesos de usuarios en sistemas multiusuario, ya sea en entornos personales, empresariales o mixtos. Su enfoque modular y flexible permite centralizar la seguridad y el control de quién entra, cuándo y a qué aplicaciones. En esta guía, vamos a ver cómo crear una aplicación dentro de Authentik, configurarle su provider correspondiente y enlazarla con un outpost para dejarla operativa. Todo explicado paso a paso y sin rodeos.


Crear aplicación + provider con el asistente

  1. Accede al panel de administración de Authentik.

  2. En la sección lateral, ve a Applications.

  3. Si tienes una versión reciente, verás este mensaje:

    You can now configure both an application and its authentication provider at the same time with our new Application Wizard.

  4. Pulsa en Create with wizard. Este asistente te permitirá crear la aplicación y su provider en una misma secuencia, ahorrándote tiempo y errores.

Paso 1: Configurar la aplicación

Paso 2: Elegir el tipo de provider

Paso 3: Configurar el provider

Paso 4: Asignar permisos de acceso

Paso 5: Finalizar creación


Asociar la app a un outpost

Ahora toca vincular la aplicación a un outpost, que es el componente de Authentik encargado de hacer de "puente" entre las apps y el sistema de autenticación.

  1. Desde el menú lateral, entra en Outposts.
  2. Verás uno ya creado por defecto llamado authentik Embedded Outpost. Haz clic en el lápiz para editarlo.
  3. Asegúrate de que el Type esté en Proxy, que es el necesario para apps con forward authentication.
  4. Baja a la sección Applications. Allí verás dos columnas: una con aplicaciones disponibles y otra con asignadas.
  5. Busca tu app (test) en la lista de disponibles y haz doble clic sobre ella para moverla a la columna de asignadas.
  6. Pulsa Update para guardar todos los cambios.

Conclusión

¡Ya está! Acabas de crear y configurar tu primera aplicación en Authentik, junto con su provider correspondiente y asignación al outpost. Esto te da control centralizado sobre qué usuarios pueden acceder, desde qué grupos y con qué reglas. Si en el futuro necesitas añadir más aplicaciones, usuarios o personalizar políticas, ya conoces la base para moverte con soltura por Authentik. Todo desde una única interfaz, sin complicaciones y con una arquitectura limpia.

Authentik

Directiva de Authentik para Caddy


Si estás utilizando Authentik como solución de autenticación y quieres integrarlo en tu configuración de Caddy, puedes usar la siguiente directiva lista para funcionar (o al menos, funcional en mi caso):

# Directiva de Authentik (mostrando la IP real del cliente, por si usas Cloudflare o similar)
(authentik) {
    reverse_proxy /outpost.goauthentik.io/* http://192.168.1.90:19000
    forward_auth http://192.168.1.90:19000 {
        uri /outpost.goauthentik.io/auth/caddy
        copy_headers X-Authentik-Username X-Authentik-Email X-Authentik-Groups X-Authentik-Name X-Authentik-Uid
        header_up X-Real-IP {client_ip}
        header_up X-Client-IP {client_ip}
    }
}


Personalización de la configuración

Para adaptar esta directiva a tu entorno, sustituye:

Si has desplegado Authentik mediante Docker, asegúrate de que el puerto configurado en docker-compose.yml coincide con el utilizado en esta directiva. Puedes encontrar o definir este puerto en el archivo .env que se usa al desplegar Authentik:

AUTHENTIK_PORT_HTTP=19000

Importando la directiva en Caddy

Una vez configurada la directiva de Authentik, solo queda importarla dentro de la configuración de Caddy para proteger las aplicaciones deseadas. Un ejemplo práctico para una biblioteca digital con Calibre sería:

# Biblioteca Digital
calibre.example.com {
    reverse_proxy http://192.168.1.90:20980
    import authentik
}

Notas finales

Con esto, Authentik debería empezar a proteger las aplicaciones configuradas en Caddy de manera efectiva.

Authentik

Evitar MFA en casa con Authentik


Introducción

Evitar que Authentik pida el segundo factor en casa, donde es una molestia constante. Se aplica solo bajo una IP fija, y sin comprometer la seguridad externa.


Características


Requisitos previos


Flujo general

Navegador ─▶ Cloudflare ─▶ Caddy ─▶ Authentik Outpost ─▶ App
                 ▲ IP real via X-Forwarded-For     ▲
                 └─────────────────────────────────┘

Caddyfile adaptado

Importante: este ejemplo solo aplica a aplicaciones que estén protegidas por Authentik. Si una app no utiliza Authentik como sistema de autenticación, este snippet no tendrá efecto sobre ella.

Antes de modificar nada, se recomienda hacer una copia de seguridad de tu Caddyfile actual. Por la naturaleza de los cambios (cabeceras, autenticación, DNS...), un error puede dejarte sin acceso a tus servicios.

Antes de modificar nada, se recomienda hacer una copia de seguridad de tu Caddyfile actual. Por la naturaleza de los cambios (cabeceras, autenticación, DNS...), un error puede dejarte sin acceso a tus servicios.

Ejemplo con datos falsos para documentar el flujo.

{
	email     ejemplo@dominio.com
	acme_dns  cloudflare "API_KEY_FAKE123"

	servers {
		trusted_proxies static private_ranges \
			203.0.113.0/24 198.51.100.0/24 192.0.2.0/24
	}
}

(authentik) {
	reverse_proxy /outpost.goauthentik.io/* http://10.0.0.3:15500

	forward_auth http://10.0.0.3:15500 {
		uri /outpost.goauthentik.io/auth/caddy

		copy_headers {
			X-Authentik-Username
			X-Authentik-Email
			X-Authentik-Groups
			X-Authentik-Name
			X-Authentik-Uid
		}

		header_up X-Real-IP   {client_ip}
		header_up X-Client-IP {client_ip}
	}
}

# Cada app que requiera autenticación debe seguir este mismo patrón.
# Primero importamos el snippet de Authentik, luego definimos el reverse_proxy de la app.

app.midominio.com {
	log {
		output file /var/log/caddy/app-access.log
		format transform "{request>headers>X-Forwarded-For>[0]:request>remote_ip} - {user_id} [{ts}] \"{request>method} {request>uri} {request>proto}\" {status} {size}" {
			time_format "02/Jan/2006:15:04:05 -0700"
		}
	}

	route {
		# 1) Llama al snippet que gestiona la autenticación
		import authentik

		# 2) Redirige a la app protegida
		reverse_proxy http://10.0.0.3:8080
	}
}

Policy en Authentik

  1. Expression Policy Nombre: Skip-Home-IP

    from ipaddress import ip_address
    return ak_client_ip == ip_address("203.0.113.42")
    
  2. Aplica la policy Ruta: Flows and Stages → Flows → default-authentication-flow → Stage Bindings → default-authentication-mfa-validation Bindea: la policy Skip-Home-IP Orden: 0 Negate: desactivado

Si tienes IP dinámica pero dentro de un rango:

from ipaddress import ip_network
return ak_client_ip in ip_network("203.0.113.0/24")

Verificación

Prueba Esperado
Desde casa Sin MFA.
Fuera de casa MFA/login normal.
Audit → Requests ALLOW (policy) y IP correcta en Client-IP.
caddy validate Configuración válida.

Ventajas

Qué Por qué
Sin MFA en casa Nada de abrir el móvil cada dos por tres.
IP real protegida trusted_proxies evita que te cuelen cabeceras falsas.
Mantenimiento mínimo Solo un snippet + una policy.
Logs decentes Se ve quién accedió, desde dónde, sin cosas raras.
Reversible fácil Borra la policy o el import, y listo.

Resumen breve


Referencias

Caddy:

Authentik:

Authentik

Forzar MFA en todos los usuarios de Authentik


Pequeña nota para dejar claro cómo obligar a que todos los usuarios de Authentik (ya existentes o nuevos) activen y usen un segundo factor de autenticación.


Requisitos previos


Pasos

1. Editar el stage de MFA

En Flows and Stages → Stages, buscar default-authentication-mfa-validation.

Con esto, cualquier usuario sin MFA configurado será obligado a activarlo.


2. Insertar el stage en el flow de autenticación


Resultado

Con esa configuración, cualquier usuario que intente iniciar sesión sin MFA configurado se verá obligado a hacerlo antes de poder acceder.

Authentik

Login sin contraseña en Authentik usando WebAuthn


Introducción

Este artículo documenta la habilitación de autenticación passwordless en Authentik mediante WebAuthn, utilizando llaves físicas (YubiKey u otras compatibles).

La integración se realiza a nivel de flujos de autenticación, sin eliminar el login tradicional, sino añadiendo una vía alternativa controlada desde el flujo principal. El resultado es un inicio de sesión donde Authentik detecta que el usuario dispone de un autenticador WebAuthn y ofrece iniciar sesión sin contraseña.


Requisito previo imprescindible: dispositivo WebAuthn registrado

Antes de modificar cualquier flujo, el usuario debe tener registrada una llave WebAuthn.

Este paso se realiza desde la interfaz de usuario, no desde el panel de administración:

Sin este requisito, el flujo passwordless no tendrá ningún dispositivo que validar y el login no funcionará.


Enfoque general

El esquema que se construye es el siguiente:

  1. El flujo de autenticación por defecto identifica al usuario.

  2. Si el usuario dispone de dispositivos WebAuthn registrados:

    • Se ofrece un flujo alternativo passwordless.
  3. Dicho flujo valida el autenticador WebAuthn.

  4. Tras la validación, se continúa con el login estándar de Authentik.

No se sustituye el login clásico: se complementa.

En usuarios con WebAuthn configurado, el proceso de autenticación se resuelve únicamente mediante la llave, sin interacción adicional ni validación de contraseña.


Desarrollo

Creación del flujo passwordless

En la interfaz de administración:

Este flujo se utilizará exclusivamente para la autenticación sin contraseña.


Validación de dispositivos WebAuthn

Dentro del flujo recién creado:

Configuración relevante:

Order:

Esta etapa es la encargada de validar los dispositivos WebAuthn ya configurados por el usuario.


Continuación con el login estándar

Dentro del mismo flujo:

De este modo:


Enlace del flujo passwordless al flujo principal

Para que Authentik ofrezca este método de autenticación:

En Flow settings:

Guardar los cambios con Update.

Este paso vincula el flujo passwordless con el proceso de autenticación principal.


Validación

Si el usuario tiene WebAuthn configurado correctamente, el login se realizará sin contraseña.


Decisiones importantes y consideraciones


Resumen breve


Referencias

Gitea

Notas personales sobre Gitea: no es una guía, es una vacuna contra perder tiempo.

Gitea

Añadir una llave física en Gitea


Introducción

Configuración del inicio de sesión en Gitea mediante una llave física compatible con WebAuthn (YubiKey 5C NFC en este caso), manteniendo el método TOTP activo como respaldo en caso de pérdida o fallo de la llave.


Requisitos previos


Desarrollo / pasos

1. Acceder a la configuración de seguridad

Desde el perfil de usuario: Perfil → Configuración → Seguridad.

2. Añadir la llave física

En el apartado Two-Factor Authentication (Security Keys):

3. Confirmar el registro

La llave quedará listada con el nombre asignado. Se puede verificar su funcionamiento cerrando sesión y volviendo a iniciar con la llave insertada o aproximada (en caso de NFC).

4. Mantener TOTP como respaldo

No eliminar el método TOTP. Servirá para acceder si la llave se pierde, se rompe o deja de funcionar.


Errores comunes o decisiones importantes


Resumen breve


Referencias o enlaces de interés

Gitea

Personalización de Gitea: Temas y otros ajustes


Introducción

Este artículo recoge los pasos necesarios para personalizar Gitea mediante temas, logos, favicons y plantillas. Todo con Docker, sin complicaciones raras. Asume que tienes los datos montados como /mnt/data:/data en el contenedor.


Estructura de carpetas

Asegúrate de tener creada la carpeta public dentro del volumen de datos. Por ejemplo:

drwxr-xr-x user user 4.0 KB ... public

Temas personalizados

  1. Crea tu CSS personalizado, por ejemplo mi-tema.css.
  2. Copia el archivo a:
/mnt/data/public/assets/css/mi-tema.css
  1. Edita el archivo app.ini (en /mnt/data/conf/app.ini) y añade en [ui]:
[ui]
THEMES = gitea,arc-green,mi-tema
DEFAULT_THEME = mi-tema
  1. Reinicia Gitea:
docker-compose restart gitea
  1. Desde la interfaz, ve a Configuración > Cuenta y selecciona el tema.

Cambiar logo y favicon

  1. Prepara los archivos:

    • logo.svg
    • favicon.png
  2. Copia a:

/mnt/data/public/assets/img/logo.svg
/mnt/data/public/assets/img/favicon.png
  1. Reinicia el contenedor:
docker-compose restart gitea

Personalizar plantillas

  1. Crea o copia las plantillas a:
/mnt/data/public/templates
  1. Edita con cuidado (usa sintaxis de Go templates).
  2. Reinicia Gitea para aplicar los cambios.

Buenas prácticas


Referencias

Gitea

YubiKey en Gitea: Error al registrar llave


Descripción

Al intentar añadir una YubiKey como método 2FA en Gitea, puede aparecer el error:

Could not read your security key.
An unknown error occurred. Please retry.

Y en los logs:

Unable to finish registration due to error: Error validating origin
DevInfo: Expected Values: [http+unix://gitea.tudominio.org], Received: https://gitea.tudominio.org
CreateCredential: Error validating origin

Este error ocurre cuando Gitea genera automáticamente la variable ROOT_URL de forma incorrecta (por ejemplo, con el prefijo http+unix://).


Solución

Editar el archivo de configuración dentro del contenedor:

nano /data/gitea/conf/app.ini

o, según la ruta interna del contenedor:

nano /gitea/conf/app.ini

Modificar la línea correspondiente a la URL base de la instancia:

ROOT_URL = https://gitea.tudominio.org/

Importante: asegúrate de incluir la barra final /.

Con esto, Gitea podrá validar correctamente el origen (origin) durante el registro de la YubiKey y permitirá añadirla sin errores. Probado con una Yubikey 5C NFC.


Referencias

RustDesk

Cosas que fallaron en RustDesk justo cuando más lo necesitaba. Aquí dejo los trucos que me salvaron.

RustDesk

RustDesk, conexión no cifrada


Introducción

Este artículo documenta un tip técnico para asegurar correctamente las conexiones en RustDesk, evitando sesiones sin cifrar o conexiones forzadas a través de relay cuando no es necesario.

En determinados escenarios, una instalación funcional de RustDesk puede mostrar conexiones relayed o unencrypted, lo que implica mayor latencia y menor control sobre el tráfico. El objetivo de este ajuste es garantizar cifrado extremo a extremo y uso preferente de conexiones directas.


Contexto del problema

RustDesk separa los roles de HBBS (ID Server) y HBBR (Relay Server), y ambos utilizan claves para asegurar la comunicación. Si estas claves no están alineadas correctamente, pueden producirse los siguientes síntomas:

El problema no suele ser de red, sino de desajuste de claves entre servicios.


Requisitos previos

Condiciones necesarias antes de aplicar este ajuste:

La instalación base de RustDesk se documenta en un artículo independiente.


Enfoque general de la solución

La solución se basa en dos acciones clave:

Esto asegura que ambas piezas confían entre sí y permiten sesiones cifradas de extremo a extremo.


Limitación de acceso mediante clave pública

RustDesk permite restringir el acceso al servidor mediante claves públicas. Para ello, los servicios deben arrancar con el parámetro de clave activado.

En un despliegue basado en Docker, es necesario modificar el comando de arranque de HBBS y HBBR.

Ejemplo de configuración:

hbbr:
  command: hbbr -k _

hbbs:
  command: hbbs -r <IP_DEL_SERVIDOR>:21117 -k _

El carácter _ indica que RustDesk debe generar y gestionar automáticamente las claves, sin intervención manual. A partir de este momento, todas las conexiones que pasen por el servidor estarán asociadas a este par de claves.

Este ajuste es imprescindible para habilitar cifrado extremo a extremo real.


Sincronización de claves entre HBBS y HBBR

En algunos despliegues, RustDesk genera las claves en directorios distintos para cada servicio. Si estas claves no coinciden, el cliente mostrará conexiones unencrypted o forzará el uso de relay.

Pasos habituales para resolver el problema:

  1. Localizar el volumen persistente donde RustDesk almacena sus datos. Por ejemplo:
/docker/rustdesk/
  1. Identificar el directorio asociado a HBBS, donde se generan las claves:
/docker/rustdesk/hbbs/
  1. Copiar las claves generadas hacia el directorio utilizado por HBBR:
cp /docker/rustdesk/hbbs/id_ed25519* /docker/rustdesk/hbbr/

Con esto se garantiza que ambos servicios utilizan exactamente el mismo par de claves.

Este paso corrige el conocido key mismatch y es crítico para que el cifrado funcione correctamente.


Aplicación de cambios

Una vez aplicados los ajustes anteriores:

  1. Reiniciar los servicios de RustDesk para que carguen las nuevas claves.
  2. Verificar que los contenedores arrancan sin errores relacionados con claves o certificados.

No es necesario realizar cambios adicionales en los clientes, más allá de volver a conectar.


Verificación

Para confirmar que la configuración es correcta:

Si alguno de estos puntos no se cumple, revisar nuevamente la generación y sincronización de claves.


Consideraciones importantes


Resumen breve

Una instalación correcta de RustDesk puede funcionar sin cifrado completo si las claves no están alineadas. Forzar la generación de claves y sincronizarlas entre HBBS y HBBR garantiza conexiones cifradas, reduce latencia y evita dependencias innecesarias del relay.


Referencias

Wazuh

Mis notas de supervivencia para que Wazuh no se convierta en spam. Ajustes de alertas, reglas y demás magia para que solo me moleste cuando realmente hay fuego.

Wazuh

Políticas que uso hoy en día en Wazuh


Introducción

Apunte rápido para tener recogidas las políticas que uso en Wazuh. Si añado más en el futuro, irán aquí. La idea es mantener un equilibrio entre conservar información útil para análisis forense y no saturar el almacenamiento de la máquina virtual donde corre Wazuh.


Retención de índices en OpenSearch

Alerts — 90 días

Ver en Gitea

Política que elimina índices wazuh-alerts-* con más de 90 días de antigüedad. Se prioriza así mantener alertas recientes para correlaciones o revisiones rápidas, pero sin almacenar indefinidamente los índices que ya no aportan valor.

"policy_id": "wazuh-alerts-90d",
"description": "Eliminar índices wazuh-alerts-* mayores de 90 días"

Archives — 180 días

Ver en Gitea

Política que elimina índices wazuh-archives-* con más de 180 días de antigüedad. En este caso, la retención es más amplia porque los archives contienen un histórico completo de eventos que pueden ser útiles para investigaciones más largas o revisiones de cumplimiento.

"policy_id": "wazuh-archives-180d",
"description": "Eliminar índices wazuh-archives-* mayores de 180 días"

Métricas — 30 días

Ver en Gitea

Política que elimina índices wazuh-monitoring-* y wazuh-stats-* con más de 30 días de antigüedad. Las métricas tienen un valor más inmediato (estado de agentes, consumo de recursos, estadísticas de uso) y rara vez son necesarias más allá de un mes.

"policy_id": "wazuh-metrics-30d",
"description": "Eliminar índices wazuh-monitoring-* y wazuh-stats-* mayores de 30 días"

Limpieza en disco con crontab

Ver en Gitea

Además de la limpieza de índices en OpenSearch, aplico un borrado periódico en disco dentro de la VM de Wazuh. El espacio de esta máquina es limitado (~60 GB), así que conviene eliminar también los ficheros crudos que se van acumulando en /var/ossec/logs/. De no hacerlo, podrían saturar el disco aunque los índices ya estén rotados.

# Elimina alertas con más de 90 días de antigüedad
0 0 * * * find /var/ossec/logs/alerts/ -type f -mtime +90 -exec rm -f {} \;

# Elimina archivos de archivo (archives) con más de 90 días de antigüedad
0 0 * * * find /var/ossec/logs/archives/ -type f -mtime +90 -exec rm -f {} \;

Esta doble estrategia (índices en OpenSearch + ficheros en disco) asegura que los datos no se acumulen por duplicado en dos capas distintas.


Resumen breve