In ufficio abbiamo un domino Internet locale e varie macchine con alcune applicazioni web che operano in maniera federata, vale a dire che quando ci si collega alla prima si viene rimandati ad un’altra per l’autenticazione e comincia un rimpallo tra le varie macchine (sempre tramite http redirect, cioè tramite il browser sul PC client) finché non si supera sia l’autenticazione che l’autorizzazione. Questa modalità di autenticazione è chiamata federativa o anche «per attestazioni», poiché in una applicazione ci si fida di un server di autenticazione, il quale può essere federato con altri tra i quali è stabilita la fiducia. L’idea è che si arrivi ad autenticare l’utente in maniera automatica, tramite il single sign on, vale a dire che l’utente viene riconosciuto perché ha già fatto il login nel suo sistema operativo e non deve rifarlo per ogni applicazione. Il protocollo utilizzato per scambiare informazioni tra i vari siti implicati è quello SAML, mentre, per fare un po’ di nomi, le tecnologie coinvolte sono la fedlet di Java, la AD FS di Microsoft e altre meno conosciute.
Facciamo l’esempio dell’ufficio con tutte le macchine nel dominio ufficio.local. Avremo quindi dei nomi di macchine fisiche come vm1.ufficio.local o vm2.ufficio.local, e CNAME per le applicazioni, come adfs.ufficio.local e app1.ufficio.local. Le applicazioni sono tutte web, ma utilizzano le porte più disparate, la 443, 8443, la 9653 ed altre ancora, tutte rigorosamente cifrate tramite SSL con certificati emessi dalla ca.ufficio.local.
Il problema è: voglio permettere l’accesso da fuori dell’ufficio protetto dal firewall, senza utilizzare nessuna VPN che dia accesso a tutta la rete interna o che richieda di configurare il firewall in maniera potenzialmente errata.
La soluzione è stata la seguente:
-
configurare il primo firewall per inoltrare tutte le porte delle varie applicazioni web al secondo firewall,
-
configurare il secondo firewall in modo che inoltri tutte le porte delle varie applicazioni ad una sola porta di una macchina proxy sulla quale è configurato pound,
-
configurare pound perché inoltri le varie richieste alla macchina corretta nella LAN.
pound è un proxy HTTP, vale a dire che si mette in ascolto su una porta e, tramite protocollo HTTP, riceve le richieste che poi smista in base a regole sulle intestazioni della richiesta HTTP. pound è in grado di mettersi in ascolto su una porta SSL e di comunicare con il server effettivo, sempre via SSL.
Perché il certificato SSL di pound sia riconosciuto e accettato dai browser per tutti i nomi delle varie macchine, ci sono alcune strade:
-
la prima è avere un certificato per ogni macchina (in questo caso pound usa l’estensione SNI (sigla che sta per Server Name Indication: suggerimento sul nome del server) del protocollo TLS (l’attuale estensione di SSL) per capire quale servername è richiesto dal client),
-
la seconda è avere un certificato che corrisponde a tanti nomi (in questo caso di utilizza l’estensione subjectAlternativeNames del certificato),
-
la terza è avere un certificato che vale per tutto il dominio.
Utilizzo la seconda possibilità e genero un certificato e una richiesta di firma (CSR: Certificate Sign Request) usando lo strumento keytool di java. Nota: questo strumento non crea automaticamente la CSR con tutti i subjectAlternativeNames, ma li si deve specificare sia per la creazione delle chiavi iniziali, sia per la creazione della CSR.
Userò pound.ufficio.local che è il nome della macchina sulla quale ho messo pound, xi12.ufficio.local che è una delle applicazioni, erpln.ufficio.local è la seconda applicazione, adfs.ufficio.local è la terza.
keytool -genkeypair -alias pound -keyalg RSA -keysize 2048 \ -dname "CN=pound.ufficio.local, OU=demo, O=ufficio, L=Torino, C=IT" \ -ext SAN=dns:pound.ufficio.local,dns:xi12.ufficio.local,\ dns:erpln.ufficio.local,dns:adfs.ufficio.local \ -validity 3650 -keypass 'password' -keystore pound.pfx \ -storepass 'password' -storetype PKCS12 keytool -certreq -alias pound -file pound.csr \ -ext SAN=dns:pound.ufficio.local,dns:xi12.ufficio.local,\ dns:erpln.ufficio.local,dns:adfs.ufficio.local \ -keypass 'password' -keystore pound.pfx -storepass 'password' \ -storetype PKCS12
A questo punto prendo il file pound.csr, lo porto alla mia autorità di certificazione, la quale restituisce il certificato pound.cer.
Poiché pound vuole un solo file con la chiave privata e con il certificato, tutto in formato PEM, estraggo la chiave privata da file PFX iniziale e le tolgo la password di protezione, poi creo il file completo per pound:
openssl pkcs12 -in pound.pfx -nocerts -out pound.pw.key # sempre con password openssl rsa -in pound.pw.key -out pound.nopw.key # senza password cat pound.cer pound.nopw.key > ssl.pem rm pound.pfx pound.csr pound.cer pound.nopw.key pound.pw.key sudo mv ssl.pem /etc/pound/ssl.pem sudo chown root:root /etc/pound/ssl.pem sudo chmod go-rwx /etc/pound/ssl.pem
Infine creo il file di configurazione per pound, /etc/pound/pound.cfg:
ListenHTTPS Address 192.168.245.99 Port 8442 Cert "/etc/pound/ssl.pem" LogLevel 5 ## allow PUT and DELETE also (by default only GET, POST and HEAD)?: xHTTP 1 Service IgnoreCase 1 URL ".*" HeadRequire "Host:.*xi12.ufficio.local:9543.*" BackEnd Address xi12.ufficio.local Port 9543 HTTPS End End Service IgnoreCase 1 URL "^/(bundles/|Scripts/|infor|api/|template/|Content/|CollaborationUI/|webresource/|user/|IONAPIUI/).*" HeadRequire "Host:.*xi12.ufficio.local.*" BackEnd Address xi12.ufficio.local Port 8443 HTTPS End End Service IgnoreCase 1 URL "^/lnui/.*" HeadRequire "Host:.*erpln.ufficio.local.*" BackEnd Address erpln.ufficio.local Port 8443 HTTPS End End Service IgnoreCase 1 URL "^/adfs.*" HeadRequire "Host:.*adfs.ufficio.local.*" BackEnd Address adfs.ufficio.local Port 443 HTTPS End End End
Ora si può avviare pound.
Come punto finale, per potersi collegare dall’esterno, si deve inserire nel proprio file /etc/hosts una riga con l’ip pubblico dell’ufficio (quello associato al firewall esterno) e tutti i nomi delle macchine e applicazioni alle quali si deve accedere.
Una volta fatta la prova, si vede che questa configurazione non funziona. Il problema che ho riscontrato è che il server adfs.ufficio.local utilizza a sua volta la SNI, ma pound non imposta l’estensione servername di openssl e quindi la SNI non funziona. A questo punto ho cercato la soluzione sul web e ho trovato che il problema è già stato sollevato da un’altra persona, alla quale è stata fornita una patch non ancora inserita nel codice di pound. La patch però funziona: difatti l’ho scaricata, poi ho fatto le modifiche suggerite nella pagina in questione, ho ricompilato il pacchetto Debian e l’ho installato e provato. Funziona. La patch è in questo thread.