Squid Proxy HA+LB

Qualche tempo fa, mi è stato chiesto di implementare un sistema proxy in alta affidabilità da un mio cliente. Ho notato che in rete non c’e’ un howto per costruire un sistema del genere, allora ho pensato di scrivere qualche nota.

Elenco dei requisiti:

  1. Il sistema proxy non deve avere delle licenze da pagare ne one-shot ne annualmente; insomma, deve essere gratis.
  2. Deve servire circa 150 utenti possibilmente senza rallentamenti anche in caso di failover del primo nodo.
  3. Non deve essere soggetto a sospensione del servizio dovuti a manutenzione (pianificati) o guasti (non pianificati).
  4. Il sistema proxera’ le richieste solo se aderenti ai dati presenti su tre white-list a cura dal personale IT contenenti indirizzi IP, URL e domini.
  5. Deve essere emessa una notifica in caso di down del nodo primario in modo che il personale IT sia a conoscenza che il sistema proxy sta funzionando in maniera degradata.
  6. Il sistema si deve automaticamente ritornare sul nodo MASTER quando il problema su di esse è cessato.
  7. In modalita’ normale sarebbe preferibile che il sistema processi le richieste in parallelo, bilanciando il carico tra le due macchine (active-active e non active-passive)

Briefing

Dunque, la prima cosa da decidere,  il sistema operativo, gratis significa Linux o BSD.. io lavoro da circa vent’anni con Redhat (ora a pagamento) e quindi oggi lavoro con CentOS il quale è basato sugli stessi sorgenti. Non ho trovato in rete un vero HOW-TO sul come fare questo progetto, quindi ho deciso di scriverne uno, in italiano. Per il sistema proxy, non c’e’ tanto da pensare, il cliente ha gia’ le liste in formato testo adatte a squid, qundi direi che il sistema proxy è squid. Inoltre è un software che c’e’ da sempre (non so se sia nato prima Linux o prima squid) quindi è affidabile e soprattutto open-source. Per quanto riguarda le White-list basta montarle su una share di un file server per avere tre liste sempre aggiornate su entrambi i proxy. Poi mi sono pensato un trucchetto in caso il file server contenente le White-list non fosse disponibile in modo che gli squid continuino a funzionare, su White-list non aggiornate ma continuino ad andare (e si potrebbero anche aggiornare ogni tanto via script). Ora manca un modulo che mi permetta di avere una sorta di alta affidabilità: un modulo che in caso rilevi un problema possa migrare un indirizzo IP sulla macchina secondaria. Keepalived è la mia scelta. Il motivo è che ci ho gia’ lavorato e che mi piace per la sua semplicità. I nodi comunicano tra loro in Multicast e sembra che questo demone sia molto leggero per il sistema. Per fornire il servizio dei proxy active-active ho pensato che HAPROXY potrebbe fornirmi il necessario. L’idea è stata di mettere in ascolto HAPROXY su qualsiasi IP della macchina linux su porta 3128 porta classica di Squid, e inoltrare in modalità tcp le richieste ai due Squid presenti sulle due macchine, controllando che siano attivi via istruzione check effettuato da HAPROXY. Ovviamente ho dovuto modificare la porta di ascolto degli Squid. Quindi in modalità normale, ovvero quando tutto è correttamente funzionante, la macchina MASTER invia tramite HAPROXY le richieste dei client ad entrambi gli Squid in modaità round-robin che per le sessioni http sembra sia la migliore strategia.

Il sistema operativo

Lavoro da un mare di tempo con CentOS e non mi viene proprio voglia di cambiare, quindi i due nodi saranno due linux box con CentOS V7.5. Finita l’installazione io ho effettuato le seguenti personalizzazioni:

  1. Disabilitato Selinux
  2. Installato net-tools – Per avere ifconfig
  3. Installato procps – Per avere killall che serve a keepalive
  4. Disabilitato e rimosso dall’autostart Firewalld
  5. Impostato in /etc/sysctl.conf la linea “net.ipv4.ip_nonlocal_bind = 1” che serve per ascoltare anche su ip che non esistono sulla macchina.

Keepalived

Ci sono diversi sistemi per avere una coppia di Linux box ad alta affidabilita’, ma io sono di quelli che “cavallo che vince non si cambia”: ho gia’ lavorato con keepalived e quindi implemento cio’ che conosco. Secondo me semplice come configurazione e si installa facilmente perché è di ‘serie’ su CentOS, ti basta fare:

[root@nodo1 ~]# yum install keepalived

# cat /etc/keepalived/keepalived.conf
global_defs {
  enable_script_security
  script_user root
  notification_email {
gbiondi@tech2.it
  }
  notification_email_from node1@tech2.it
  smtp_server localhost
  smtp_connect_timeout 30
}

vrrp_script chk_squid {
   script “/usr/bin/killall -0 squid”      # verify the pid existance
   interval 2                     # check every 2 seconds
   weight 2                       # add 2 points of prio if OK
}

vrrp_script chk_haproxy {
   script “/usr/bin/killall -0 haproxy”      # verify the pid existance
   interval 2                     # check every 2 seconds
   weight 2                       # add 2 points of prio if OK
}

vrrp_instance VI_1 {
   interface eth0                # interface to monitor
   state MASTER
   virtual_router_id 54          # Assign one ID for this route
   priority 101                  # 101 on master, 100 on backup
   advert_int 1
   smtp_alert
   virtual_ipaddress {
        10.12.14.140              # the virtual IP
   }
   track_script {
       chk_squid
       chk_haproxy
   }
}

In sostanza si vedono bene i due ‘vrrp_script’ che controllano che i due processi siano UP e il ‘vrrp_instance’ che è il cuore di keepalived. Questo è lo script del MASTER, quindi quando si sveglia si mette come MASTER e si autoassegna un priorita’. Si assegna un ‘router_id’ che serve al demone per comunicare con l’altro nodo via unicast. Inoltre quando deve operare perché qualcosa è andato storto (non vede l’altro nodo) ci avvisa via smtp. Il resto non credo che ci sia bisogno di spiegazioni. Allego anche lo script del secondo nodo per completezza:

global_defs {
  enable_script_security
  script_user root
  notification_email {
gbiondi@tech2.it
  }
  notification_email_from node2@tech2.it
  smtp_server localhost
  smtp_connect_timeout 30
}

vrrp_script chk_squid {
   script “/usr/bin/killall -0 squid”      # verify the pid existance
   interval 2                     # check every 2 seconds
   weight 2                       # add 2 points of prio if OK
}

vrrp_script chk_haproxy {
   script “/usr/bin/killall -0 haproxy”      # verify the pid existance
   interval 2                     # check every 2 seconds
   weight 2                       # add 2 points of prio if OK
}

vrrp_instance VI_1 {
   interface  eth0               # interface to monitor
   state BACKUP
   virtual_router_id 54          # Assign one ID for this route
   priority 100                  # 101 on master, 100 on backup
   advert_int 1
   smtp_alert
   virtual_ipaddress {
       10.12.14.140               # the virtual IP
   }
   track_script {
       chk_squid
       chk_haproxy
   }
}

HAProxy

Il demone HAProxy è il responsabile per il bilanciamento di carico dei proxy Squid. Esso riceve le richieste dei client su porta 3128 (ho scelto questa porta in quanto tutti sono abituati al fatto che se c’e’ un proxy Squid questo ascolta su questa porta) e inoltra le sessioni sui proxy Squid attivi in quel momento. Il demone conosce il proxy attivo il quanto effettua un check su entrambi i proxy Squid in modo da esere a conoscenza su quale Squid inoltrare le richieste. Il demone HAProxy è in grado di inoltrare migliaia di sessioni senza avere problemi di performance, leggete la documentazione e i test che sono stati effettuati su questo software se siete curiosi. Allego i file di configurazione dei due HAProxy montati sulle due macchine linux: i due file sono uguale su entrambe le macchine linux. Precisiamo che in questo particolare caso ci limitamo ad avere ‘solo’ due proxy Squid, ma si potrebbe aggiungere altre macchine linux, queste con i solo demone Squid configurato, per avere un cluster con un parallelismo maggiore di due. Si potrebbe avere altre due macchine linux con Squid montato e utilizzare quattro Squid per servire i nostri utenti.

global
daemon
maxconn 256
defaults
mode tcp
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms

frontend squid_frontend
bind *:3128

default_backend squid_backend
backend squid_backend
server node1 10.12.14.141:8001 check
server node2 10.12.14.142:8001 check
# Add more IPs here as required
balance roundrobin

listen stats # Define a listen section called “stats”
bind :9000 # Listen on localhost:9000
mode http
stats enable # Enable stats page
stats hide-version # Hide HAProxy version
stats realm Haproxy\ Statistics # Title text for popup window
stats uri /haproxy_stats # Stats URI
stats auth amin:paperina # Authentication credentials

Squid

Proxy Squid. Squid è un proxy che conosciamo tutti: chi ha messo in pista una macchina proxy con linux lo ha fatto con Squid. E’ robusto, e’ mantenuto aggiornato, e’ gratis e funziona, non c’e’ bisogno di provare qualcosa d’altro. Nel nostro sistema proxy, viene usato molto semplicemente con delle white-list, c’e’ un minimo di configurazione da fare ma la cosa piu’ importate è il cambio di porta di ascolto, nel nostro caso da 3128 viene modificata in 8001. Poi c’e’ il discorso delle white-list ma non mi pare che sia un argomento da trattare.. non ci interessa l’autenticazione, ma anche qui si trova tutto in rete. Invece voglio dirvi come ho fatto a fare in modo che, se per caso la share che condivide le white-list non fosse disponibile ,il sistema comunque continui a funzionare. Ho semplicemente copiate le white-list interessate nella directory /mnt/wl – certo che nel momento del problema non saranno aggiornate, ma sempre meglio che rimanere senza che su un sistema che lavora in white list significa non navigare piu’ da nessuna parte… e poi si potrebbe fare in modo via script che ogni giorno venga smontata la share, copiate le whitelist e rimontata la share..

Conclusioni

Il sistema sta funzionando correttamente, per ora non sono stati riscontrati disservizi, purtroppo non è sottoposto ad un carico pesantissimo, i due nodi sfiorano carico ‘1’ negli ultimi 5 minuti solo all’inizio delle ore mattutine e pomeridiane