Configurazione di un bastione SSH con mTLS su HAProxy integrato con Windows Enterprise CA – Parte 1

da | Mar 23, 2026

 

Il protocollo SSH viene utilizzato dai sistemisti per collegarsi da remoto alle shell dei servers e tipicamente viene fortemente sconsigliato esporre questo servizio su reti non sicure, come ad esempio su internet.

L’utilizzo delle chiavi al posto delle credenziali tradizionali (username e password) per effettuare l’autenticazione può mitigare alcuni problemi di sicurezza, tuttavia in caso di vulnerabilità, potrebbe comunque esserne rischiosa l’esposizione.

Mediante HAProxy è possibile configurare un bastione SSH che permetta di collegarsi ai servers solo in seguito all’autenticazione mediante mTLS con certificati SSL, in modo che gli utenti non autorizzati non possano raggiungere i servers remoti in SSH.

In questo articolo vengono mostrati i passaggi necessari per la configurazione del cluster Keepalived e per la configurazione di HAProxy con gli scripts LUA, nei prossimi due articoli verranno mostrati i passaggi di configurazione della Enterprise CA di Windows e la configurazione sui clients.

REQUISITI

Affinché sia possibile configurare un cluster in alta affidabilità con Keepalived e HAProxy, sono necessari due servers che condividono un collegamento network L2 (con due IP sulla stessa subnet).

Allo scopo della stesura di questo articolo sono stati utilizzati due server Debian 13, se si utilizzano altre distribuzione alcuni comandi potrebbero variare.

Inoltre, per il rilascio dei certificati TLS/SSL è necessaria una CA privata, nel prossimo articolo verranno mostrati i passaggi di configurazione per la Enterprise CA di Windows, ma in alternativa potrebbe venir utilizzata una CA OpenSSL.

SCHEMA DI RETE

In seguito lo schema di rete che raffigura l’architettura proposta in questo articolo:

Come si può notare dal disegno, il mTLS viene utilizzato tra HAProxy ed i clients, invece le connessioni verso i servers interni sono cifrate ed autenticate solamente mediante il procollo SSH.

CONFIGURAZIONE PARAMETRI DEL KERNEL

Prima di proseguire con l’installazione dei servizi, è necessaria la modifica di alcuni parametri del kernel, in particolare il primo parametro viene utilizzato per disabilitare l’IPv6 (operazione consigliata, ma non obbligatoria) ed il secondo per consentire ad HAProxy di mettersi in ascolto su IP che non gli appartengono (operazione obbligatoria per effettuare il bind sui VIP).

Eseguire i seguenti comandi come root su una bash al fine di creare i files di configurazione ed applicare le modfiche:

 

MODIFICA LISTEN ADDRESS SSHD

Al fine di evitare che il demone SSH sui servers HAProxy sia in ascolto anche sul VIP, rendendone impossibile l’utilizzo per il bastione, è possibile modificarne la configurazione.

Eseguire i seguenti comandi su una bash come root, opzionalmente è possibile sostituire il valore di LISTEN_ADDRESS nella prima riga con un IP qualunque del server:

Verificare che nel file /etc/ssh/sshd_config.d/hardening.conf sia presente l’IP corretto e riavviare il servizio:

 

COPIA DELLE CHIAVI SSH

Per semplificare la copia delle configurazione tra i due servers HAProxy è possibile generare due coppie di chiavi SSH ed autorizzarle mediante authorized_keys, in modo che non venga richiesta la password quando si esegue “scp”.

Per generare una coppia di chiavi eseguire in una bash come root su entrambi i nodi il seguente comando:

Copiare la chiave pubblica (/root/.ssh/id_ed25519.pub o /root/.ssh/id_rsa.pub) nel file /root/.ssh/authorized_keys dell’altro nodo.

Se il file non esiste è possibile crearlo, ma in seguito è necessario lanciare il seguente comando per aggiustare i permessi:

Se la configurazione è andata a buon fine è possibile accedere in SSH sull’altro nodo come root senza che vengano richieste le credenziali.

INSTALLAZIONE E CONFIGURAZIONE DI KEEPALIVED

Keepalived è il servizio che si occupa di gestire il VIP, in modo che esso venga automaticamente preso in carico dal nodo secondario in caso di fallimento del primario.
Il VIP non è altro che un IP condiviso tra i due servers su cui HAProxy si mette in ascolto per ricevere le richieste destinate al servizio bastione.

Installare il pacchetto necessario eseguendo il seguente comando su una bash come root:

Il file /etc/keepalived/keepalived.conf è simile su entrambi i nodi, allo scopo dimostrativo viene utilizzato 192.168.1.100 come VIP e 45 come router ID, ma è possibile modificare entrambi i parametri a patto che essi non siano già utilizati da altri servizi.

Inoltre, è necessario scegliere una password che per motivi di compatibilità si consiglia che non debba superare gli 8 caratteri.

Aggiungre al file /etc/keepalived/keepalived.conf su entrambi i nodi la seguente configurazione:

Sostituire HOSTNAME-HERE con l’hostname dei servers e smtp.pizza.local con il server SMTP (smarthost) che si desidera utilizzare, inoltre popolare notification_email con le emails che devono ricevere gli alerts in caso di mal funzionamenti.

Se non si desidera ricevere notifiche via email è possibile escludere dalla configurazione le righe da (incluso) notification_email a (incluso) smtp_connect_timeout.

Sul server primario aggiungere al file /etc/keepalived/keepalived.conf la seguente configurazione:

Sul server secondario aggiungere al file /etc/keepalived/keepalived.conf la seguente configurazione:

Nelle precedenti configurazioni è necessario sostituire:

  • “eth0” con l’interfaccia sui cui i servers condividono il network layer L2 (l’interfaccia su cui entrambi hanno un IP sulla stessa subnet)
  • “45” con un numero inferiore a 255 (uguale per entrambi i nodi) che non viene utilizzato come “virtual_router_id” per altri VIP
  • “PASSWORD-HERE” con una password di lunghezza inferiore a 8 caratteri (uguale su entrambi i nodi)
  • “192.168.1.100/24” con il VIP e la relativa subnet, l’IP si consiglia che appartenga alla subnet dell’interfaccia specificata con la direttiva precedente

Ad esempio:

  • haproxy01: 192.168.1.11/24
  • haproxy02: 192.168.1.12/24
  • VIP: 192.168.1.100/24

Mediante vrrp_track_process e track_process viene specificato che il fallimento del servizio haproxy è sufficiente per effettuare il fallback sul server secondario, altrimenti sarebbe necessaria la sua disconnessione dalla rete.

Per abilitare ed avviare il servizio è possibile eseguire su entrambi i nodi il seguente comando:

Finchè il servizio “haproxy” non viene avviato è possibile che il VIP non sia detenuto da nessuno dei due membri del cluster, quando esso sarà disponibile dovrebbe essere possibile visualizzarlo sul server primario mediante il seguente comando:

Il VIP dovrebbe anche rispondere al ping, salvo configurazioni diverse sul firewall.

CONFIGURAZIONE CERTIFICATI SSL SU HAPROXY

Nel prossimo articolo di questa serie verranno mostrati i passaggi per la configurazione della CA per il rilascio dei certificati agli utenti, dalla stessa CA è necessario che venga rilasciato un certificato wildcard per il cluster HAProxy.

I passaggi per il rilascio di un certificato wildcard non verranno descritti nel dettaglio, se si utilizza la Enterprise CA di Microsoft è possibile clonare il template Web Server, selezionando nel tab Subject Name l’opzione Supply in the request, in modo analogo a come verrà mostrato per i certificati dei clients nel prossimo articolo.

Mediante il template clonato, oppure mediante OpenSSL, è necessario aggiungere alla SAN della richiesta il dominio o i domini con wildcard (ad esempio *.pizza.local), il certificato deve consentire Server Authentication tra i propri usi.

È importante utilizzare un certificato wildcard per far sì che la validazione lato client non fallisca quando ci si connette al bastione specificando l’FQDN di un server interno (il cui dominio deve appartenere alla SAN del certificato).

Se i servers appartengono a più domini è possibile eseguire la medesima procedura per importare più di un certificato SSL, oppure specificare più domini nella SAN dello stesso certificato.
I certificati devono essere tutti in formato PEM codificati in Base64, perciò se li si ha generati in formato DER, è necessario convertirli con OpenSSL.

Creare un unico file nella directory /etc/ssl/private con estensione .pem, strutturato come segue:

  1. Chiave privata
  2. Certificato HAProxy (wildcard)
  3. CA intermedia (se presente)
  4. CA root

Esempio:

Aggiustare i permessi:

I certificati della CA root e di eventuali CA intermedie sono necessari al fine di effettuare la configurazione di HAProxy ed è possibile salvarli in due files distinti nella directory /etc/ssl.
Nella configurazione proposta in seguito verranno utilizzati i files /etc/ssl/MyRootCA.crt e /etc/ssl/MyIntermediateCA.crt.

Si consiglia, inoltre, di importare il certificato della CA root tra quelle fidate, per farlo creare un file con estensione .crt nella directory /usr/local/share/ca-certificates con il contenuto della CA root.
In seguito un esempio:

Aggiornare i certificati fidati:

 

CONFIGURAZIONE DEI REPOSITORIES DI HAPROXY

Questo passaggio è opzionale, poichè Debian 13 mette a disposizione nei propri repositories stable una versione di HAProxy, tuttavia quest’ultima ha come major la 3.0 che non supporta gli attributi della SAN nelle ACL, perciò non è possibile utilizzare l’email per autorizzare gli utenti ad accedere a determinati servers.

Se ci si accontenta del CN e delle OU per la gestione dei permessi è possibile proseguire con l’installazione, altrimenti è necessario seguire i passaggi di questo paragrafo per configurare un repository aggiuntivo da cui è possibile scaricare i pacchetti delle versioni più recenti di HAProxy.

Navigare sul sito del repository (https://haproxy.debian.net/), selezionare il proprio sistema operativo e la versione di HAProxy che si vuole installare:

La versione 3.2-stable (LTS) è perfetta per lo scopo di questo articolo.

Copiare in una bash aperta come root i comandi di configurazione dei repositories:

Nel mio caso i comandi di configurazione dei repositories sono i seguenti:

Per ricaricare i repositories eseguire il seguente comando:

È possibile installare la nuova versione anche se è presente una versione meno recente, poichè viene gestita come un normale aggiornamento software mediante APT.

INSTALLAZIONE DI HAPROXY

Procedere all’installazione di HAProxy su entrambi i servers, eseguendo su una bash come root il seguente comando:

Se si vuole installare la versione più recente facendo utilizzo dei repositories aggiuntivi, eseguire al posto del precedente comando il seguente (sostituire 3.2 con la versione per la quale si ha configurato i repositories):

Per abilitare ed avviare il servizio è possibile eseguire su entrambi i nodi il seguente comando:

La configurazione di HAProxy può essere ricca di direttive, perciò verranno descritte solo le parti principali.

Tutte le configurazioni sono contenute nel file /etc/haproxy/haproxy.cfg salvo che venga specificato diversamente.

Aggiungere le opzioni necessarie per il funzionamento degli script LUA sotto la direttiva global:

Se si utilizza la versione di HAProxy distribuita con i repositories di Debian commentare la direttiva tune.lua.bool-sample-conversion normal.

Affinché sia possibile utilizzare la risoluzione dei nomi DNS per collegarsi specificando l’FQDN e non l’IP è necessario configurare un resolver:

Sostituire 192.168.10.30 e 192.168.10.31 con gli IP dei server DNS che si desidera utilizzare.

Opzionalmente è possibile abilitare la pagina delle statistiche:

Nella precedente configurazione sostituire:

  • 9000 con la porta che si desidera utilizzare per la pagina delle statistiche
  • eth0 con l’interfaccia da cui si vuole raggiungere la pagina delle statistiche
  • USERNAME-HERE:PASSWORD-HERE con le credenziali che si vogliono utilizzare (formato username:password)

Se non si desidera utilizzare HTTPS per la connessione alla pagina delle statistiche è possibile omettere le seguenti direttive:

Aggiungere il frontend dedicato al bastione SSH:

La direttiva bind è composta dalle seguenti opzioni:

  • 192.168.1.100: il VIP configurato con Keepalived
  • ssl: abilita il TLS lato HAProxy
  • strict-sni: richiede che l’utente debba specificare uno SNI per il quale HAProxy detiene un certificato SSL valido, rifiutando le connessioni con SNI malformato, come ad esempio quelle effettuate dai bots e dai crawlers
  • verify required: abilita il mutual TLS
  • ca-file /etc/ssl/MyIntermediateCA.crt: direttiva utilizzata per specificare con che CA HAProxy deve validare il certificato del client (sostituire il percorso con il path in cui è stata salvata la CA intermedia, se esiste, oppure in cui è stata salvata la CA root)
  • ca-verify-file /etc/ssl/MyRootCA.crt: direttiva opzionale utilizzata per suggerire al client che certificato utilizzare (sostituire il percorso con il path in cui è stata salvata la CA root)

L’opzione option logasap serve a richiedere ad HAProxy di loggare la richiesta appena ricevuta e non quando la connessione SSH viene terminata.

In seguito, vengono abilitati i keepalives per i clients e vengono specificati i timeouts che possono essere modificati a piacere.

L’utilizzo di keepalives è fondamentale in ambienti in cui sono presenti apparati di rete stateful tra il client ed HAProxy, come per esempio i firewalls, oppure i proxy ZTNA.

Con l’opzione log-format viene specificato il formato dei logs, facendo sì che vengano registrate anche la destinazione specificata mediante lo SNI e le informazioni ottenute dai certificato SSL del client.

Nelle due istruzioni tcp-request vengono impostate due variabili di sessione con rispettivamente l’IP, risolto dal DNS se necessario, ed il nome del server di destinazione.

Con l’istrzione tcp-request successiva viene salvata in una variabile della transazione la lista di emails estratta dalla SAN mediante lo script (converter) LUA get_emails_from_san, questa riga deve essere commentata se si uttilizza la versione di HAProxy distribuita dai repositories di Debian.

Le direttive sotto il commento Drop invalid SSH connections servono a consentire solo il traffico SSH per evitare che venga instradato un altro protocollo.

Infine, la direttiva default_backend be_ssh_all indirizza le richieste verso il backend del bastione, dove successivamente verranno verificate le ACL ed avverrà la connessione con il server di destinazione.

Aggiungere le configurazione del backend:

La configurazione del backend incomicia specificando la modalità tcp ed i timeouts, poi analogamente a come sono stati abilitati nel frontend i keepalives verso il clients, vengono abilitati i keepalives verso i servers.

L’instruzione tcp-request content reject viene utilizzata per rifiutare le richieste il cui IP di destinazione non è definito, ad esempio quando viene richiesto un FQDN non presente sul DNS.

Successivamente vengono eseguiti gli scripts (actions) LUA di validazione delle ACL e poi mediante le tre direttive acl authorized viene effettuato un OR logico tra le variabili di sessione in cui gli script salvano il risultato della validazione.

Le richieste non autorizzate vengono respinte con l’istruzione tcp-request content reject successiva ed infine viene impostata la destinazione e la richiesta viene girata al server richiesto.

Creare la cartella per gli scripts LUA eseguendo:

Creare il file /etc/haproxy/lua/acl_cache.lua con il seguente contenuto:

Creare il file /etc/haproxy/lua/actions.lua con il seguente contenuto:

Lo script acl_cache viene utilizzato per caricare le ACL in memoria in fase di caricamento, per evitare inefficenti letture dal file system durante il runtime.

Nello script actions vengono definite le funzioni per la validazione delle ACL che vengono richiamate nella configurazione di HAProxy.

Nello script converters è definita la funzione get_emails_from_san per estrarre le emails dalla SAN, anch’essa richiamata nella configurazione di HAProxy.

Infine, nello script utils sono presenti alcune funzioni utili agli altri scripts.

Su entrambi i servers creare la directory per le ACL ed i files vuoti:

Per verificare la configurazione eseguire:

Per installare rsync, che necessario per la replica della configurazione, eseguire su entrambi i nodi:

Per replicare la configurazione eseguire (sostituire DESTINATION con l’hostname o l’IP del server su cui si vuole copiare la configurazione):

Per applicare localmente la configurazione eseguire:

Se vengono modificate le variabili d’ambiente è necessario riavviare HAProxy eseguendo:

 

CONFIGURAZIONE DELLE ACL

Mediante le ACL salvate nei files specificati con le variabili d’ambiente ACL_CN_PATH, ACL_EMAIL_PATH e ACL_OU_PATH gli utenti vengono autorizzati ad accedere ai servers.

Tutti i files seguono la seguente sintassi:

ATTRIBUTO: RISORSA

Esempio per CN: VALLE Marco:mylocalserver.pizza.local

Esempio per EMAIL: [email protected]:mylocalserver.pizza.local

Esempio per OU: 01-LAB:mylocalserver.pizza.local e 01-LAB:192.168.1.88

Per applicare le ACL è necessario ricaricare HAProxy:

Dopo averle applicate sul nodo secondario, replicare la configurazione sul primario ed applicarla.

ATTENZIONE:
Per come funziona la logica di validazione delle ACL definita negli scripts, due OU presenti in posti diversi dell’alberatura di Active Directory, se omonime, vengono valutate nello stesso modo.
Per questo motivo un utente con accesso in scrittura su almeno una posizione dell’alberatura, potrebbe creare una OU chiamata come una uilizzata per abilitare gli utenti al bastione, abusando dei suoi permessi.
Potenzialmente si potrebbero modificare gli script per concatenare le OU e garantire una validazione più stringente delle ACL.

CONFIGURAZIONE OPZIONALE DELLA LANDING PAGE

Nonostante HAProxy non sia un web server, è possibile distribuire delle pagine HTML statiche sui frontends di tipo HTTP.
Questa configurazione può risultare utile per creare una landing page in cui viene spiegato come utillizare il bastione.

Aggiungere il seguente frontend:

Sostituire ssh.pizza.com con l’FQDN che si desidera utilizzare.

Se non si vuole rendere obbligatoria l’autenticazione per questa pagina mediante mTLS omettere la direttiva verify required.

Creare la directory con i files statici:

Aggiungere il file /etc/haproxy/static/favicon.ico con la favicon ed il file /etc/haproxy/static/landing_page.html con la pagina HTML.

Replicare la configurazione ed i files statici su entrambi i servers e ricaricare la configurazione:

 

Articoli Recenti

Veeam Backup

Monitoring

Friends

  • My English Lab  English School
  • ChrSystem   Servizi ICT
  • Since 01  Kreative Graphics

Database

Networking

Autori

  • Raffaele Chiatto  Amministratore
  • Marco Valle  Autore
  • Angelo Lauria  Autore
  • Edoardo Prot  Autore
  • Davide D’Urso  Autore
Marco Valle

Marco Valle

Mi chiamo Marco Valle e da sempre sono appassionato di Cybersicurezza e Linux. Per lavoro implemento soluzioni open source.

Related Post

0 commenti

Invia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Virtualizzazione

Linux

Microsoft

Apple

Backup

Database

Security

Automazione