Cómo tener nuestro propio SSO+2FA con Authelia y Nginx Proxy Manager
Este artículo está basado en la versión 2.9.19 de NginxProxyManager. Las versiones 2.10 y posteriores incluyen algunos Breaking Changes que afectan a cómo funciona la integración con Authelia, que aún no he podido revisar.
Si disponemos de un servidor privado (o VPS) donde tenemos varios servicios expuestos a Internet, a lo mejor queremos añadirle una capa extra de seguridad. O directamente añadir una, ya que algunos de estos servicios, al estar pensados para uso local, pueden carecer de log-in.
Authelia es un servicio que nos permite implementar eso de una forma realmente sencilla y rápida.
¿Qué es SSO?
No entraremos muy en detalle, puesto que es algo más complejo que 2 simples párrafos, pero las siglas (en inglés) significan "Single Sign On", lo que traducido podría ser algo así como "Registro Único". En el mundo empresarial es una terminología muy conocida, pero más allá de eso, y para entenderlo fácilmente, el ejemplo más fácil sería nuestra cuenta de Google: con ella podemos acceder a todos sus servicios como correo, calendario, drive... Es decir, tenemos una única cuenta para acceder a diferentes servicios.
Pero el SSO puede servir no sólo para productos de una misma empresa, sino que podemos usar una misma cuenta para acceder a diferentes servicios de diferentes empresas, como pasa generalmente para acceder a diferentes herramientas internas de una compañía (Jira/GitLab/Herramientas internas...). Todas ellas requieren de la cuenta corporativa para acceder.
Pero yo no tengo ninguna empresa, soy un simple friki
Vale, pero eso no quiere decir que no podamos añadir un extra de seguridad a nuestros servicios.
Como hemos comentado, a veces muchos de los servicios que queremos utilizar (la gran mayoría van a ser OpenSource) están pensados para uso local, y pueden carecer de log-in como tal. Otras veces simplemente queremos añadir ese extra de seguridad, ya que al exponer cosas a Internet toda seguridad es poca.
Por ejemplo, podemos tener nuestro gestor de finanzas, Plex, nuestro gestor de favoritos, nuestro propio buscador, nuestra aplicación de recetas... Aunque algunos puedan tener registro de usuarios, tal vez queremos limitar un poco más el acceso, pudiendo tener el log-in de Authelia + 2FA + log-in de aplicación.
Desplegar Authelia con Docker
La mejor forma de desplegar Authelia es usar Docker, como la inmensa mayoría de servicios actuales. Para empezar, lo que haremos es ir a nuestro proveedor de dominios a crear un subdominio destinado a nuestra plataforma de autenticación. Por ejemplo, lo podemos llamar authelia.midominio.com
, o login.midominio.com
, eso ya es elección de cada uno.
Ah, y acordarse de apuntarlo a la IP de nuestro servidor.
Luego procedemos a añadir a nuestro servidor la carpeta correspondiente a Authelia (como siempre donde más nos guste), y dentro debemos crear varias cosas.
Por una parte, el fichero docker-compose.yml
version: '3.3'
services:
authelia:
image: authelia/authelia
container_name: authelia
volumes:
- ./config:/config
ports:
- "9091:9091"
expose:
- 9091
restart: unless-stopped
healthcheck:
disable: true
environment:
- TZ=Europe/Madrid
Por otra parte, debemos crear una carpeta llamada config
, y dentro debemos añadir los siguientes ficheros:
configuration.yml
Este fichero es la base de la configuración para Authelia, y más abajo se detallan los campos importantes.
###############################################################
# Authelia configuration #
###############################################################
jwt_secret: a_very_important_secret
default_redirection_url: https://public.example.com
server:
host: 0.0.0.0
port: 9091
log:
level: debug
# This secret can also be set using the env variables AUTHELIA_JWT_SECRET_FILE
totp:
issuer: authelia.com
# duo_api:
# hostname: api-123456789.example.com
# integration_key: ABCDEF
# # This secret can also be set using the env variables AUTHELIA_DUO_API_SECRET_KEY_FILE
# secret_key: 1234567890abcdefghifjkl
authentication_backend:
file:
path: /config/users_database.yml
access_control:
default_policy: deny
rules:
# Rules applied to everyone
- domain: public.example.com
policy: bypass
- domain: subdomain1.example.com
policy: one_factor
- domain: subdomain2.example.com
policy: two_factor
session:
name: authelia_session
# This secret can also be set using the env variables AUTHELIA_SESSION_SECRET_FILE
secret: unsecure_session_secret
expiration: 3600 # 1 hour
inactivity: 300 # 5 minutes
domain: example.com # Should match whatever your root protected domain is
# redis:
# host: redis
# port: 6379
# This secret can also be set using the env variables AUTHELIA_SESSION_REDIS_PASSWORD_FILE
# password: authelia
regulation:
max_retries: 3
find_time: 120
ban_time: 300
storage:
encryption_key: you_must_generate_a_random_string_of_more_than_twenty_chars_and_configure_this
local:
path: /config/db.sqlite3
notifier:
smtp:
username: test
# This secret can also be set using the env variables AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE
password: password
host: mail.example.com
port: 25
sender: admin@example.com
En dicho fichero se deben modificar/añadir las siguientes cosas:
- jwt_secret: debe ser un "token" autogenerado lo más complejo posible, de hasta 64 caracteres.
- default_redirection_url: debemos añadir el dominio que hemos creado para nuestro servidor de Authelia
- access_control: se deben añadir aquellos subdominios que se quieran gestionar con Authelia, dentro del bloque
rules
, con una de las siguientes políticas:- bypass: permite el tráfico abiertamente
- one_factor: requiere de log-in con las credenciales de Authelia
- two_factor: además de log-in con credenciales, se requiere un OTP
- session: en esta sección se deben modificar 2 cosas:
- secret: debe ser un secreto lo suficientemente complejo, de al menos 16 caracteres
- domain: aquí debemos añadir el dominio base al que van a pertenecer todos los subdominios que vayamos a gestionar (midominio.com)
- storage: aquí debemos modificar el siguiente parámetro:
- encryption_key: como antes, debe ser una clave suficientemente segura
- notifier: aquí debemos rellenar los campos con los datos de nuestro servidor de correo electrónico. Este punto es muy importante para poder activar el 2FA, y si no está bien configurado el servicio directamente no arrancará.
El resto de valores los podemos dejar por defecto, a menos que sepamos qué estamos haciendo.
users_database.yml
En este fichero es donde vamos a definir los usuarios que van a tener acceso a través de Authelia.
###############################################################
# Users Database #
###############################################################
# This file can be used if you do not have an LDAP set up.
# List of users
users:
username1:
displayname: "John Doe"
password: "my hashed pass" # yamllint disable-line rule:line-length
email: me@mydomain.com
groups:
- admins
- dev
Lo importante aquí son varios puntos. Por una parte, dentro del bloque users
debemos definir tantos usuarios como queramos siguiendo la estructura del ejemplo de arriba.
username1 será el nombre de usuario para acceder, y será el que inicia el bloque de configuración de dicho usuario.
Lo siguiente relevante es el password, que no debe ser en texto plano, sino que deberá estar encriptado. Para ello podemos usar un pequeño script que proporciona la propia imagen Docker de Authelia, de la siguiente manera:
docker run authelia/authelia:latest authelia hash-password -- 'password'
Que nos generará algo parecido a esto:$argon2id$v=19$m=65536,t=3,p=4$KzRQdnFKVGxrcFNwRGNheA$Gf4geiNHilF5IE/X1oIyIOQA1ePbICrMbtXKY3Sji7g
Y será este string lo que debemos pegar en el campo password
.
Por último, el correo debe ser válido, ya que para activar el 2FA se enviará un mail de activación. Los grupos se pueden dejar como están, porque es para configuraciones más avanzadas.
Y con esto ya estaríamos en disposición de arrancar nuestro servidor de Authelia con docker-compose up -d
.
Probar Authelia
Lo mejor que podemos hacer para comprobar que todo funciona correctamente es añadir como regla el propio dominio que hayamos creado y asignarle una política de two_factor
en el fichero de configuración de Authelia.
Luego, accedemos al dominio en cuestión y deberíamos ver algo parecido a la siguiente imagen.
Al poner nuestro usuario y contraseña, la primera vez que accedemos nos pedirá activar 2FA, así que pulsamos sobre "Registrar Dispositivo":
Al hacerlo se nos enviará un mail para verificar la cuenta:
Al pulsar sobre "Register" se abrirá el navegador mostrando algo parecido a esto.
Lo que deberemos hacer es usar la app de 2FA que más nos guste (en mi caso uso Aegis y Bitwarden, por lo de que son OpenSource y esas cosas) para hacer una foto al QR. Alternativamente, podemos copiar y pegar el secreto que aparece abajo.
Tras eso, nos pedirá el código de verificación que se habrá generado con la aplicación para comprobar que todo funciona correctamente:
Y si todo ha ido bien, ya tendremos Authelia configurado.
Preparar Nginx Proxy Manager
Una vez tenemos preparado el servicio de Authelia, debemos añadir cierta configuración al Reverse Proxy. Si hemos configurado Nginx Proxy Manager siguiendo este artículo, será necesario realizar algunas modificaciones. Si lo habéis desplegado de otra forma, bastará adaptar lo siguiente a vuestra configuración.
Lo primero que haremos es crear una carpeta llamada snippets
dentro de la carpeta raíz donde tengamos la configuración de Nginx Proxy Manager (donde esté el docker-compose.yml). Dentro de esta carpeta snippets
creamos 2 ficheros:
authelia-location.conf
## Virtual endpoint created by nginx to forward auth requests.
location /authelia {
## Essential Proxy Configuration
internal;
proxy_pass https://authelia.mydomain.com/api/verify;
## Headers
## The headers starting with X-* are required.
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Forwarded-Method $request_method;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Content-Length "";
proxy_set_header Connection "";
## Basic Proxy Configuration
proxy_pass_request_body off;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; # Timeout if the real server is dead
proxy_redirect http:// $scheme://;
proxy_http_version 1.1;
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 4 32k;
client_body_buffer_size 128k;
## Advanced Proxy Configuration
send_timeout 5m;
proxy_read_timeout 240;
proxy_send_timeout 240;
proxy_connect_timeout 240;
}
Aquí debemos cambiar la variable proxy_pass
por nuestro dominio de Authelia, dejando "/api/verify" al final.
authelia-authrequest.conf
## Send a subrequest to Authelia to verify if the user is authenticated and has permission to access the resource.
auth_request /authelia;
## Set the $target_url variable based on the original request.
## Comment this line if you're using nginx without the http_set_misc module.
#set_escape_uri $target_url $scheme://$http_host$request_uri;
## Uncomment this line if you're using NGINX without the http_set_misc module.
set $target_url $scheme://$http_host$request_uri;
## Save the upstream response headers from Authelia to variables.
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
auth_request_set $name $upstream_http_remote_name;
auth_request_set $email $upstream_http_remote_email;
## Inject the response headers from the variables into the request made to the backend.
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
proxy_set_header Remote-Name $name;
proxy_set_header Remote-Email $email;
## If the subreqest returns 200 pass to the backend, if the subrequest returns 401 redirect to the portal.
error_page 401 =302 https://authelia.mydomain.com/?rd=$target_url;
Aquí debemos modificar la variable error_page 401
por nuestro dominio de Authelia, dejando "/?rd=$target_url" al final.
Lo que nos quedaría es añadir la siguiente línea al docker-compose.yml que ya tenemos de Nginx Proxy Manager, en la sección de volumes, para que cargue los nuevos ficheros:
- ./snippets/:/etc/nginx/snippets
Añadir la configuración a los subdominios de Nginx Proxy Manager
Lo último que nos falta por hacer es incluir estos ficheros en los subdominios que nos interese limitar. Para ello accedemos a las opciones del subdominio en cuestión, dentro de la configuración de Nginx Proxy Manager, y añadimos las siguientes líneas en la sección "Custom Nginx Configuration", dentro de la pestaña "Advanced":
include /etc/nginx/snippets/authelia-location.conf;
include /etc/nginx/snippets/authelia-authrequest.conf;
Quedando de la siguiente manera:
Y listo, ya tendríamos el subdominio con una capa extra de seguridad. Para validarlo, abrimos un navegador en modo incógnito y accedemos al dominio que acabamos de configurar.
Conclusiones
Puede que esta haya sido una entrada algo larga y técnica, pero si todo ha salido a pedir de Milhouse, ya tendremos nuestro propio servicio SSO+2FA listo para poner detrás cualquier aplicación que queramos, pudiendo acceder a ella con un único usuario, lo cual es bastante interesante.
Espero que os haya sido útil, y si por lo que fuera no os acaba de funcionar o se ha colado algo, me lo hacéis saber y le echamos un vistazo.
Fuente: Authelia