<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>psk &amp;mdash; Cyberdyne Systems</title>
    <link>https://noblogo.org/aytin/tag:psk</link>
    <description>&#34;Fare o non fare. Non c&#39;è provare!&#34;</description>
    <pubDate>Thu, 30 Apr 2026 10:15:39 +0000</pubDate>
    <item>
      <title>Script per la gestione della configurazione di una vpn wireguard</title>
      <link>https://noblogo.org/aytin/script-per-la-gestione-della-configurazione-di-una-vpn-wireguard</link>
      <description>&lt;![CDATA[vpn&#xA;&#xA;Cos&#39;è wireguard e come si configura, lo sappiamo ma mi serviva qualcosa che mi permettesse di fare provisioning e deprovisioning dei certificati in maniera più semplice di quanto già si faccia con i tool disponibili nella userland, wg e wg-quick.&#xA;&#xA;E questo è il motivo principale per cui è nato questo script.&#xA;!--more--&#xA;Prende come riferimento una configurazione road warrior, il primo scenario di una topologia point-to-site, quella più comune.&#xA;&#xA;Alcune considerazioni&#xA;Lo script definisce una workdir dove deposita tutte le configurazioni e i certificati.&#xA;Le precondizioni sono legate alla presenza dei tool userland wg-tools (ovviamente) e di ufw. Vengono comunque verificate nello script.&#xA;&#xA;Altra semplificazione è data dal fatto di allocare una /24 come rete wireguard. 254 host per una rete domestica sono più che sufficienti.&#xA;&#xA;L&#39;allocazione degli ip viene fatta con un progressivo memorizzato nel file &#39;ip\renew&#39;. Gli ip dei certificati revocati vengono mantenuti in un file, &#39;ip\release&#39;.&#xA;Quando si crea un nuovo certificato, si controlla prima che ci sia un ip da recuperare in ip\release. Se la lista è vuota si ricorre al progressivo.&#xA;&#xA;La creazione della configurazione lato server passa da due file di configurazione: una configurazione globale ottenuta tracciando l&#39;evoluzione iniziale in termini di aggiunta o rimozione dei client peer e destinata al rilascio in esecuzione. L&#39;altra contenente la sola configurazione del server e usata unicamente per la rigenerazione della configurazione globale a partire dai peer esistenti.&#xA;&#xA;L&#39;operazione di init è propedeutica per addclient, removeclient, rebuild, deploy, share.&#xA;&#xA;Le operazioni a disposizione sono:&#xA;&#xA;init: inizializza la configurazione di un server wireguard&#xA;addclient: crea il certificato lato client e aggiunge il relativo peer sulla configurazione del server&#xA;removeclient: cancella il certificato lato client e rimuove il relativo peer sulla configurazione del server&#xA;rebuild: rigenera la configurazione del server usando i certificati client esistenti&#xA;deploy: finalizza la configurazione riavviando il servizio con le nuove impostazioni&#xA;share: crea i qr-code per i certificati client da utilizzare nelle configurazioni&#xA;&#xA;Per tutto il resto, i commenti nel codice sono abbastanza esplicativi.&#xA;Lo script&#xA;!/bin/bash&#xA;&#xA;Questo è il file di configurazione globale, i dati sono fittizi.&#xA;Può essere mantenuto nello script o nella home dell&#39;utente &#xA;(es. $HOME/.config/wgman.conf) e importato &#xA;con &#39;source&#39; all&#39;inizio.&#xA;WGINTERFACE=wg0&#xA;PHYSICALINTERFACE=eth0&#xA;NETWORK=&#34;192.168.15.0&#34;&#xA;SUBNETMASK=&#34;24&#34;&#xA;SERVERIPADDRESS=&#34;192.168.15.1&#34;&#xA;DNS=&#34;1.1.1.1&#34;&#xA;LISTENPORT=&#34;51820&#34;&#xA;ENDPOINT=wireguard.nodns.net:51820&#34;&#xA;WORKDIR=&#34;$HOME/wireguard&#34;&#xA;&#xA;checkdependency() {&#xA;    if test -e /usr/sbin/ufw; then&#xA;        if test -e /usr/bin/wg; then&#xA;            return 0&#xA;        else&#xA;            return 2&#xA;        fi&#xA;    else&#xA;        return 1&#xA;    fi&#xA;}&#xA;&#xA;isinit() {&#xA;    test -e ${WORKDIR}/conf.d/serverwg.conf &amp;&amp; return 0 || return 1&#xA;}&#xA;&#xA;Genera la chiave privata&#xA;genprivkey() {&#xA;    wg genkey | tee ${WORKDIR}/keys/$1privkey&#xA;}&#xA;&#xA;Genera la pre-shared key&#xA;genclientpsk() {&#xA;    # Evita il warning sui permessi del file che devono essere 600&#xA;    umask 077&#xA;    wg genpsk | tee ${WORKDIR}/psk/$1psk&#xA;}&#xA;&#xA;Rilascio di un nuovo indirizzo ip. Questa funziona viene invocata da&#xA;addclient().&#xA;&#xA;I primi 3 ottetti li ottengo dalla variabile globale NETWORK.&#xA;L&#39;ultimo ottetto, relativo all&#39;host, lo ricavo dalla lista degli ip&#xA;riutilizzabili (&#34;iprelease&#34;).&#xA;&#xA;Se non è vuota, prelevo il primo e lo rimuovo dalla lista. Se è vuota,&#xA;prelevo l&#39;ultimo ottetto da &#34;iprenew&#34; e lo incremento per il successivo&#xA;assegnamento.&#xA;iprenew() {&#xA;    # Selezioni i primi 3 ottetti del network&#xA;    SUBIP=$(echo ${NETWORK}|awk -F &#34;.&#34; &#39;{print $1&#34;.&#34;$2&#34;.&#34;$3}&#39;)&#xA;&#xA;    if [[ ! -e ${WORKDIR}/conf.d/iprelease || ! -s ${WORKDIR}/conf.d/iprelease ]]; then&#xA;        # Genero il nuovo ip (Incremento di 1 l&#39;ultimo ottetto)&#xA;        IP=$(cat ${WORKDIR}/conf.d/iprenew)&#xA;        echo $((++IP))   ${WORKDIR}/conf.d/iprenew&#xA;&#xA;        # Restituisco i 3 ottetti + il quarto&#xA;        #echo -n ${SUBIP};cat ${WORKDIR}/conf.d/iprenew&#xA;    else&#xA;        IP=$(head -n 1 ${WORKDIR}/conf.d/iprelease)&#xA;        sed -i &#34;1d&#34; ${WORKDIR}/conf.d/iprelease&#xA;    fi&#xA;    echo -n ${SUBIP}&#34;.&#34;${IP}&#xA;}&#xA;&#xA;Riallocazione di un indirizzo ip. Questa funzione viene invocata da&#xA;removeclient().&#xA;Aggiungo l&#39;ultimo ottetto alla lista degli ip riallocabili.&#xA;@par 1: ultimo ottetto.&#xA;iprelease() {&#xA;    echo $1|cut -d&#34;.&#34; -f 4     ${WORKDIR}/conf.d/iprelease&#xA;}&#xA;&#xA;Aggiunge il nuovo peer al file di configurazione del server&#xA;@par 1: CLIENTPUBLICKEY&#xA;@par 2: CLIENTPSK&#xA;@par 3: CLIENTIPADDRESS&#xA;@par 4: CLIENTNAME&#xA;addpeertoserver() {&#xA;    cat     ${WORKDIR}/conf.d/serverwg.conf &lt;&lt; EOF&#xA;$4&#xA;[Peer]&#xA;PublicKey = $1&#xA;PresharedKey = $2&#xA;AllowedIPs = $3/32&#xA;PersistentKeepalive = 25&#xA;&#xA;EOF&#xA;}&#xA;&#xA;Inizializza la configurazione del server wireguard.&#xA;&#xA;Questa operazione può essere fatta una sola volta a meno che non si&#xA;cancelli tutta la workdir.&#xA;&#xA;Verranno creati due file  di configurazione: serverwg.conf e &#xA;serverwgraw.conf&#xA;&#xA;Il primo conterrà la configurazione completa del server e dei peer,&#xA;verrà aggiornato ad ogni modifica dei client (aggiunta o rimozione) e&#xA;verrà usato per il deploy della configurazione.&#xA;&#xA;Il secondo conterrà la configurazione del solo server e verrà usato&#xA;solo per rigenerare il primo file di configurazione.&#xA;init() {&#xA;    # Controllo che wireguard sia almeno abilitato&#xA;    echo -n &#34;Inserire la password di Amministratore: &#34;; read -s PASSWORD&#xA;    sudo -k&#xA;    if echo $PASSWORD|sudo -S echo &#34;got a root&#34;   /dev/null; then&#xA;        if ! sudo systemctl is-enabled --quiet wg-quick@${WGINTERFACE}; then&#xA;            echo -en &#34;\nAttivazione servizio wireguard... &#34;&#xA;            #sudo systemctl enable --quiet wg-quick@${WGINTERFACE}&#xA;            echo &#34;fatto.&#34;&#xA;        fi&#xA;        sudo -k &#xA;        &#xA;        #Verifico che queste cartelle esistano. Se lo sono, non faccio nulla, se no le creo.&#xA;        echo -n &#34;Creazione workdir... &#34;&#xA;        [[ ! -e ${WORKDIR}/conf.d || ! -e ${WORKDIR}/psk  || ! -e ${WORKDIR}/keys ]] \&#xA;            &amp;&amp; { mkdir -p ${WORKDIR}/{conf.d,keys,psk}; } \&#xA;            || { echo &#34;inizializzazione già effettuata.&#34;; exit; }&#xA;        echo &#34;fatto.&#34;&#xA;        &#xA;        # Genero la chiave privata per il server&#xA;        echo -n &#34;Creazione chiave private del server...&#34;&#xA;        SERVERPRIVKEY=$(genprivkey &#34;serverwg&#34;)&#xA;        echo &#34;fatto.&#34;&#xA;&#xA;        # Genero il file di configurazione&#xA;        echo -n &#34;Inizializzazione del server... &#34;&#xA;        cat   ${WORKDIR}/conf.d/serverwg.conf &lt;&lt; EOF&#xA;[Interface]&#xA;Address = ${SERVERIPADDRESS}/${SUBNETMASK}&#xA;SaveConfig = true&#xA;&#xA;PreUp = ufw route allow in on ${WGINTERFACE} out on ${PHYSICALINTERFACE} log from ${NETWORK}/${SUBNETMASK} to 0.0.0.0/0&#xA;PostDown = ufw route delete allow in on ${WGINTERFACE} out on ${PHYSICALINTERFACE} log from ${NETWORK}/${SUBNETMASK} to 0.0.0.0/0&#xA;&#xA;IP masquerading&#xA;PreUp = iptables -t nat -A POSTROUTING -o ${PHYSICALINTERFACE} -s ${NETWORK}/${SUBNETMASK} -j MASQUERADE&#xA;PostDown = iptables -t nat -D POSTROUTING -o ${PHYSICALINTERFACE} -s ${NETWORK}/${SUBNETMASK} -j MASQUERADE&#xA;&#xA;IP filtering&#xA;PreUp = ufw allow in on ${PHYSICALINTERFACE} log to 0.0.0.0/0 app Wireguard&#xA;PostDown = ufw delete allow in on ${PHYSICALINTERFACE} log to 0.0.0.0/0 app Wireguard&#xA;&#xA;ListenPort = ${LISTENPORT}&#xA;PrivateKey = ${SERVERPRIVKEY}&#xA;&#xA;EOF&#xA;        echo &#34;fatto.&#34;&#xA;        cp ${WORKDIR}/conf.d/serverwg.conf ${WORKDIR}/conf.d/serverwgraw.conf&#xA;        # Inizializza l&#39;erogatore di ip&#xA;        echo 1   ${WORKDIR}/conf.d/iprenew&#xA;    else&#xA;        echo &#34;Sono necessarie le credenziali di amministrazione per eseguire questo comando.&#34;&#xA;        exit 1&#xA;    fi&#xA;}&#xA;&#xA;Genera un certificato per il client composto da:&#xA;chiave privata del client&#xA;chiave pre-condivisa&#xA;client ip&#xA;chiave pubblica del server&#xA;nome simbolico del client&#xA;&#xA;Dopo la creazione e il salvataggio in WORKDIR/conf.d, verrà aggiunto&#xA;il relativo peer nella configurazione del server (serverwg.conf).&#xA;@par1 @par2 @par3...: lista di nomi relativi ai certificati da creare.&#xA;addclient() {&#xA;    if isinit; then&#xA;        # Se non c&#39;è alcun input, esco.&#xA;        if [[ $# -lt 1 ]]; then&#xA;            echo -e &#34;Devi inserire almeno un nome.&#34;&#xA;            exit 1&#xA;        else&#xA;            # Per ogni nome presente in input, creo una configurazione &#xA;            # client e l&#39;aggiungo alla configurazione del server.&#xA;            for CLIENTNAME in &#34;$@&#34;; do&#xA;                echo -n &#34;Creazione certificato per il client \&#34;${CLIENTNAME}\&#34;... &#34;&#xA;                &#xA;                # Controllo se la configurazione esista già discriminando&#xA;                # in base al nome del file.&#xA;                if [[ -e ${WORKDIR}/conf.d/client${CLIENTNAME}.conf ]]; then&#xA;                    echo &#34;già esistente.&#34;&#xA;                else&#xA;                    # Creo la configurazione del client&#xA;                    CLIENTPRIVKEY=$(genprivkey ${CLIENTNAME})&#xA;                    CLIENTPUBLICKEY=$(echo ${CLIENTPRIVKEY} | wg pubkey)&#xA;                    CLIENTPSK=$(genclientpsk ${CLIENTNAME})&#xA;                    CLIENTIPADDRESS=$(iprenew)&#xA;                    SERVERPUBLICKEY=$(grep PrivateKey ${WORKDIR}/conf.d/serverwg.conf | cut -d &#34; &#34; -f 3 | tr -d &#34; &#34; | wg pubkey)&#xA;                    CLIENTNAMEUPPER=$(echo ${CLIENTNAME} | tr &#39;[:lower:]&#39; &#39;[:upper:]&#39;)&#xA;                    cat   ${WORKDIR}/conf.d/client${CLIENTNAME}.conf &lt;&lt; EOF&#xA;    # ${CLIENTNAMEUPPER}&#xA;    [Interface]&#xA;    Address = ${CLIENTIPADDRESS}/${SUBNETMASK}&#xA;    DNS = ${DNS}&#xA;    PrivateKey = ${CLIENTPRIVKEY}&#xA;&#xA;    [Peer]&#xA;    PublicKey = ${SERVERPUBLICKEY}&#xA;    PresharedKey = ${CLIENTPSK}&#xA;    AllowedIPs = 0.0.0.0/0&#xA;    Endpoint = ${ENDPOINT}&#xA;    PersistentKeepalive = 25&#xA;EOF&#xA;                    echo &#34;fatto.&#34;&#xA;                    echo -n &#34;Aggiunta peer \&#34;${CLIENTNAME}\&#34; al file di configurazione del server... &#34;&#xA;                    &#xA;                    # Aggiungo il peer alla configurazione del server.&#xA;                    addpeertoserver ${CLIENTPUBLICKEY} ${CLIENTPSK} ${CLIENTIPADDRESS} ${CLIENTNAMEUPPER}&#xA;                    echo -e &#34;fatto.\n&#34;                &#xA;                fi&#xA;            done&#xA;        fi&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;Rimuove file di configurazioni, chiavi e pre-shared key realtive a file&#xA;dati in input.&#xA;Rimuove inoltre il peer dal file di configurazione serverwg.conf.&#xA;@par1 @par2 @par3...: lista di nomi relativi ai certificati da rimuovere.&#xA;removeclient() {&#xA;    if isinit; then&#xA;        if [[ $# -lt 1 ]]; then&#xA;            echo -e &#34;Devi inserire almeno un nome.&#34;&#xA;            exit 1&#xA;        else&#xA;            for CLIENTNAME in &#34;$@&#34;; do&#xA;                echo -n &#34;Rimozione client \&#34;${CLIENTNAME}\&#34;... &#34;&#xA;                if [[ ! -e ${WORKDIR}/conf.d/client${CLIENTNAME}.conf ]]; then&#xA;                    echo &#34;non esistente.&#34;&#xA;                else&#xA;                    # Estraggo l&#39;ultimo ottetto dell&#39;ip del client.&#xA;                    IP=$(grep &#34;Address&#34; ${WORKDIR}/conf.d/client${CLIENTNAME}.conf|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;|cut -d &#34;/&#34; -f 1)&#xA;                    &#xA;                    # Lo inserisco nella lista degli ip riallocabili.&#xA;                    iprelease ${IP}&#xA;                    &#xA;                    # Cancello file di configurazione, chiave e psk del client.&#xA;                    rm ${WORKDIR}/conf.d/client${CLIENTNAME}.conf ${WORKDIR}/keys/${CLIENTNAME}privkey ${WORKDIR}/psk/${CLIENTNAME}psk&#xA;                    echo &#34;terminata con successo.&#34;&#xA;                    echo -n &#34;Rimozione peer \&#34;${CLIENTNAME}\&#34; dal file di configurazione del server... &#34;&#xA;                    &#xA;                    # Rimuovo il peer dalla configurazione del server.&#xA;                    CLIENTNAMEUPPER=$(echo ${CLIENTNAME} | tr &#39;[:lower:]&#39; &#39;[:upper:]&#39;)&#xA;                    sed -i &#34;/# ${CLIENTNAMEUPPER}/,+6d&#34; ${WORKDIR}/conf.d/serverwg.conf&#xA;                    echo -e &#34;terminata con successo.\n&#34;   &#xA;                fi&#xA;            done&#xA;        fi&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;rebuild() {&#xA;    if isinit; then&#xA;        # Rigenero il file di configurazione del server da serverwgraw.conf.&#xA;        echo -n &#34;Ripristino del file di configurazione del server... &#34;&#xA;        cat ${WORKDIR}/conf.d/serverwgraw.conf   ${WORKDIR}/conf.d/serverwg.conf&#xA;        echo &#34;fatto.&#34;&#xA;        &#xA;        # Per ogni file di configurazione client, aggiungo il relativo peer&#xA;        # nel file di configurazione serverwg.conf.&#xA;        for FILECONF in ${WORKDIR}/conf.d/client.conf; do&#xA;            CLIENTPUBLICKEY=$(grep &#34;PrivateKey&#34; ${FILECONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34; | wg pubkey)&#xA;            CLIENTPSK=$(grep &#34;PresharedKey&#34; ${FILECONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;)&#xA;            CLIENTIPADDRESS=$(grep &#34;Address&#34; ${FILECONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;|cut -d &#34;/&#34; -f 1)&#xA;            CLIENTNAMEUPPER=$(grep &#34;#&#34; ${FILECONF} | cut -d &#34; &#34; -f 2)&#xA;            echo -n &#34;Aggiunta peer \&#34;$(echo ${CLIENTNAMEUPPER} | tr &#39;[:upper:]&#39; &#39;[:lower:]&#39;)\&#34;... &#34;&#xA;            addpeertoserver ${CLIENTPUBLICKEY} ${CLIENTPSK} ${CLIENTIPADDRESS} ${CLIENTNAMEUPPER}&#xA;            echo -e &#34;fatto.&#34;&#xA;        done&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;Avvia il server wireguard con la nuova configurazione&#xA;deploy() {&#xA;    if isinit; then&#xA;        echo -n &#34;Inserire la password di Amministratore: &#34;; read -s PASSWORD&#xA;        sudo -k&#xA;        if echo $PASSWORD|sudo -S echo &#34;got a root&#34;   /dev/null; then&#xA;   &#xA;            # Stoppo il servizio wireguard&#xA;            echo -ne &#34;\nStop wireguard... &#34;&#xA;            sudo systemctl stop wg-quick@${WGINTERFACE}&#xA;            echo &#34;fatto.&#34;&#xA;            &#xA;            # Aggiorno la configurazione&#xA;            echo -n &#34;Copia della nuova configurazione... &#34;&#xA;            sudo cp ${WORKDIR}/conf.d/serverwg.conf /etc/wireguard/${WGINTERFACE}&#xA;            echo &#34;fatto.&#34;&#xA;            &#xA;            # Riavvio il servizio wireguard&#xA;            echo -n &#34;Riavvio wireguard... &#34;&#xA;            sudo systemctl start wg-quick@${WGINTERFACE}&#xA;            echo &#34;fatto.&#34;&#xA;            &#xA;            # Revoco i privilegi di amministrazione&#xA;            sudo -k&#xA;        else&#xA;            echo &#34;Sono necessarie le credenziali di amministrazione per eseguire questo comando.&#34;&#xA;            exit 1&#xA;        fi&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;Crea il qr-code della configurazione del client nella cartella corrente.&#xA;share() {&#xA;    if isinit; then&#xA;        if [[ $# -lt 1 ]]; then&#xA;            echo -e &#34;Devi inserire almeno un nome.&#34;&#xA;            exit 1&#xA;        else&#xA;            for CLIENTNAME in &#34;$@&#34;; do&#xA;                echo -n &#34;Creazione qr-code per il client \&#34;${CLIENTNAME}\&#34;... &#34;&#xA;                qrencode -r ${WORKDIR}/conf.d/client${CLIENTNAME}.conf -o qrcodeclient${CLIENTNAME}.jpg&#xA;                echo &#34;fatto.&#34;&#xA;            done&#xA;        fi&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;help() {&#xA;&#xA;[[ $1 != &#34;&#34; &amp;&amp; $1 != &#34;help&#34; ]] &amp;&amp; echo -e &#34;Comando inesistente.&#34;&#xA;&#xA;    cat&lt;&lt;EOF&#xA;Usa come: ./wgman.sh [command] ARG&#xA;dove:&#xA;    [command]&#xA;        init                     : Inizializza la configurazione del server.&#xA;        addclient lista nomi   : Aggiunge i client indicati in lista nomi.&#xA;        removeclient lista nomi: Rimuove i client indicati in lista nomi.&#xA;        rebuild                  : Ricostruisce il file di configurazione&#xA;                                   del server partendo dalle configurazioni&#xA;                                   di tutti i client registrati.&#xA;        deploy                   : Riavvia il server wireguard con l&#39;ultima&#xA;                                   configurazione disponibile.&#xA;        share lista nomi       : Genera i qr-code relativi ai client indicati in lista nomi.&#xA;        help                     : Stampa questa pagina di help.&#xA;&#xA;ESEMPI:&#xA;    INiZIALIZZA IL SERVER WIREGUARD&#xA;    wgman.sh init&#xA;&#xA;    AGGIUNGE I CLIENT &#39;macbookpro&#39;, &#39;mobile&#39;&#xA;    wgman.sh addclient macbookpro mobile&#xA;&#xA;    RIMUOVE I CLIENT &#39;iphoneluca&#39;, &#39;workstation&#39;&#xA;    wgman.sh removeclient iphoneluca workstation&#xA;&#xA;    RICOSTRUISCE LA CONFIGURAZIONE DEL SERVER WIREGUARD&#xA;    wgman.sh rebuild&#xA;    &#xA;    ATTIVA LA NUOVA CONFIGURAZIONE&#xA;    wgman.sh deploy&#xA;&#xA;    GENERA I QRCODE PER &#39;pcufficio&#39;, &#39;laptop&#39;&#xA;    wgman.sh share pcufficio laptop&#xA;EOF&#xA;}&#xA;&#xA;main() {&#xA;    case $1 in&#xA;        init         ) init ;;&#xA;        addclient    ) shift; addclient &#34;$@&#34; ;;&#xA;        removeclient ) shift; removeclient &#34;$@&#34; ;;&#xA;        rebuild      ) rebuild ;;&#xA;        deploy       ) deploy ;;&#xA;        share        ) shift; share &#34;$@&#34; ;;&#xA;        ) help ;;&#xA;    esac&#xA;}&#xA;&#xA;check_dependency&#xA;case $? in&#xA;    &#34;0&#34; ) main $* ;;&#xA;    &#34;1&#34; ) echo -e &#34;UFW non presente. Installare UFW.&#34;; exit 1 ;;&#xA;    &#34;2&#34; ) echo -e &#34;wireguard-tools non presenti. È necessario installarli.&#34;; exit 1 ;;&#xA;esac&#xA;&#xA;#bash #wireguard #psk #chiavi #certificati #crittografia&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/586f75268-5004eb/XBn3L6jB84Ka/b6zYDZWzIcLbax1taLgBnIQu8hoy7ZeZVlXBkGf0.png" alt="vpn"></p>

<p><a href="https://noblogo.org/aytin/vpn-con-wireguard-semplice-e-veloce" rel="nofollow">Cos&#39;è wireguard e come si configura</a>, lo sappiamo ma mi serviva qualcosa che mi permettesse di fare provisioning e deprovisioning dei certificati in maniera più semplice di quanto già si faccia con i tool disponibili nella userland, wg e wg-quick.</p>

<p>E questo è il motivo principale per cui è nato questo script.

Prende come riferimento una configurazione road warrior, <a href="https://noblogo.org/aytin/vpn-con-wireguard-semplice-e-veloce#primo-scenario" rel="nofollow">il primo scenario di una topologia point-to-site</a>, quella più comune.</p>

<h2 id="alcune-considerazioni">Alcune considerazioni</h2>
<ol><li><p>Lo script definisce una workdir dove deposita tutte le configurazioni e i certificati.
Le precondizioni sono legate alla presenza dei tool userland <strong>wg-tools</strong> (ovviamente) e di <strong>ufw</strong>. Vengono comunque verificate nello script.</p></li>

<li><p>Altra semplificazione è data dal fatto di allocare una /24 come rete wireguard. 254 host per una rete domestica sono più che sufficienti.</p></li>

<li><p>L&#39;allocazione degli ip viene fatta con un progressivo memorizzato nel file &#39;ip_renew&#39;. Gli ip dei certificati revocati vengono mantenuti in un file, &#39;ip_release&#39;.
Quando si crea un nuovo certificato, si controlla prima che ci sia un ip da recuperare in ip_release. Se la lista è vuota si ricorre al progressivo.</p></li>

<li><p>La creazione della configurazione lato server passa da due file di configurazione: una configurazione <strong>globale</strong> ottenuta tracciando l&#39;evoluzione iniziale in termini di aggiunta o rimozione dei client peer e destinata al rilascio in esecuzione. L&#39;altra contenente <strong>la sola configurazione del server</strong> e usata unicamente per la rigenerazione della configurazione globale a partire dai peer esistenti.</p></li>

<li><p>L&#39;operazione di <strong>init</strong> è propedeutica per <strong>addclient</strong>, <strong>removeclient</strong>, <strong>rebuild</strong>, <strong>deploy</strong>, <strong>share</strong>.</p></li></ol>

<p>Le operazioni a disposizione sono:</p>
<ul><li><strong>init:</strong> inizializza la configurazione di un server wireguard</li>
<li><strong>addclient:</strong> crea il certificato lato client e aggiunge il relativo peer sulla configurazione del server</li>
<li><strong>removeclient:</strong> cancella il certificato lato client e rimuove il relativo peer sulla configurazione del server</li>
<li><strong>rebuild:</strong> rigenera la configurazione del server usando i certificati client esistenti</li>
<li><strong>deploy:</strong> finalizza la configurazione riavviando il servizio con le nuove impostazioni</li>
<li><strong>share:</strong> crea i qr-code per i certificati client da utilizzare nelle configurazioni</li></ul>

<p>Per tutto il resto, i commenti nel codice sono abbastanza esplicativi.</p>

<h2 id="lo-script">Lo script</h2>

<pre><code class="language-bash">#!/bin/bash

# Questo è il file di configurazione globale, i dati sono fittizi.
# Può essere mantenuto nello script o nella home dell&#39;utente 
# (es. $HOME/.config/wg_man.conf) e importato 
# con &#39;source&#39; all&#39;inizio.
WG_INTERFACE=wg0
PHYSICAL_INTERFACE=eth0
NETWORK=&#34;192.168.15.0&#34;
SUBNET_MASK=&#34;24&#34;
SERVER_IP_ADDRESS=&#34;192.168.15.1&#34;
DNS=&#34;1.1.1.1&#34;
LISTEN_PORT=&#34;51820&#34;
ENDPOINT=wireguard.nodns.net:51820&#34;
WORKDIR=&#34;$HOME/wireguard&#34;



check_dependency() {
    if test -e /usr/sbin/ufw; then
        if test -e /usr/bin/wg; then
            return 0
        else
            return 2
        fi
    else
        return 1
    fi
}



is_init() {
    test -e ${WORKDIR}/conf.d/server_wg.conf &amp;&amp; return 0 || return 1
}



# Genera la chiave privata
gen_priv_key() {
    wg genkey | tee ${WORKDIR}/keys/$1_privkey
}



# Genera la pre-shared key
gen_client_psk() {
    # Evita il warning sui permessi del file che devono essere 600
    umask 077
    wg genpsk | tee ${WORKDIR}/psk/$1_psk
}



# Rilascio di un nuovo indirizzo ip. Questa funziona viene invocata da
# addclient().
#
# I primi 3 ottetti li ottengo dalla variabile globale NETWORK.
# L&#39;ultimo ottetto, relativo all&#39;host, lo ricavo dalla lista degli ip
# riutilizzabili (&#34;ip_release&#34;).
#
# Se non è vuota, prelevo il primo e lo rimuovo dalla lista. Se è vuota,
# prelevo l&#39;ultimo ottetto da &#34;ip_renew&#34; e lo incremento per il successivo
# assegnamento.
ip_renew() {
    # Selezioni i primi 3 ottetti del network
    SUB_IP=$(echo ${NETWORK}|awk -F &#34;.&#34; &#39;{print $1&#34;.&#34;$2&#34;.&#34;$3}&#39;)

    if [[ ! -e ${WORKDIR}/conf.d/ip_release || ! -s ${WORKDIR}/conf.d/ip_release ]]; then
        # Genero il nuovo ip (Incremento di 1 l&#39;ultimo ottetto)
        IP=$(cat ${WORKDIR}/conf.d/ip_renew)
        echo $((++IP)) &gt; ${WORKDIR}/conf.d/ip_renew

        # Restituisco i 3 ottetti + il quarto
        #echo -n ${SUB_IP};cat ${WORKDIR}/conf.d/ip_renew
    else
        IP=$(head -n 1 ${WORKDIR}/conf.d/ip_release)
        sed -i &#34;1d&#34; ${WORKDIR}/conf.d/ip_release
    fi
    echo -n ${SUB_IP}&#34;.&#34;${IP}
}



# Riallocazione di un indirizzo ip. Questa funzione viene invocata da
# removeclient().
# Aggiungo l&#39;ultimo ottetto alla lista degli ip riallocabili.
# @par 1: ultimo ottetto.
ip_release() {
    echo $1|cut -d&#34;.&#34; -f 4 &gt;&gt; ${WORKDIR}/conf.d/ip_release
}



# Aggiunge il nuovo peer al file di configurazione del server
# @par 1: CLIENT_PUBLIC_KEY
# @par 2: CLIENT_PSK
# @par 3: CLIENT_IP_ADDRESS
# @par 4: CLIENT_NAME
add_peer_to_server() {
    cat &gt;&gt; ${WORKDIR}/conf.d/server_wg.conf &lt;&lt; EOF
# $4
[Peer]
PublicKey = $1
PresharedKey = $2
AllowedIPs = $3/32
PersistentKeepalive = 25

EOF
}



# Inizializza la configurazione del server wireguard.
#
# Questa operazione può essere fatta una sola volta a meno che non si
# cancelli tutta la workdir.
#
# Verranno creati due file  di configurazione: server_wg.conf e 
# server_wg_raw.conf
#
# Il primo conterrà la configurazione completa del server e dei peer,
# verrà aggiornato ad ogni modifica dei client (aggiunta o rimozione) e
# verrà usato per il deploy della configurazione.
#
# Il secondo conterrà la configurazione del solo server e verrà usato
# solo per rigenerare il primo file di configurazione.
init() {
    # Controllo che wireguard sia almeno abilitato
    echo -n &#34;Inserire la password di Amministratore: &#34;; read -s PASSWORD
    sudo -k
    if echo $PASSWORD|sudo -S echo &#34;got a root&#34; &gt; /dev/null; then
        if ! sudo systemctl is-enabled --quiet wg-quick@${WG_INTERFACE}; then
            echo -en &#34;\nAttivazione servizio wireguard... &#34;
            #sudo systemctl enable --quiet wg-quick@${WG_INTERFACE}
            echo &#34;fatto.&#34;
        fi
        sudo -k 
        
        #Verifico che queste cartelle esistano. Se lo sono, non faccio nulla, se no le creo.
        echo -n &#34;Creazione workdir... &#34;
        [[ ! -e ${WORKDIR}/conf.d || ! -e ${WORKDIR}/psk  || ! -e ${WORKDIR}/keys ]] \
            &amp;&amp; { mkdir -p ${WORKDIR}/{conf.d,keys,psk}; } \
            || { echo &#34;inizializzazione già effettuata.&#34;; exit; }
        echo &#34;fatto.&#34;
        
        # Genero la chiave privata per il server
        echo -n &#34;Creazione chiave private del server...&#34;
        SERVER_PRIV_KEY=$(gen_priv_key &#34;server_wg&#34;)
        echo &#34;fatto.&#34;

        # Genero il file di configurazione
        echo -n &#34;Inizializzazione del server... &#34;
        cat &gt; ${WORKDIR}/conf.d/server_wg.conf &lt;&lt; EOF
[Interface]
Address = ${SERVER_IP_ADDRESS}/${SUBNET_MASK}
# SaveConfig = true

PreUp = ufw route allow in on ${WG_INTERFACE} out on ${PHYSICAL_INTERFACE} log from ${NETWORK}/${SUBNET_MASK} to 0.0.0.0/0
PostDown = ufw route delete allow in on ${WG_INTERFACE} out on ${PHYSICAL_INTERFACE} log from ${NETWORK}/${SUBNET_MASK} to 0.0.0.0/0

# IP masquerading
PreUp = iptables -t nat -A POSTROUTING -o ${PHYSICAL_INTERFACE} -s ${NETWORK}/${SUBNET_MASK} -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o ${PHYSICAL_INTERFACE} -s ${NETWORK}/${SUBNET_MASK} -j MASQUERADE

# IP filtering
PreUp = ufw allow in on ${PHYSICAL_INTERFACE} log to 0.0.0.0/0 app Wireguard
PostDown = ufw delete allow in on ${PHYSICAL_INTERFACE} log to 0.0.0.0/0 app Wireguard

ListenPort = ${LISTEN_PORT}
PrivateKey = ${SERVER_PRIV_KEY}

EOF
        echo &#34;fatto.&#34;
        cp ${WORKDIR}/conf.d/server_wg.conf ${WORKDIR}/conf.d/server_wg_raw.conf
        # Inizializza l&#39;erogatore di ip
        echo 1 &gt; ${WORKDIR}/conf.d/ip_renew
    else
        echo &#34;Sono necessarie le credenziali di amministrazione per eseguire questo comando.&#34;
        exit 1
    fi
}



# Genera un certificato per il client composto da:
# * chiave privata del client
# * chiave pre-condivisa
# * client ip
# * chiave pubblica del server
# * nome simbolico del client
#
# Dopo la creazione e il salvataggio in &lt;WORKDIR&gt;/conf.d, verrà aggiunto
# il relativo peer nella configurazione del server (server_wg.conf).
# @par_1 @par_2 @par_3...: lista di nomi relativi ai certificati da creare.
add_client() {
    if is_init; then
        # Se non c&#39;è alcun input, esco.
        if [[ $# -lt 1 ]]; then
            echo -e &#34;Devi inserire almeno un nome.&#34;
            exit 1
        else
            # Per ogni nome presente in input, creo una configurazione 
            # client e l&#39;aggiungo alla configurazione del server.
            for CLIENT_NAME in &#34;$@&#34;; do
                echo -n &#34;Creazione certificato per il client \&#34;${CLIENT_NAME}\&#34;... &#34;
                
                # Controllo se la configurazione esista già discriminando
                # in base al nome del file.
                if [[ -e ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf ]]; then
                    echo &#34;già esistente.&#34;
                else
                    # Creo la configurazione del client
                    CLIENT_PRIV_KEY=$(gen_priv_key ${CLIENT_NAME})
                    CLIENT_PUBLIC_KEY=$(echo ${CLIENT_PRIV_KEY} | wg pubkey)
                    CLIENT_PSK=$(gen_client_psk ${CLIENT_NAME})
                    CLIENT_IP_ADDRESS=$(ip_renew)
                    SERVER_PUBLIC_KEY=$(grep PrivateKey ${WORKDIR}/conf.d/server_wg.conf | cut -d &#34; &#34; -f 3 | tr -d &#34; &#34; | wg pubkey)
                    CLIENT_NAME_UPPER=$(echo ${CLIENT_NAME} | tr &#39;[:lower:]&#39; &#39;[:upper:]&#39;)
                    cat &gt; ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf &lt;&lt; EOF
    # ${CLIENT_NAME_UPPER}
    [Interface]
    Address = ${CLIENT_IP_ADDRESS}/${SUBNET_MASK}
    DNS = ${DNS}
    PrivateKey = ${CLIENT_PRIV_KEY}

    [Peer]
    PublicKey = ${SERVER_PUBLIC_KEY}
    PresharedKey = ${CLIENT_PSK}
    AllowedIPs = 0.0.0.0/0
    Endpoint = ${ENDPOINT}
    PersistentKeepalive = 25
EOF
                    echo &#34;fatto.&#34;
                    echo -n &#34;Aggiunta peer \&#34;${CLIENT_NAME}\&#34; al file di configurazione del server... &#34;
                    
                    # Aggiungo il peer alla configurazione del server.
                    add_peer_to_server ${CLIENT_PUBLIC_KEY} ${CLIENT_PSK} ${CLIENT_IP_ADDRESS} ${CLIENT_NAME_UPPER}
                    echo -e &#34;fatto.\n&#34;                
                fi
            done
        fi
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



# Rimuove file di configurazioni, chiavi e pre-shared key realtive a file
# dati in input.
# Rimuove inoltre il peer dal file di configurazione server_wg.conf.
# @par_1 @par_2 @par_3...: lista di nomi relativi ai certificati da rimuovere.
remove_client() {
    if is_init; then
        if [[ $# -lt 1 ]]; then
            echo -e &#34;Devi inserire almeno un nome.&#34;
            exit 1
        else
            for CLIENT_NAME in &#34;$@&#34;; do
                echo -n &#34;Rimozione client \&#34;${CLIENT_NAME}\&#34;... &#34;
                if [[ ! -e ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf ]]; then
                    echo &#34;non esistente.&#34;
                else
                    # Estraggo l&#39;ultimo ottetto dell&#39;ip del client.
                    IP=$(grep &#34;Address&#34; ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;|cut -d &#34;/&#34; -f 1)
                    
                    # Lo inserisco nella lista degli ip riallocabili.
                    ip_release ${IP}
                    
                    # Cancello file di configurazione, chiave e psk del client.
                    rm ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf ${WORKDIR}/keys/${CLIENT_NAME}_privkey ${WORKDIR}/psk/${CLIENT_NAME}_psk
                    echo &#34;terminata con successo.&#34;
                    echo -n &#34;Rimozione peer \&#34;${CLIENT_NAME}\&#34; dal file di configurazione del server... &#34;
                    
                    # Rimuovo il peer dalla configurazione del server.
                    CLIENT_NAME_UPPER=$(echo ${CLIENT_NAME} | tr &#39;[:lower:]&#39; &#39;[:upper:]&#39;)
                    sed -i &#34;/# ${CLIENT_NAME_UPPER}/,+6d&#34; ${WORKDIR}/conf.d/server_wg.conf
                    echo -e &#34;terminata con successo.\n&#34;   
                fi
            done
        fi
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



rebuild() {
    if is_init; then
        # Rigenero il file di configurazione del server da server_wg_raw.conf.
        echo -n &#34;Ripristino del file di configurazione del server... &#34;
        cat ${WORKDIR}/conf.d/server_wg_raw.conf &gt; ${WORKDIR}/conf.d/server_wg.conf
        echo &#34;fatto.&#34;
        
        # Per ogni file di configurazione client, aggiungo il relativo peer
        # nel file di configurazione server_wg.conf.
        for FILE_CONF in ${WORKDIR}/conf.d/client_*.conf; do
            CLIENT_PUBLIC_KEY=$(grep &#34;PrivateKey&#34; ${FILE_CONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34; | wg pubkey)
            CLIENT_PSK=$(grep &#34;PresharedKey&#34; ${FILE_CONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;)
            CLIENT_IP_ADDRESS=$(grep &#34;Address&#34; ${FILE_CONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;|cut -d &#34;/&#34; -f 1)
            CLIENT_NAME_UPPER=$(grep &#34;#&#34; ${FILE_CONF} | cut -d &#34; &#34; -f 2)
            echo -n &#34;Aggiunta peer \&#34;$(echo ${CLIENT_NAME_UPPER} | tr &#39;[:upper:]&#39; &#39;[:lower:]&#39;)\&#34;... &#34;
            add_peer_to_server ${CLIENT_PUBLIC_KEY} ${CLIENT_PSK} ${CLIENT_IP_ADDRESS} ${CLIENT_NAME_UPPER}
            echo -e &#34;fatto.&#34;
        done
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



# Avvia il server wireguard con la nuova configurazione
deploy() {
    if is_init; then
        echo -n &#34;Inserire la password di Amministratore: &#34;; read -s PASSWORD
        sudo -k
        if echo $PASSWORD|sudo -S echo &#34;got a root&#34; &gt; /dev/null; then
   
            # Stoppo il servizio wireguard
            echo -ne &#34;\nStop wireguard... &#34;
            sudo systemctl stop wg-quick@${WG_INTERFACE}
            echo &#34;fatto.&#34;
            
            # Aggiorno la configurazione
            echo -n &#34;Copia della nuova configurazione... &#34;
            sudo cp ${WORKDIR}/conf.d/server_wg.conf /etc/wireguard/${WG_INTERFACE}
            echo &#34;fatto.&#34;
            
            # Riavvio il servizio wireguard
            echo -n &#34;Riavvio wireguard... &#34;
            sudo systemctl start wg-quick@${WG_INTERFACE}
            echo &#34;fatto.&#34;
            
            # Revoco i privilegi di amministrazione
            sudo -k
        else
            echo &#34;Sono necessarie le credenziali di amministrazione per eseguire questo comando.&#34;
            exit 1
        fi
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



# Crea il qr-code della configurazione del client nella cartella corrente.
share() {
    if is_init; then
        if [[ $# -lt 1 ]]; then
            echo -e &#34;Devi inserire almeno un nome.&#34;
            exit 1
        else
            for CLIENT_NAME in &#34;$@&#34;; do
                echo -n &#34;Creazione qr-code per il client \&#34;${CLIENT_NAME}\&#34;... &#34;
                qrencode -r ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf -o qrcode_client_${CLIENT_NAME}.jpg
                echo &#34;fatto.&#34;
            done
        fi
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



help() {

[[ $1 != &#34;&#34; &amp;&amp; $1 != &#34;help&#34; ]] &amp;&amp; echo -e &#34;Comando inesistente.&#34;

    cat&lt;&lt;EOF
Usa come: ./wg_man.sh [command] ARG
dove:
    [command]
        init                     : Inizializza la configurazione del server.
        addclient &lt;lista nomi&gt;   : Aggiunge i client indicati in &lt;lista nomi&gt;.
        removeclient &lt;lista nomi&gt;: Rimuove i client indicati in &lt;lista nomi&gt;.
        rebuild                  : Ricostruisce il file di configurazione
                                   del server partendo dalle configurazioni
                                   di tutti i client registrati.
        deploy                   : Riavvia il server wireguard con l&#39;ultima
                                   configurazione disponibile.
        share &lt;lista nomi&gt;       : Genera i qr-code relativi ai client indicati in &lt;lista nomi&gt;.
        help                     : Stampa questa pagina di help.

ESEMPI:
    INiZIALIZZA IL SERVER WIREGUARD
    wg_man.sh init

    AGGIUNGE I CLIENT &#39;macbook_pro&#39;, &#39;mobile&#39;
    wg_man.sh addclient macbook_pro mobile

    RIMUOVE I CLIENT &#39;iphone_luca&#39;, &#39;workstation&#39;
    wg_man.sh removeclient iphone_luca workstation

    RICOSTRUISCE LA CONFIGURAZIONE DEL SERVER WIREGUARD
    wg_man.sh rebuild
    
    ATTIVA LA NUOVA CONFIGURAZIONE
    wg_man.sh deploy

    GENERA I QRCODE PER &#39;pc_ufficio&#39;, &#39;laptop&#39;
    wg_man.sh share pc_ufficio laptop
EOF
}



main() {
    case $1 in
        init         ) init ;;
        addclient    ) shift; add_client &#34;$@&#34; ;;
        removeclient ) shift; remove_client &#34;$@&#34; ;;
        rebuild      ) rebuild ;;
        deploy       ) deploy ;;
        share        ) shift; share &#34;$@&#34; ;;
        *            ) help ;;
    esac
}



check_dependency
case $? in
    &#34;0&#34; ) main $* ;;
    &#34;1&#34; ) echo -e &#34;UFW non presente. Installare UFW.&#34;; exit 1 ;;
    &#34;2&#34; ) echo -e &#34;wireguard-tools non presenti. È necessario installarli.&#34;; exit 1 ;;
esac
</code></pre>

<p><a href="/aytin/tag:bash" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bash</span></a> <a href="/aytin/tag:wireguard" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">wireguard</span></a> <a href="/aytin/tag:psk" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">psk</span></a> <a href="/aytin/tag:chiavi" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">chiavi</span></a> <a href="/aytin/tag:certificati" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">certificati</span></a> <a href="/aytin/tag:crittografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">crittografia</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/script-per-la-gestione-della-configurazione-di-una-vpn-wireguard</guid>
      <pubDate>Sun, 22 Sep 2024 13:27:09 +0000</pubDate>
    </item>
    <item>
      <title>Stunnel: Cos&#39;è e come si configura</title>
      <link>https://noblogo.org/aytin/stunnel-cose-e-come-si-configura</link>
      <description>&lt;![CDATA[(pubblicato il 7 gennaio 2023)&#xA;Stunnel&#xA;smalliFonte: a href=&#34;https://www.stunnel.org&#34;stunnel.org/a/i/small&#xA;&#xA;Introduzione&#xA;&#xA;Da documentazione, Stunnel agisce come un proxy per aggiungere crittografia TLS a server e/o a client già esistenti.&#xA;&#xA;Risulta quindi molto comodo quando si vuole aggiungere, attraverso un tunnel TLS, quella crittografia che manca alle nostre applicazioni per rendere le comunicazioni più sicure.&#xA;!--more--&#xA;Come in ssh, è possibile “tunnellizzare” solo connessioni TCP.&#xA;&#xA;Di stunnel esaminerò in particolare la fase di autenticazione attraverso certificato o PSK.&#xA;&#xA;Gli scenari possibili, in base alle combinazioni, sono tre:&#xA;&#xA;client tls – server in chiaro&#xA;client in chiaro – server tls&#xA;client e server in chiaro&#xA;&#xA;Nel primo caso, occorre configurare stunnel in server mode, definendo un receiver ssl, a cui il client potrà connettersi.&#xA;stunel server&#xA;smalliScenario 1: stunnel server/i/small&#xA;&#xA;Nel secondo caso, occorre configurare stunnel in client mode, definendo un sender ssl che il client userà per connettersi al server&#xA;stunnel client&#xA;smalliScenario 2: stunnel client/i/small&#xA;&#xA;Nel terzo caso, occorre configurare uno stunnel client e uno server&#xA;stunnel client e server&#xA;smalliScenario 3: stunnel client e server/i/small&#xA;&#xA;Come ulteriore evoluzione per quel che riguarda le tratte in chiaro (e non solo) di client-stunnel client, stunnel client-stunnel server, stunnel server-server, sarebbe buona norma limitarne l’accesso con un firewall.&#xA;stunnel client e server e firewall&#xA;smalliStunnel e firewall/i/small&#xA;&#xA;Se invece stunnel fosse locale (installato direttamente sul client e/o sul server), la richiesta del client o il listener del servizio, avverrebbero sull’interfaccia di loopback.&#xA;Altrimenti, in assenza di firewall, sarebbe consigliabile accertare che la rete di collegamento fra i proxy stunnel e i rispettivi client/server, sia almeno di tipo “trusted”.&#xA;&#xA;Stunnel consente un certo tuning sulla parte tls, potendo discriminare fra le cipher suites da abilitare, specificare comandi o configurazioni specifiche per openssl.&#xA;Quando si deve incapsulare una connessione in chiaro in un tunnel ssl bisogna tenere presente gli scenari menzionati prima.&#xA;Convenzioni&#xA;&#xA;Per non perdere generalità, negli esempi che seguiranno, immaginiamo che stunnel non sia locale (anche se spesso lo è).&#xA;   se stunnel in client mode è locale ⇒ accept avverrà sull’interfaccia di loopback, da dove avviene effettivamente la richiesta&#xA;   se stunnel in server mode è locale ⇒ connect avverrà sull’interfaccia di loopback, dove viene erogato effettivamente il servizio&#xA;Non faremo assunzioni sulla creazione dei certificati. Possono anche essere self-signed.&#xA;&#xA;Configurazione stunnel&#xA;&#xA;Verranno mostrate le configurazioni relative agli scenari mostrati nel modo più semplice possibile.&#xA;&#xA;accept: host e porta che ricevono la richiesta&#xA;connect: host e porta a cui girare l’accept&#xA;cert: normalmente conterrebbe il certificato pubblico che stunnel espone per autenticarsi (la parte privata viene specificata con key). Può però anche essere costituito da tutta i certificati della chain fino alla root CA, in formato pem o p12, iniziando dalla chiave privata, proseguendo con la chiave pubblica, fino a tutte le CA della chain.&#xA;key: chiave privata del certificato&#xA;client: stabilisce se stunnel funzioni in server mode oppure no&#xA;&#xA;Primo scenario&#xA;&#xA;Nel primo caso, una configurazione minimale lato server, ha bisogno:&#xA;&#xA;host e porta dello stunnel server che riceve il traffico cifrato&#xA;host e porta del server su cui girare il traffico in chiaro&#xA;certificato pubblico e chiave privata necessari per la cifratura&#xA;&#xA;Stunnel Server:&#xA;[myService]&#xA;accept = ipstunnelserver:portsts&#xA;connect = ipserver:portserver&#xA;cert = /servercrt.pembr&#xA;key = /serverkey.pem&#xA;Secondo scenario&#xA;&#xA;Nel secondo caso, una configurazione minimale lato client, ha bisogno:&#xA;&#xA;host e porta dello stunnel client da cui partirà la richiesta&#xA;host e porta del server da cui stunnel client avvierà la sessione tls&#xA;&#xA;Stunnel Client:&#xA;[myService]&#xA;client = yes&#xA;accept = ipstunnelclient:portstc&#xA;connect = ipserver:portserver&#xA;Terzo Scenario&#xA;&#xA;Il terzo caso, è una fusione dei primi due. Sono gli stunnel a gestire il grosso della comunicazione. E nei casi in cui lo stunnel viene installato sulle macchine di servizio, client e server reali usano solo l’interfaccia di loopback.&#xA;&#xA;Una configurazione minimale per il client ha bisogno di:&#xA;&#xA;host e porta dello stunnel client da cui partirà la richiesta&#xA;host e porta del server da cui stunnel client avvierà la sessione tls&#xA;&#xA;Stunnel Client:&#xA;[myService]&#xA;client = yes&#xA;accept = ipstunnelclient:portstc&#xA;connect = ipstunnelserver:portserver&#xA;Una configurazione minimale per il server ha bisogno:&#xA;&#xA;host e porta dello stunnel server che riceve il traffico cifrato&#xA;host e porta del server su cui girare il traffico in chiaro&#xA;    certificato pubblicato e chiave privata necessari per la cifratura&#xA;&#xA;Stunnel Server:&#xA;[myService]&#xA;accept = ipstunnelserver:portsts&#xA;connect = ipserver:portserver&#xA;cert = /servercrt.pem&#xA;key = /serverkey.pem&#xA;smallPiccola nota: se client e/o server dovessero supportare chiavi PSK, si potrebbe usare PSK in luogo dei certificati. Ci ritornerò più avanti./small&#xA;&#xA;Autenticazione dei client&#xA;&#xA;Le impostazioni viste finora, mostrano come incapsulare un traffico in chiaro all’interno di un tunnel tls e si basano sulla sola autenticazione lato server.&#xA;&#xA;Per migliorare la configurazione possiamo ricorrere alla mutua autenticazione facendo in modo che anche i client si autentichino.&#xA;&#xA;Una mutua autenticazione, con tutte le verifiche del caso, aumenta il grado di sicurezza comunicazione TLS ed è un efficace deterrente contro eventuali attacchi MITM. L’autenticazione sul client si può ottenere sempre con i certificati oppure, più semplicemente, con chiavi PSK.&#xA;&#xA;Autenticazione dei client con certificato&#xA;&#xA;Ad una configurazione minimale per una mutua autenticazione, lato server, si richiede che i client esibiscano il certificato e i client (che sia stunnel in client mode, un browser o qualunque altra cosa) dovranno essere in grado di esibire i certificati nel momento in cui il server li richiederà.&#xA;&#xA;Su stunnel server, alle configurazioni viste in precedenza, si aggiunge requireCert impostato a yes, che richiede ai client l’esibizione di un certificato. Se, durante l’handshake TLS, il client non esibisce un certificato, l’handshake fallisce e la connessione viene rifiutata.&#xA;&#xA;Stunnel Server:&#xA;[myService]&#xA;…&#xA;requireCert = yes&#xA;…&#xA;È sufficiente questo se i client possono manipolare i propri certificati. Altrimenti, se c’è uno stunnel client che intermedia le richieste dei client effettivi, si deve aggiungere alla sua configurazione la chiave e il certificato del client&#xA;&#xA;Stunnel Client:&#xA;[myService]&#xA;…&#xA;cert = /servercrt.pem&#xA;key = /serverkey.pem&#xA;…&#xA;Autenticazione dei client con PSK&#xA;&#xA;Per l’autenticazione PSK bisogna disporre della lista di utenti abilitati con relative chiavi esadecimali di almeno 16 bytes (ossia almeno 32 caratteri esadecimali visto che con un byte si rappresentano due esadecimali).&#xA;&#xA;La creazione di una chiave esadecimale può essere fatta velocemente con openssl.&#xA;Supponiamo di creare due utenze per Frodo e Gandalf con chiavi da 20 e 42 bytes.&#xA;echo -e &#34;frodo:&#34;$(openssl rand -hex 20)   frodopsk.txt&#xA;echo -e &#34;gandalf:&#34;$(openssl rand -hex 42)   gandalfpsk.txt&#xA;Tutte le identità dovranno confluire nel file che, nella configurazione stunnel, sarà indicato da PSKsecrets. Ad es:&#xA;cat frodopsk.txt gandalfpsk.txt   psksecrets.txt&#xA;…&#xA;frodo:84196825fab3389624dcc83eb61189e5b21099febrgandalf:5daf128419855993a2d95ba0a337c51b3f373df88e594441f2979eba6461f25676f1f825b0c76df392f2&#xA;…&#xA;E, come detto, nella configurazione dello stunnel server dovrò indicare il file delle identità:&#xA;&#xA;Stunnel Server&#xA;[myServer]&#xA;accept = ipstunnelserver:portsts&#xA;connect = ipserver:portserver&#xA;PSKsecrets = pathidentityfile/psksecrets.txt&#xA;Se il client supporta PSK, dovrà fornire identità e password. Ad es. facendo un test con openssl:&#xA;openssl sclient -port porta -pskidentity frodo -psk 84196825fab3389624dcc83eb61189e5b21099fe -tls12 -connect host&#xA;Altrimenti si configura stunnel client indicando sia l’identità, sia il file individuate da PSKsecrets.&#xA;&#xA;Stunnel Client&#xA;[myClient]&#xA;client = yes&#xA;accept = ipstunnelclient:portstc&#xA;connect = ipstunnelserver:portserver&#xA;PSKidentity = frodo&#xA;PSKsecrets = pathidentityfile/psksecrets.txt&#xA;In alternativa, per non far viaggiare il file delle identità fra tutti i client, possiamo sfruttare a nostro vantaggio il default delle identità.&#xA;&#xA;In assenza della direttiva PSKidentity, viene assunta come identità di default la prima riga del file indicato da PSKSecrets. Basta quindi creare un file con la sola identità che mi occorre, ad es. frodopsk.txt&#xA;frodo:84196825fab3389624dcc83eb61189e5b21099fe&#xA;e indicare quello in PSKSecrets. La configurazione che segue è equivalente alla precedente.&#xA;&#xA;Stunnel Client&#xA;[myClient]&#xA;client = yes&#xA;accept = ipstunnelclient:portstc&#xA;connect = ipstunnelserver:portserver&#xA;PSKsecrets = pathidentityfile/frodopsk.txt&#xA;Ulteriori considerazioni di sicurezza&#xA;Autenticazione con certificato&#xA;&#xA;La richiesta di autenticazione dei client mediante certificato è una buona misura preventiva ma può essere resa migliore.&#xA;&#xA;Nelle configurazioni viste finora, stunnel server autorizza l’accesso al servizio solo se il client si presenta con un certificato ma non c’è nulla che vincoli il certificato al servizio. In altre parole, un client in possesso di un qualunque certificato, può accedere alla risorsa.&#xA;&#xA;È possibile rafforzare il trusting fra le parti facendo in modo che stunnel autorizzi solo alcuni certificati invece che qualunque. Questo tipo di controllo può essere fatto sia su stunnel sia in client mode che in server mode.&#xA;&#xA;verifyChain = yes | no&#xA;checkEmail = email del certificato&#xA;checkHost = CN del certificato&#xA;checkIP = IP del peer che presenta il certificato&#xA;verifyPeer = yes | no&#xA;CApath =  path CA &#xA;CAfile =  file pem contenente la fullchain del certificato presentato a stunnel &#xA;&#xA;verifyChain&#xA;Impone che si possa verificare la fullchain del certificato presentato. Se uno degli issuer non viene trovato, la connessione fallisce. La fullchain viene indicata attraverso CAfile o CApath.&#xA;&#xA;CAfile&#xA;È il file contenente le CA con cui stunnel valida i certificati che gli vengono presentati. Se stunnel è in server mode, sarà la fullchain relativa ai client. Altrimenti sarà la fullchain relativa al server.&#xA;&#xA;CApath&#xA;È il path in cui si trovano le CA con cui stunnel valida i certificati che gli vengono presentati. Se lo stunnel è in server mode, sarà la fullchain realtiva ai client. Altrimenti sarà la fullchain relativa al server.&#xA;&#xA;verifyPeer&#xA;Se con CAfile e CApath si verifica la fullchain dei certificati presentati a stunnel, con verifyPeer = yes si verifica che questi certificati siano presenti anche nel suo keystore (CAfile o CApath). Permette di “legare” a stunnel i certificati che dovrà validare.&#xA;&#xA;checkEmail, checkHost, checkIP&#xA;Come per verifyPeer, sono direttive che permettono di stringere il legame fra il certificato che viene presentato e stunnel.&#xA;Verifica che l’email, il CN o l’IP del certificato che viene presentato corrispondano a quelli presenti nella configurazione.&#xA;In una configurazione lato server posso avere molteplici occorrenze di questi due campi relative ad altrettanti certificati. Il caso in cui ad es. si debbano autenticare n client.&#xA;&#xA;Se i certificati sono self-signed, verifyChain perde di significato (coinciderebbe con verifyPeer). La possibilità di generare i certificati attraverso una CA, anche interna, renderebbe il processo più strutturato anche se più complesso (si dovrà trovare un modo per distribuire la CA, se interna). Si tratta di trovare il giusto compromesso fra ampiezza del servizio (quanti utenti coinvolge?) e complessità richiesta.&#xA;&#xA;Se si tratta di realizzare un canale sicuro fra due apparati per una comunicazione server-2-server, vanno bene anche i certificati self-signed o un’autenticazione PSK. Altrimenti, soprattutto nel caso in cui l’autenticazione dei client è una fase critica, conviene valutare l’uso di una CA e una validazione il più possibile restrittiva sui client e sul server.&#xA;&#xA;Autenticazione PSK&#xA;&#xA;A differenza dell’autenticazione con certificato, l’autenticazione con PSK non prevede enhancement di sicurezza ulteriori a meno di specificare opportuni algoritmi di cifratura (cfr. paragrafo successivo).&#xA;&#xA;Cifratura&#xA;&#xA;Come sempre succede, negli scenari di cifratura asimmetrica orientatia alla connessione, l’autenticazione, per quanto possa essere accurata, costituisce solo uno degli aspetti di cui tenere conto nella fase di messa in sicurezza del servizio.&#xA;&#xA;Avere un’autenticazione con certificato generato con tutti i crismi da una CA, è certamente una gran cosa ma mette in sicurezza solo l’aspetto dell’autenticazione, per l’appunto.&#xA;&#xA;l transito dei dati è affidato alle suite di cifratura supportati da openssl e, volendo lavorare di fino, bisognerebbe stringere anche su quelli.&#xA;&#xA;Altrimenti, paradossalmente, si avrà un’autenticazione robustissima ma con algoritmi colabrodo di cifratura dei dati che, ad attaccanti ben motivati, lascerebbero delle porte spalancate per sferrare attacchi MITM per intercettare direttamente i dati, piuttosto che provare il furto di identità.&#xA;&#xA;Ad ogni modo, il default, per ragioni di compatibilità legacy, dei parametri di cifratura (da settare eventualmente su client e sul server) è il seguente:&#xA;ciphers: HIGH:!aNULL:!SSLv2:!DH:!kDHEPSK&#xA;ciphersuites: TLSAES256GCMSHA384:TLSAES128GCMSHA256:TLSCHACHA20POLY1305SHA256&#xA;dove ciphers raggruppa le suite di cifratura relativi a TLS1.2 in giù e ciphersuites riguarda invece TLS1.3.&#xA;&#xA;Configurazione servizio&#xA;&#xA;Ulteriori restrizioni possono essere aggiunte a livelllo di sistema:&#xA;&#xA;regolando i bit di setuid e setgid se stunnel gira come root&#xA;delimitando l’esecuzione del processo in una gabbia chroot&#xA;disabilitando le regonetiation (se supportato dalla versione di openssl in uso) che mitiga in parte attacchi dos di tipo CPU-exhaustion&#xA;ecc..&#xA;&#xA;Caso reale: tunnelizzare Transmission.&#xA;&#xA;Transmission è un client bittorrent che può essere controllato da remoto via rpc attraverso un’interfaccia web o altri client.&#xA;&#xA;Transmission, nelle sue varie declinazioni, non incapsula il traffico rpc in una connessione tls.&#xA;&#xA;Se si vuole che il dato in transito sia cifrato e che la connessione sia autenticata, si può ricorrere:&#xA;&#xA;ad un tunnel ssh;&#xA;all’intermediazione di un webserver come apache o nginx ;&#xA;ad uno stunnel server&#xA;&#xA;Sugli ultimi due punti si può configurare una mutua autenticazione con certificato (complessa e articolata e, per tanti client, ha un impatto significativo). Scegliamo il 3° caso.&#xA;&#xA;Esposizione dell’interfaccia web&#xA;&#xA;Scenario: abbiamo una macchina (il nostro serverino di fiducia o un nas) con transmission a bordo, presumibilmente dietro un firewall che natta il suo indirizzo privato (192.168.70.15).&#xA;&#xA;Transmission Stunnel&#xA;smallEsposizione transmission attraverso stunnel server/small&#xA;&#xA;Obiettivo: Vogliamo poter raggiungere transmission e vogliamo che i client autentichino la loro connessione prima di accedere al servizio. In base allo scenario, sappiamo che dovremmo configurare un port forwarding dall’AP fino allo stunnel server. Il server transmission rimarrà confinato nella nostra rete locale.&#xA;&#xA;Utilizzo di un client esterno&#xA;&#xA;Supponiamo di utilizzare diversi client: il browser, transmission-remote-gtk o transmission-remote-gui (transgui), tremotesf (mobile).&#xA;&#xA;La prima cosa da fare è configurare un port forwarding sul nostro AP&#xA;&#xA;    Rulesub1/sub: 9091 ⇒ 192.168.70.10:9091&#xA;&#xA;Dopodichè, configureremo stunnel in server mode davanti a transmission&#xA;[transmission]&#xA;accept = 192.168.70.10:9091&#xA;connect = 192.168.70.15:9091&#xA;cert = path stunnel conf/ssl/server/certs/stunnelcrt.pem&#xA;key = path stunnel conf/ssl/server/private/stunnelkey.pem&#xA;requireCert = yes&#xA;verifyChain = yes&#xA;verifyPeer = yes&#xA;CApath = path stunnel conf/ssl/client/certs&#xA;Alcune note sulla configurazione:&#xA;&#xA;devo disporre di un certificato per stunnel&#xA;devo disporre dei certificati per i client che si connetteranno, le cui fullchain dovranno essere localizzate nel path indicato da CApath&#xA;&#xA;A questo punto basta che i web-client puntino all’host pubblico (151.25.77.205) sulla porta 9091 e il gioco è fatto.&#xA;&#xA;Per gli altri client come transmission-remote-gtk, transgui o tremotesf, per i quali al massimo posso chiedere di usare TLS (ma non sono riuscito ad usare un’autenticazione lato client), conviene installare stunnel in client mode :&#xA;[transmission-client]&#xA;accept = localhost:9091&#xA;connect = 151.25.77.205:9091&#xA;client = yes&#xA;cert = path stunnel conf/ssl/client/laptopcrt.pem&#xA;key = path stunnel conf/ssl/client/laptopkey.pem&#xA;verifyChain = yes&#xA;verifyPeer = yes&#xA;CAPath = path stunnel conf/ssl/server/certs&#xA;Il client (ad es. sul laptop) si connetterà su localhost:9091 e dovrà disporre anche del certificato del server e della sua fullchain affinchè i check su verifyChain e verifyPeer non falliscano.&#xA;&#xA;#ca #DigitalCertificate #AsymmetricEncryption #SymmetricEncryption #cryptography #fullchain #psk #ssh #ssl #stunnel #tls #x509 #openssl]]&gt;</description>
      <content:encoded><![CDATA[<p><strong><em>(pubblicato il 7 gennaio 2023)</em></strong>
<img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/42a8ecf32-5a8865/eZP2oeutp2KD/bkO44BGcvLFyYYUeCuYKXlSQzvBqgKi0Uh4fYtYk.jpg" alt="Stunnel">
<small><i>Fonte: <a href="https://www.stunnel.org" rel="nofollow">stunnel.org</a></i></small></p>

<h2 id="introduzione">Introduzione</h2>

<p>Da documentazione, Stunnel agisce come un proxy per aggiungere crittografia TLS a server e/o a client già esistenti.</p>

<p>Risulta quindi molto comodo quando si vuole aggiungere, attraverso un tunnel TLS, quella crittografia che manca alle nostre applicazioni per rendere le comunicazioni più sicure.

Come in ssh, è possibile “tunnellizzare” solo connessioni TCP.</p>

<p>Di stunnel esaminerò in particolare la fase di autenticazione attraverso certificato o PSK.</p>

<p>Gli scenari possibili, in base alle combinazioni, sono tre:</p>
<ul><li>client tls – server in chiaro</li>
<li>client in chiaro – server tls</li>
<li>client e server in chiaro</li></ul>

<p>Nel primo caso, occorre configurare stunnel in server mode, definendo un receiver ssl, a cui il client potrà connettersi.
<img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/42a8ecf32-5a8865/sQc861Pfxyfg/39Yo5lasr3nAebRZbrzqtoQOskqS62aHW9fwwyo0.png" alt="stunel server">
<small><i>Scenario 1: stunnel server</i></small></p>

<p>Nel secondo caso, occorre configurare stunnel in client mode, definendo un sender ssl che il client userà per connettersi al server
<img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/42a8ecf32-5a8865/nz4fkq8opVoD/HcocxYf4VwB0UtihuwlQ6pOo2CKxDCTU4X5v1UNB.png" alt="stunnel client">
<small><i>Scenario 2: stunnel client</i></small></p>

<p>Nel terzo caso, occorre configurare uno stunnel client e uno server
<img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/42a8ecf32-5a8865/zxIg9C1izJPj/DqgYaAezDIab01XBFMHiDRjUqEDWxNqxMJOGDSvs.png" alt="stunnel client e server">
<small><i>Scenario 3: stunnel client e server</i></small></p>

<p>Come ulteriore evoluzione per quel che riguarda le tratte in chiaro (e non solo) di client-stunnel client, stunnel client-stunnel server, stunnel server-server, sarebbe buona norma limitarne l’accesso con un firewall.
<img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/42a8ecf32-5a8865/j9Qbwy74AkaE/igU7qV0XI8gVIASWfDufiBvWeAf0OgnQ24ZLwC42.png" alt="stunnel client e server e firewall">
<small><i>Stunnel e firewall</i></small></p>

<p>Se invece stunnel fosse locale (installato direttamente sul client e/o sul server), la richiesta del client o il listener del servizio, avverrebbero sull’interfaccia di loopback.
Altrimenti, in assenza di firewall, sarebbe consigliabile accertare che la rete di collegamento fra i proxy stunnel e i rispettivi client/server, sia almeno di tipo “trusted”.</p>

<p>Stunnel consente un certo tuning sulla parte tls, potendo discriminare fra le cipher suites da abilitare, specificare comandi o configurazioni specifiche per openssl.
Quando si deve incapsulare una connessione in chiaro in un tunnel ssl bisogna tenere presente gli scenari menzionati prima.</p>

<h2 id="convenzioni">Convenzioni</h2>
<ul><li>Per non perdere generalità, negli esempi che seguiranno, immaginiamo che stunnel non sia locale (anche se spesso lo è).
<ul><li>se stunnel in <em>client mode</em> è locale ⇒ <strong>accept</strong> avverrà sull’interfaccia di loopback, da dove avviene effettivamente la richiesta</li>
<li>se stunnel in <em>server mode</em> è locale ⇒ <strong>connect</strong> avverrà sull’interfaccia di loopback, dove viene erogato effettivamente il servizio</li></ul></li>
<li>Non faremo assunzioni sulla creazione dei certificati. Possono anche essere self-signed.</li></ul>

<h2 id="configurazione-stunnel">Configurazione stunnel</h2>

<p>Verranno mostrate le configurazioni relative agli scenari mostrati nel modo più semplice possibile.</p>
<ul><li><strong>accept</strong>: host e porta che ricevono la richiesta</li>
<li><strong>connect</strong>: host e porta a cui girare l’accept</li>
<li><strong>cert</strong>: normalmente conterrebbe il certificato pubblico che stunnel espone per autenticarsi (la parte privata viene specificata con <strong>key</strong>). Può però anche essere costituito da tutta i certificati della chain fino alla root CA, in formato pem o p12, iniziando dalla chiave privata, proseguendo con la chiave pubblica, fino a tutte le CA della chain.</li>
<li><strong>key</strong>: chiave privata del certificato</li>
<li><strong>client</strong>: stabilisce se stunnel funzioni in server mode oppure no</li></ul>

<h3 id="primo-scenario">Primo scenario</h3>

<p>Nel primo caso, una configurazione minimale lato server, ha bisogno:</p>
<ol><li>host e porta dello stunnel server che riceve il traffico cifrato</li>
<li>host e porta del server su cui girare il traffico in chiaro</li>
<li>certificato pubblico e chiave privata necessari per la cifratura</li></ol>

<p><strong>Stunnel Server:</strong></p>

<pre><code>[myService]
accept = ip_stunnel_server:port_sts
connect = ip_server:port_server
cert = /server_crt.pem&lt;br&gt;
key = /server_key.pem
</code></pre>

<h3 id="secondo-scenario">Secondo scenario</h3>

<p>Nel secondo caso, una configurazione minimale lato client, ha bisogno:</p>
<ol><li>host e porta dello stunnel client da cui partirà la richiesta</li>
<li>host e porta del server da cui stunnel client avvierà la sessione tls</li></ol>

<p><strong>Stunnel Client:</strong></p>

<pre><code>[myService]
client = yes
accept = ip_stunnel_client:port_stc
connect = ip_server:port_server
</code></pre>

<h3 id="terzo-scenario">Terzo Scenario</h3>

<p>Il terzo caso, è una fusione dei primi due. Sono gli stunnel a gestire il grosso della comunicazione. E nei casi in cui lo stunnel viene installato sulle macchine di servizio, client e server reali usano solo l’interfaccia di loopback.</p>

<p>Una configurazione minimale per il client ha bisogno di:</p>
<ol><li>host e porta dello stunnel client da cui partirà la richiesta</li>
<li>host e porta del server da cui stunnel client avvierà la sessione tls</li></ol>

<p><strong>Stunnel Client:</strong></p>

<pre><code>[myService]
client = yes
accept = ip_stunnel_client:port_stc
connect = ip_stunnel_server:port_server
</code></pre>

<p>Una configurazione minimale per il server ha bisogno:</p>
<ol><li>host e porta dello stunnel server che riceve il traffico cifrato</li>
<li>host e porta del server su cui girare il traffico in chiaro
certificato pubblicato e chiave privata necessari per la cifratura</li></ol>

<p><strong>Stunnel Server:</strong></p>

<pre><code>[myService]
accept = ip_stunnel_server:port_sts
connect = ip_server:port_server
cert = /server_crt.pem
key = /server_key.pem
</code></pre>

<p><small><strong>Piccola nota</strong>: se client e/o server dovessero supportare chiavi PSK, si potrebbe usare PSK in luogo dei certificati. Ci ritornerò più avanti.</small></p>

<h2 id="autenticazione-dei-client">Autenticazione dei client</h2>

<p>Le impostazioni viste finora, mostrano come incapsulare un traffico in chiaro all’interno di un tunnel tls e si basano sulla sola autenticazione lato server.</p>

<p>Per migliorare la configurazione possiamo ricorrere alla <a href="https://noblogo.org/aytin/mutua-autenticazione" rel="nofollow"><strong>mutua autenticazione</strong></a> facendo in modo che anche i client si autentichino.</p>

<p>Una mutua autenticazione, con tutte le verifiche del caso, aumenta il grado di sicurezza comunicazione TLS ed è un efficace deterrente contro eventuali attacchi MITM. L’autenticazione sul client si può ottenere sempre con i certificati oppure, più semplicemente, con chiavi PSK.</p>

<h3 id="autenticazione-dei-client-con-certificato">Autenticazione dei client con certificato</h3>

<p>Ad una configurazione minimale per una mutua autenticazione, lato server, si richiede che i client esibiscano il certificato e i client (che sia stunnel in <em>client mode</em>, un browser o qualunque altra cosa) dovranno essere in grado di esibire i certificati nel momento in cui il server li richiederà.</p>

<p>Su stunnel server, alle configurazioni viste in precedenza, si aggiunge <strong>requireCert</strong> impostato a <strong>yes</strong>, che richiede ai client l’esibizione di un certificato. Se, durante l’handshake TLS, il client non esibisce un certificato, l’handshake fallisce e la connessione viene rifiutata.</p>

<p><strong>Stunnel Server:</strong></p>

<pre><code>[myService]
…
requireCert = yes
…
</code></pre>

<p>È sufficiente questo se i client possono manipolare i propri certificati. Altrimenti, se c’è uno stunnel client che intermedia le richieste dei client effettivi, si deve aggiungere alla sua configurazione la chiave e il certificato del client</p>

<p><strong>Stunnel Client:</strong></p>

<pre><code>[myService]
…
cert = /server_crt.pem
key = /server_key.pem
…
</code></pre>

<h3 id="autenticazione-dei-client-con-psk">Autenticazione dei client con PSK</h3>

<p>Per l’autenticazione PSK bisogna disporre della lista di utenti abilitati con relative chiavi esadecimali di almeno 16 bytes (ossia almeno 32 caratteri esadecimali visto che con un byte si rappresentano due esadecimali).</p>

<p>La creazione di una chiave esadecimale può essere fatta velocemente con openssl.
Supponiamo di creare due utenze per <em>Frodo</em> e <em>Gandalf</em> con chiavi da 20 e 42 bytes.</p>

<pre><code class="language-bash">echo -e &#34;frodo:&#34;$(openssl rand -hex 20) &gt; frodo_psk.txt
echo -e &#34;gandalf:&#34;$(openssl rand -hex 42) &gt; gandalf_psk.txt
</code></pre>

<p>Tutte le identità dovranno confluire nel file che, nella configurazione stunnel, sarà indicato da <strong>PSKsecrets</strong>. Ad es:</p>

<pre><code class="language-bash">cat frodo_psk.txt gandalf_psk.txt &gt; psksecrets.txt
…
frodo:84196825fab3389624dcc83eb61189e5b21099fe&lt;br&gt;gandalf:5daf128419855993a2d95ba0a337c51b3f373df88e594441f2979eba6461f25676f1f825b0c76df392f2
…
</code></pre>

<p>E, come detto, nella configurazione dello stunnel server dovrò indicare il file delle identità:</p>

<p><strong>Stunnel Server</strong></p>

<pre><code>[myServer]
accept = ip_stunnel_server:port_sts
connect = ip_server:port_server
PSKsecrets = &lt;path_identity_file&gt;/psksecrets.txt
</code></pre>

<p>Se il client supporta PSK, dovrà fornire identità e password. Ad es. facendo un test con <code>openssl</code>:</p>

<pre><code class="language-bash">openssl s_client -port &lt;porta&gt; -psk_identity frodo -psk 84196825fab3389624dcc83eb61189e5b21099fe -tls1_2 -connect &lt;host&gt;
</code></pre>

<p>Altrimenti si configura stunnel client indicando sia l’identità, sia il file individuate da <strong>PSKsecrets</strong>.</p>

<p><strong>Stunnel Client</strong></p>

<pre><code>[myClient]
client = yes
accept = ip_stunnel_client:port_stc
connect = ip_stunnel_server:port_server
PSKidentity = frodo
PSKsecrets = &lt;path_identity_file&gt;/psksecrets.txt
</code></pre>

<p>In alternativa, per non far viaggiare il file delle identità fra tutti i client, possiamo sfruttare a nostro vantaggio il default delle identità.</p>

<p>In assenza della direttiva <strong>PSKidentity</strong>, viene assunta come identità di default la prima riga del file indicato da <strong>PSKSecrets</strong>. Basta quindi creare un file con la sola identità che mi occorre, ad es. <strong>frodo_psk.txt</strong></p>

<pre><code>frodo:84196825fab3389624dcc83eb61189e5b21099fe
</code></pre>

<p>e indicare quello in <strong>PSKSecrets</strong>. La configurazione che segue è equivalente alla precedente.</p>

<p><strong>Stunnel Client</strong></p>

<pre><code>[myClient]
client = yes
accept = ip_stunnel_client:port_stc
connect = ip_stunnel_server:port_server
PSKsecrets = &lt;path_identity_file&gt;/frodo_psk.txt
</code></pre>

<h2 id="ulteriori-considerazioni-di-sicurezza">Ulteriori considerazioni di sicurezza</h2>

<h3 id="autenticazione-con-certificato">Autenticazione con certificato</h3>

<p>La richiesta di autenticazione dei client mediante certificato è una buona misura preventiva ma può essere resa migliore.</p>

<p>Nelle configurazioni viste finora, stunnel server autorizza l’accesso al servizio solo se il client si presenta con un certificato ma non c’è nulla che vincoli il certificato al servizio. In altre parole, un client in possesso di un qualunque certificato, può accedere alla risorsa.</p>

<p>È possibile rafforzare il trusting fra le parti facendo in modo che stunnel autorizzi solo alcuni certificati invece che qualunque. Questo tipo di controllo può essere fatto sia su stunnel sia in <em>client mode</em> che in <em>server mode</em>.</p>
<ul><li><strong>verifyChain</strong> = yes | no</li>
<li><strong>checkEmail</strong> = email del certificato</li>
<li><strong>checkHost</strong> = CN del certificato</li>
<li><strong>checkIP</strong> = IP del peer che presenta il certificato</li>
<li><strong>verifyPeer</strong> = yes | no</li>
<li><strong>CApath</strong> = &lt; path CA &gt;</li>
<li><strong>CAfile</strong> = &lt; file <strong>pem</strong> contenente la fullchain del certificato presentato a stunnel &gt;</li></ul>

<p><strong>verifyChain</strong>
Impone che si possa verificare la fullchain del certificato presentato. Se uno degli issuer non viene trovato, la connessione fallisce. La fullchain viene indicata attraverso <strong>CAfile</strong> o <strong>CApath</strong>.</p>

<p><strong>CAfile</strong>
È il <strong>file</strong> contenente le CA con cui stunnel valida i certificati che gli vengono presentati. Se stunnel è in <em>server mode</em>, sarà la fullchain relativa ai client. Altrimenti sarà la fullchain relativa al server.</p>

<p><strong>CApath</strong>
È il path in cui si trovano le CA con cui stunnel valida i certificati che gli vengono presentati. Se lo stunnel è in server mode, sarà la fullchain realtiva ai client. Altrimenti sarà la fullchain relativa al server.</p>

<p><strong>verifyPeer</strong>
Se con <strong>CAfile</strong> e <strong>CApath</strong> si verifica la fullchain dei certificati presentati a stunnel, con <strong>verifyPeer = yes</strong> si verifica che questi certificati siano presenti anche nel suo keystore (<strong>CAfile</strong> o <strong>CApath</strong>). Permette di “legare” a stunnel i certificati che dovrà validare.</p>

<p><strong>checkEmail</strong>, <strong>checkHost</strong>, <strong>checkIP</strong>
Come per <strong>verifyPeer</strong>, sono direttive che permettono di stringere il legame fra il certificato che viene presentato e stunnel.
Verifica che l’email, il CN o l’IP del certificato che viene presentato corrispondano a quelli presenti nella configurazione.
In una configurazione lato server posso avere molteplici occorrenze di questi due campi relative ad altrettanti certificati. Il caso in cui ad es. si debbano autenticare n client.</p>

<p>Se i certificati sono self-signed, <strong>verifyChain</strong> perde di significato (coinciderebbe con <strong>verifyPeer</strong>). La possibilità di generare i certificati attraverso una CA, anche interna, renderebbe il processo più strutturato anche se più complesso (si dovrà trovare un modo per distribuire la CA, se interna). Si tratta di trovare il giusto compromesso fra ampiezza del servizio (quanti utenti coinvolge?) e complessità richiesta.</p>

<p>Se si tratta di realizzare un canale sicuro fra due apparati per una comunicazione server-2-server, vanno bene anche i certificati self-signed o un’autenticazione PSK. Altrimenti, soprattutto nel caso in cui l’autenticazione dei client è una fase critica, conviene valutare l’uso di una CA e una validazione il più possibile restrittiva sui client e sul server.</p>

<h3 id="autenticazione-psk">Autenticazione PSK</h3>

<p>A differenza dell’autenticazione con certificato, l’autenticazione con PSK non prevede enhancement di sicurezza ulteriori a meno di specificare opportuni algoritmi di cifratura (cfr. paragrafo successivo).</p>

<h3 id="cifratura">Cifratura</h3>

<p>Come sempre succede, negli scenari di cifratura asimmetrica orientatia alla connessione, l’autenticazione, per quanto possa essere accurata, costituisce solo uno degli aspetti di cui tenere conto nella fase di messa in sicurezza del servizio.</p>

<p>Avere un’autenticazione con certificato generato con tutti i crismi da una CA, è certamente una gran cosa ma mette in sicurezza solo l’aspetto dell’autenticazione, per l’appunto.</p>

<p>l transito dei dati è affidato alle suite di cifratura supportati da openssl e, volendo lavorare di fino, bisognerebbe stringere anche su quelli.</p>

<p>Altrimenti, paradossalmente, si avrà un’autenticazione robustissima ma con algoritmi colabrodo di cifratura dei dati che, ad attaccanti ben motivati, lascerebbero delle porte spalancate per sferrare attacchi MITM per intercettare direttamente i dati, piuttosto che provare il furto di identità.</p>

<p>Ad ogni modo, il default, per ragioni di compatibilità legacy, dei parametri di cifratura (da settare eventualmente su client e sul server) è il seguente:</p>

<pre><code>ciphers: HIGH:!aNULL:!SSLv2:!DH:!kDHEPSK
ciphersuites: TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256
</code></pre>

<p>dove <strong>ciphers</strong> raggruppa le suite di cifratura relativi a TLS1.2 in giù e <strong>ciphersuites</strong> riguarda invece TLS1.3.</p>

<h3 id="configurazione-servizio">Configurazione servizio</h3>

<p>Ulteriori restrizioni possono essere aggiunte a livelllo di sistema:</p>
<ol><li>regolando i bit di <strong>setuid</strong> e <strong>setgid</strong> se stunnel gira come root</li>
<li>delimitando l’esecuzione del processo in una gabbia <strong>chroot</strong></li>
<li>disabilitando le <em>regonetiation</em> (se supportato dalla versione di openssl in uso) che mitiga in parte attacchi dos di tipo CPU-exhaustion</li>
<li>ecc..</li></ol>

<h2 id="caso-reale-tunnelizzare-transmission">Caso reale: tunnelizzare Transmission.</h2>

<p><strong>Transmission</strong> è un client <strong>bittorrent</strong> che può essere controllato da remoto via <strong>rpc</strong> attraverso un’interfaccia web o altri client.</p>

<p>Transmission, nelle sue varie declinazioni, non incapsula il traffico rpc in una connessione tls.</p>

<p>Se si vuole che il dato in transito sia cifrato e che la connessione sia autenticata, si può ricorrere:</p>
<ol><li>ad un tunnel ssh;</li>
<li>all’intermediazione di un webserver come apache o nginx ;</li>
<li>ad uno stunnel server</li></ol>

<p>Sugli ultimi due punti si può configurare una mutua autenticazione con certificato (complessa e articolata e, per tanti client, ha un impatto significativo). Scegliamo il 3° caso.</p>

<h2 id="esposizione-dell-interfaccia-web">Esposizione dell’interfaccia web</h2>

<p><strong>Scenario</strong>: abbiamo una macchina (il nostro serverino di fiducia o un nas) con transmission a bordo, presumibilmente dietro un firewall che natta il suo indirizzo privato (192.168.70.15).</p>

<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/42a8ecf32-5a8865/xP2UKA4QZMkK/OVVicpId7etadviBPtZUKHscaXrzy4vlaZAWAoBn.png" alt="Transmission Stunnel">
<small>Esposizione transmission attraverso stunnel server</small></p>

<p><strong>Obiettivo</strong>: Vogliamo poter raggiungere transmission e vogliamo che i client autentichino la loro connessione prima di accedere al servizio. In base allo scenario, sappiamo che dovremmo configurare un port forwarding dall’AP fino allo stunnel server. Il server transmission rimarrà confinato nella nostra rete locale.</p>

<h2 id="utilizzo-di-un-client-esterno">Utilizzo di un client esterno</h2>

<p>Supponiamo di utilizzare diversi client: il browser, <strong>transmission-remote-gtk</strong> o <strong>transmission-remote-gui</strong> (<em>transgui</em>), <strong>tremotesf</strong> (mobile).</p>

<p>La prima cosa da fare è configurare un port forwarding sul nostro AP</p>

<p>    Rule<sub>1</sub>: <strong>9091</strong> ⇒ 192.168.70.10:<strong>9091</strong></p>

<p>Dopodichè, configureremo stunnel in server mode davanti a transmission</p>

<pre><code>[transmission]
accept = 192.168.70.10:9091
connect = 192.168.70.15:9091
cert = &lt;path stunnel conf&gt;/ssl/server/certs/stunnel_crt.pem
key = &lt;path stunnel conf&gt;/ssl/server/private/stunnel_key.pem
requireCert = yes
verifyChain = yes
verifyPeer = yes
CApath = &lt;path stunnel conf&gt;/ssl/client/certs
</code></pre>

<p><strong>Alcune note sulla configurazione</strong>:</p>
<ul><li>devo disporre di un certificato per stunnel</li>
<li>devo disporre dei certificati per i client che si connetteranno, le cui fullchain dovranno essere localizzate nel path indicato da CApath</li></ul>

<p>A questo punto basta che i web-client puntino all’host pubblico (151.25.77.205) sulla porta 9091 e il gioco è fatto.</p>

<p>Per gli altri client come <strong>transmission-remote-gtk</strong>, <strong>transgui</strong> o <strong>tremotesf</strong>, per i quali al massimo posso chiedere di usare TLS (ma non sono riuscito ad usare un’autenticazione lato client), conviene installare stunnel in client mode :</p>

<pre><code>[transmission-client]
accept = localhost:9091
connect = 151.25.77.205:9091
client = yes
cert = &lt;path stunnel conf&gt;/ssl/client/laptop_crt.pem
key = &lt;path stunnel conf&gt;/ssl/client/laptop_key.pem
verifyChain = yes
verifyPeer = yes
CAPath = &lt;path stunnel conf&gt;/ssl/server/certs
</code></pre>

<p>Il client (ad es. sul laptop) si connetterà su localhost:9091 e dovrà disporre anche del certificato del server e della sua fullchain affinchè i check su <strong>verifyChain</strong> e <strong>verifyPeer</strong> non falliscano.</p>

<p><a href="/aytin/tag:ca" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ca</span></a> <a href="/aytin/tag:DigitalCertificate" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">DigitalCertificate</span></a> <a href="/aytin/tag:AsymmetricEncryption" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">AsymmetricEncryption</span></a> <a href="/aytin/tag:SymmetricEncryption" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">SymmetricEncryption</span></a> <a href="/aytin/tag:cryptography" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cryptography</span></a> <a href="/aytin/tag:fullchain" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">fullchain</span></a> <a href="/aytin/tag:psk" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">psk</span></a> <a href="/aytin/tag:ssh" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ssh</span></a> <a href="/aytin/tag:ssl" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ssl</span></a> <a href="/aytin/tag:stunnel" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">stunnel</span></a> <a href="/aytin/tag:tls" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">tls</span></a> <a href="/aytin/tag:x509" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">x509</span></a> <a href="/aytin/tag:openssl" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">openssl</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/stunnel-cose-e-come-si-configura</guid>
      <pubDate>Sat, 04 Mar 2023 15:16:09 +0000</pubDate>
    </item>
  </channel>
</rss>