________ __________  __________________  __________________ ____ ___      
\______ \\______   \ \_   _____/\______ \ \_   _____/|    |   |    |     
 |    |  \|       _/  |    __)_  |    |  \ |    __)  |    |   |    |     
 |    `   \    |   \  |        \ |    `   \|     \   |    |  /|    |___  
/_______  /____|_  / /_______  //_______  /\___  /   |______/ |_______ \
        \/       \/          \/         \/      \/                    \/     
        

Il/lo/la Identity Provider: la base politically correct

Scritto il: 2026-03-12

N applicazioni, Y utenze, 1 password

Un tempo c'erano N applicazioni, Y utenti, N^Y password da ricordare, che per lo più erano "123456". Poi sono state introdotte delle stringenti policy di sicurezza per evitare il password guessing e il bruteforce, allorché è stato unanimamente deciso che le credenziali devono essere di almeno 8 caratteri. E questa è stata la svolta perché, dopo grandi sforzi, si è dovuto insegnare agli utenti che "123456" non è buono, come non è buono "000000" o "111111". Ma "12345678" evidentemente sarebbe stato sufficiente, per cui ecco miriadi di sistemi popolati da utenze come "Andrea", "Massimo", "Gianluca"" con 3 password distinte (ma uguali): "12345678". L'utenza admin, non dovendo sottostare a policy da se stessa imposte, fu sollevata dal dover reimpostare la propria password, che comunque non era "123456" ma "admin". E tale rimase.

A seguire fu deciso che probabilmente la complessità non era sufficiente, e che almeno si sarebbero dovuti usare delle lettere (maiuscole e minuscole), dei numeri e persino dei caratteri speciali. E quindi si parte con il nuovo trend: "a1234567!", "Pa55w0rd!" e "Nome1234!" (le pià fortunate erano le persone chiamate Ada perché in questo caso "Ada1234!" era compliant senza eccedere gli 8 caratteri, cosa che un "Gianluca1234!" necessitava di ricordarne almeno 13).

Comunque sia, per quanto uguali, c'era un problema insormontabile: se devi accedere a molte applicazioni, anche se la password è sempre uguale e molto complicata (magari perché c'è anche un * nel mezzo e non sei proprio in grado di ricordare in che punto sia della parola), devi perdere tempo a scriverle.

E quindi nasce il Single Sign On (o SSO). In pratica, una volta autenticato su un portale, sarà lui a informare le varie N applicazioni che tu, detentore della verità e delle credenziali, sei già stato da lui verificato e che gli N sudditi si sarebbero potuti fidare di te senza necessariamente chiederti ulteriori prove di rara identità.

Authentik

Authentik sarà il nostro mastro di chiavi. Sarà lui ad avere le identità di tutti e le appicazioni dovranno interrogarlo: Ma che sei sicuro questo sia il Talpo? Sìsì è il Talpo è il Talpo.

Il nostro approccio sarà molto pragmatico e indolore. Useremo Docker.

Passo 1: la preparazione dell'ambiente

Una volta entrati su antares via il vostro metodo preferito

# mkdir /opt/dreadful.work/authentik
# cd /opt/dreadful.work/authentik

Iniziamo con un bel docker-compose.yml il cui contenuto sarà:

services:
  postgresql:
    env_file:
    - .env
    environment:
      POSTGRES_DB: ${PG_DB:-authentik}
      POSTGRES_PASSWORD: ${PG_PASS:?database password required}
      POSTGRES_USER: ${PG_USER:-authentik}
    healthcheck:
      interval: 30s
      retries: 5
      start_period: 20s
      test:
      - CMD-SHELL
      - pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}
      timeout: 5s
    image: docker.io/library/postgres:16-alpine
    restart: unless-stopped
    volumes:
      #- database:/var/lib/postgresql/data
    - ./database:/var/lib/postgresql/data
  server:
    command: server
    depends_on:
      postgresql:
        condition: service_healthy
    env_file:
    - .env
    environment:
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.10.2}
    ports:
    - ${COMPOSE_PORT_HTTP:-9000}:9000
    - ${COMPOSE_PORT_HTTPS:-9443}:9443
    restart: unless-stopped
    volumes:
    - ./media:/media
    - ./custom-templates:/templates
  worker:
    command: worker
    depends_on:
      postgresql:
        condition: service_healthy
    env_file:
    - .env
    environment:
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.10.2}
    restart: unless-stopped
    user: root
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    - ./media:/media
    - ./certs:/certs
    - ./custom-templates:/templates

Ora c'è da dire una cosa. A me i named volumes hanno sempre suscitato un grande ribrezzo, per cui sebbene la documentazione ufficiale li usi, io li ho trasformati in volumi relativi. Anche perché così, a palle ferme, si fa un bel tarball e il backup è fatto. ${AUTHENTIK_TAG:-2025.10.2} significa semplicemente che se non viene definita la variabile, di default vale 2025.10.2. L'occhio attento noterà che necessitiamo di un file .env con le variabili di ambiente.

# echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
# echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
# echo "AUTHENTIK_TAG=2026.2" >> .env
# echo "AUTHENTIK_ERROR_REPORTING__ENABLED=true" >> .env

Ok ora fermiamoci un attimo. Authentik ascolta internamente sulle porte 9000/tcp e 9443/tcp e se vediamo i tag che abbiamo inserito nel docker-compose.yaml vediamo che sono anche le mappature di default. Se non ci piacciono e vogliamo esporle su altre porte è sufficiente:

# echo "COMPOSE_PORT_HTTPS=443" >> .env
# echo "COMPOSE_PORT_HTTP=80" >> .env

Questo è buono se vogliamo esporre direttamente Authentik su Internet, ma è mia personale opinione che come soluzione sia abbastanza oscena. Ecco perché io lascio la 9000 e la 9443 e a queste si connetterà il nostro fantastico reverse proxy fatto con nginx.

# echo "AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS=100.64.0.0/10,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fe80::/10,::1/128,192.168.0.0/24" >> .env

Quella serie di variabili ci dice quali sono i reverse proxy accetati (o meglio quali sono i loro indirizzi IP). Io non ho idea di dove lo vogliate mettere il vostro. Il mio sta su un'altra macchina con cui sono connesso via Netbird, ecco perché il primo della lista è 100.64.0.0/10 Dovete semplicemente adattare la lista alle vostre esigenze.

Detto questo si può procedere con un docker compose pull ; docker compose up -d ; docker compose logs -f.

Passo 2: akadmin e devnull

Siamo giunti al momento di configurare l'utente amministratore: akadmin. Per farlo dobbiamo andare su http://[ip-del-server]/if/flow/initial-setup/.

Inizialmente ci troveremo davanti a una bella schermata vuota. Clicchiamo su Interfaccia amministrativa e rendiamoci conto di un paio di cose

Comunque sia teniamo conto di una cosa:

Supponiamo di avere un servizio come Discourse. Vogliamo che chi si autentica su Authentik abbia accesso diretto al forum. Gli step sono:

Anzitutto mi fa onco pensare di dover usare akadmin, per cui creo un altro utente a cui eventualmente delegherò lo status di admin.

Interfaccia amministrativa --> Cartella --> Utenti --> New User (sì la traduzione è abbastanza fallace). Per un funzionamento di base è sufficiente compilare i campi

E ovviamente Attivo deve essere flaggato. Creiamo l'utente.

Cliccando sul nuovo utente appena creato si è sulla panoramica. Imposta password abbiamo già il sentore di a che cosa serva, per cui impostiamola. Fatto questo, in alto, accanto a Panoramica c'è Gruppi. Clicchiamoci sopra e aggiungiamo l'utente al gruppo esistente Authentik Admins. Tornando sulla panoramica, qualora vedessimo ancora "Superutente" valorizzato con No, dovremmo effettuare un'operazione molto delicata: aggiornare la pagina del browser.

Passo 3: la creazione del gruppo

Siccome non vogliamo farci mancare niente, vediamo come creare i gruppi, in modo poi da differenziare chi può accedere a quali applicativi. Dal menù laterale a sinistra di Authentik, Cartella --> Gruppi --> New Group, perché anche in questo caso la lingua italiana non prevede concetti come "Nuovo Gruppo", motivo per cui l'hanno lasciato in inglese.

Fine. Cliccate pure su Crea Gruppo.

Cliccando sul nome del gruppo appena creato, in alto avete la Panoramica proprio come nel caso degli utenti. Alla sua immediata destra ci sono gli Utenti che potete aggiungere. Anche in questo caso Aggiungi utente esistente e mettoamoci il buon vecchio caro devnull.

Passo 4: la creazione del provider

Ok abbiamo l'utente, abbiamo il gruppo. Che cosa facciamo? Installiamo da qualche parte Discourse (cosa che ovviamente non ho la minima intenzione di fare adesso, visto che è solo un esempio) e configuriamolo per fargli usare Authentik. Per farlo è necessario creare un provider: sempre dal menù a sinistra Appicazioni --> Providers --> Crea.

Per il nostro applicativo Discourse utilizzeremo il Fornitore Oauth2/OpenID

Il resto va bene così.

Passo 5: la creazione dell'applicazione

Sempre dal menù a sinistra: Applicazioni --> Applicazioni --> Crea (non con fornitore, lo abbiamo già creato il provider):

Create pure

Se volete associarlo ad un gruppo, ci cliccate sopra, compare la solita Panoramica, e alla sua destra c'è Associazione Criterio/Gruppo/Utente. Cliccandoci sopra possiamo selezionare "Associa esistente Criterio/Gruppo/Utente", possiamo selezionare quindi se associare ad un Criterio, ad un gruppo o ad un utente: scegliendo quello di mezzo, clichiamo sul campo Gruppo e selezioniamo Allow-Discourse.

Da questo momento, quando un utente si vuole autenticare sul sito su cui è ospitato Discourse, viene indirizzato ad Authentik: questo controllerà le credenziali, se sono valide controllerà il gruppo e, se anche questo permette l'accesso a Discourse, allora avrà accesso.

Attenzione: spesso le registrazioni sugli applicativi e le autenticazioni vanno buca perché l'utente non ha configurato una mail. Valorizzate sempre quel campo.

Passo 6: permettiamo il self register

Se vogliamo che gli avventori possano auto registrarsi nella nostra locanda, seppur con attivazione condizionata alla nostra benedizione (che avviene attivando l'utente da Cartella -> Utenti ), dobbiamo creare il flusso di registrazione. Ma prima ancora bisogna modificare il flusso di login.

Dal menù a sinistra Flussi e fasi --> Fasi e creiamone una nuova:

Adesso dobbiamo creare un'altra fase, ovvero quella per la richiesta del TOTP. Quindi, come appena fatto, procediamo con il crearne una nuova:

E per finire creiamo la fase per la registrazione utente con approvazione (ovvero di default inattiva):

Il resto può restare così com'è.

Spostiamoci sui flussi.

Dal menù a sinistra Flussi e fasi --> Flussi e creiamo un nuovo flusso:

Il resto può essere lasciato come di default. Clicchiamo quindi sul flusso appena creato, arrivando alla panoramica. In alto scegliamo Associazione Fase e proseguiamo con Bind Existing Stage, perché anche in questo caso la traduzione fa faville:

Cocludiamo e associamo adesso la fase successiva: di nuovo "Bind existing stage*

E per ultima la fase di TOTP, stesso procedimento:

Colpo di grazia: torniamo nella sezione delle fasi dal menù a sinistra Fussi e fasi --> Fasi e modifichiamo il default-authentication-identification. Scorriamo fino al termine di Impostazioni flusso --> Flusso di iscrizione valorizzandolo con *Registration-flow (Registration Flow).

In questo modo chi accede alla pagina principale di Authentik, può iscriversi (obbligatoriamente con TOTP) e necessiterà della nostra approvazione per proseguire.

Passo 7: vogliamo continuare con la porta 9000?

La domanda è retorica e la risposta è: NO.

Abbiamo più scelte, ma le principali sono due: o serviamo tutto dietro Cloudflare Tunnel, che sarebbe anche buona come cosa per evitare di esporre il nostro indirizzo, oppure usiamo un reverse proxy su una nostra macchina. Sì esatto possiamo usare anche la stessa su cui abbiamo installato Authentik, ma capite da soli che è meglio avere i front end delle applicazioni su host diversi rispetto al core. Ad ogni modo, supponendo di avere il dominio auth.dreadful.work adibito alla pubblicazione di Authentik, il reverse proxy fatto con nginx sarà:

server {
    listen 80;
    server_name auth.dreadful.work;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name auth.dreadful.work;

    ssl_certificate /etc/letsencrypt/live/auth.dreadful.work/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/auth.dreadful.work/privkey.pem;

    # Sicurezza aggiuntiva per l'IdP
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    # Authentik gestisce upload di icone/loghi e flussi pesanti
    client_max_body_size 50M;

    location / {
        # Inoltro verso Antares sulla porta 9443 tramite il DNS di NetBird
        proxy_pass https://antares.netbird.dreadful.work:9443;

        # Bypass verifica SSL (come su Cloudflare)
        proxy_ssl_verify off;
        proxy_ssl_server_name on;

        # Header fondamentali per l'autenticazione
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket per l'interfaccia amministrativa di Authentik
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Timeout generosi per evitare errori durante i flussi di login complessi
        proxy_read_timeout 900;
        proxy_connect_timeout 900;
        proxy_send_timeout 900;
    }
}

In questo caso specifico noterete che l'host antares è identificato con antares.netbird.dreadful.work: come avrete capito io utilizzo Netbird per la connettività; voi mettete l'indirizzo con cui il reverse proxy identifica l'host che ha Authentik (se sono sulla stessa macchina il 127.0.0.1 ci sta bene). Ricordate, ovviamente, di mettere l'indirizzo IP con cui il reverse proxy si presenta ad antares nel vostro .env come abbiamo visto nei primi passi:

AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS=100.64.0.0/10,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fe80::/10,::1/128,192.168.0.0/24

[EOF]