Modificare le regole del firewall in ESXi

Dopo una certa esperienza maturata nell’ambito della virtualizzazione con Linux e KVM/QEMU, ho voluto iniziare a cimentarmi con VMware ESXi 6.7. In realtà non è proprio una novità in quanto già diversi anni fa avevo fatto uso di VMware versioni Workstation (su piattaforma Windows) e Server (su piattaforma Linux).

Come quasi sempre accade quando si affrontano nuovi sistemi, dobbiamo innanzitutto impararne le peculiarità e scontrarsi con i suoi limiti. In questo articolo mi voglio soffermare proprio su uno di questi, ovvero quella della persistenza delle modifiche. Infatti, quelle effettuate tramite shell a basso livello sui file di configurazione, vengono perse ad ogni riavvio del sistema. Ciò è dovuto alla particolare struttura di ESXi ove il file-system viene caricato su RAM e solo una parte di essa viene manutenuta sul disco di boot.

Così succede che per aggiungere una banale regola del firewall come quella di aprire in uscita la porta SMTP (TCP 25) occorre lavorare manualmente sulla configurazione in quanto l’interfaccia web non te lo permette di fare (puoi solo modificare quelle esistenti). In rete ho trovato diverse guide ma non abbastanza chiare in quanto la soluzione cambia da una versione all’altra. Io sono riuscito a rendere persistente la modifica sul mio ESXi 6.7 seguendo questi passaggi. Accetto suggerimenti se esistono soluzioni più eleganti.

Creazione della regola

Per prima cosa occorre creare la regola. Quelle predefinite si trovano nel file /etc/vmware/firewall/services.xml. Alcuni ti suggeriscono di aggungere le tue modifiche in questo file. Io ho preferito adottare una strada leggermente diversa che consiste nell’aggiungere un nuovo file che definisce la regola.

Ho creato così il file /etc/vmware/firewall/smtp.xml:

<ConfigRoot>
  <service id="1000">
    <id>SMTP_Outbound</id>
    <rule>
      <direction>outbound</direction>
      <protocol>tcp</protocol>
      <porttype>dst</porttype>
      <port>25</port>
    </rule>
    <enabled>true</enabled>
    <required>false</required>
  </service>
</ConfigRoot>

Ho riavviato il firewall, sempre da riga di comando:

[root@dellpet440:~] esxcli network firewall refresh

Quindi ho verificato sull’interfaccia web la mia regola appena creata:

Come rendere le modifiche persistenti

Senza entrare troppo nel merito di come funziona ESXi (lo devo ancora capire meglio anch’io) per rendere questa modifica persistente, occorre creare un archivio compresso, contenente il nostro file, che verrà scompattato automaticamente dal sistema ad ogni avvio.

Così ho creato l’archivio compresso smtpfw.tgz contenente il file smtp.xml e l’ho registrato nella cache di boot con l’apposito comando:

[root@dellpet440:~] tar -czvf smtpfw.tgz /etc/vmware/firewall/state.xml
[root@dellpet440:~] BootModuleConfig.sh --add=smtpfw.tgz

Possiamo verificare se l’archivio è stato copiato correttamente nella cache:

[root@dellpet440:~] ls -la /bootbank/smtpfw.tgz
-rwx------ 1 root root 1887 Mar 28 08:54 /bootbank/smtpfw.tgz

Possiamo anche verificare se l’archivio verrà correttamente scompattato all’avvio:

[root@dellpet440:~] cat /bootbank/boot.cfg 
bootstate=0
title=
timeout=5
prefix=
kernel=b.b00
kernelopt=installerDiskDumpSlotSize=2560
modules=jumpstrt.gz --- useropts.gz --- features.gz --- k.b00 --- chardevs.b00 --- user.b00 --- procfs.b00 --- uc_intel.b00 --- uc_amd.b00 --- vmx.v00 --- vim.v00 --- sb.v00 --- s.v00 --- ata_liba.v00 --- ata_pata.v00 --- ata_pata.v01 --- ata_pata.v02 --- ata_pata.v03 --- ata_pata.v04 --- ata_pata.v05 --- ata_pata.v06 --- ata_pata.v07 --- block_cc.v00 --- bnxtnet.v00 --- brcmfcoe.v00 --- char_ran.v00 --- ehci_ehc.v00 --- elxiscsi.v00 --- elxnet.v00 --- hid_hid.v00 --- i40en.v00 --- iavmd.v00 --- igbn.v00 --- ima_qla4.v00 --- ipmi_ipm.v00 --- ipmi_ipm.v01 --- ipmi_ipm.v02 --- iser.v00 --- ixgben.v00 --- lpfc.v00 --- lpnic.v00 --- lsi_mr3.v00 --- lsi_msgp.v00 --- lsi_msgp.v01 --- lsi_msgp.v02 --- misc_cni.v00 --- misc_dri.v00 --- mtip32xx.v00 --- ne1000.v00 --- nenic.v00 --- net_bnx2.v00 --- net_bnx2.v01 --- net_cdc_.v00 --- net_cnic.v00 --- net_e100.v00 --- net_e100.v01 --- net_enic.v00 --- net_fcoe.v00 --- net_forc.v00 --- net_igb.v00 --- net_ixgb.v00 --- net_libf.v00 --- net_mlx4.v00 --- net_mlx4.v01 --- net_nx_n.v00 --- net_tg3.v00 --- net_usbn.v00 --- net_vmxn.v00 --- nhpsa.v00 --- nmlx4_co.v00 --- nmlx4_en.v00 --- nmlx4_rd.v00 --- nmlx5_co.v00 --- nmlx5_rd.v00 --- ntg3.v00 --- nvme.v00 --- nvmxnet3.v00 --- nvmxnet3.v01 --- ohci_usb.v00 --- pvscsi.v00 --- qcnic.v00 --- qedentv.v00 --- qfle3.v00 --- qfle3f.v00 --- qfle3i.v00 --- qflge.v00 --- sata_ahc.v00 --- sata_ata.v00 --- sata_sat.v00 --- sata_sat.v01 --- sata_sat.v02 --- sata_sat.v03 --- sata_sat.v04 --- scsi_aac.v00 --- scsi_adp.v00 --- scsi_aic.v00 --- scsi_bnx.v00 --- scsi_bnx.v01 --- scsi_fni.v00 --- scsi_hps.v00 --- scsi_ips.v00 --- scsi_isc.v00 --- scsi_lib.v00 --- scsi_meg.v00 --- scsi_meg.v01 --- scsi_meg.v02 --- scsi_mpt.v00 --- scsi_mpt.v01 --- scsi_mpt.v02 --- scsi_qla.v00 --- shim_isc.v00 --- shim_isc.v01 --- shim_lib.v00 --- shim_lib.v01 --- shim_lib.v02 --- shim_lib.v03 --- shim_lib.v04 --- shim_lib.v05 --- shim_vmk.v00 --- shim_vmk.v01 --- shim_vmk.v02 --- smartpqi.v00 --- uhci_usb.v00 --- usb_stor.v00 --- usbcore_.v00 --- vmkata.v00 --- vmkfcoe.v00 --- vmkplexe.v00 --- vmkusb.v00 --- vmw_ahci.v00 --- xhci_xhc.v00 --- elx_esx_.v00 --- btldr.t00 --- weaselin.t00 --- esx_dvfi.v00 --- esx_ui.v00 --- lsu_hp_h.v00 --- lsu_lsi_.v00 --- lsu_lsi_.v01 --- lsu_lsi_.v02 --- lsu_lsi_.v03 --- native_m.v00 --- qlnative.v00 --- rste.v00 --- vmware_e.v00 --- vsan.v00 --- vsanheal.v00 --- vsanmgmt.v00 --- payload1.v00 --- xorg.v00 --- imgdb.tgz --- state.tgz --- smtpfw.tgz
build=6.7.0-0.0.8169922
updated=4

Da adesso in poi, ogni volta che riavvieremo il nostro server, il sistema scompatterà il nostro file nella giusta posizione, il resto lo farà il firewall che aggiungerà così la regola.

Come tornare indietro

Sarò sufficiente rimuovere la nostra modifica dalla cache di avvio:

[root@dellpet440:~] BootModuleConfig.sh --remove=smtpfw.tgz

e poi riavviare.

Considerazioni finali

Come già detto, questa è stata l’unica soluzione che mi ha permesso di rendere persistente la mia modifica; non credo sia l’unica e neanche la più elegante. Ho anche il dubbio che venga mantenuta in caso di aggiornamento del sistema.

Un’altra possibilità poteva essere quella di modificare direttamente il file services.xml. Per chi desidera procedere in questo modo deve prima prima modificare i permessi così:

[root@dellpet440:~] chmod 644 /etc/vmware/firewall/services.xml
[root@dellpet440:~] chmod +t /etc/vmware/firewall/services.xml

Se il primo comando risulta quasi ovvio, il secondo merita una spiegazione a parte: secondo quanto trovato in rete, i file di configurazione in ESXi sono tutti in sola lettura e se tentate di modificarne uno senza prima abilitare lo sticky bit il sistema vi negherà il salvataggio delle modifiche anche con i permessi in scrittura. Questo perché il sistema salva automaticamente una copia del file originale che verrà poi confrontata con la versione modificata, al fine di creare un file diff che verrà poi applicato in fase di reboot. A me sinceramente non ha funzionato, non sono sicuro se per un qualche mio errore oppure se nella versione 6.7 è stato cambiato qualcosa. Purtroppo quello che si trova in rete è abbastanza datato e fa riferimento alle versioni 4.x o 5.x.

Login remoto via SSH senza password

Per effettuare il login da remoto su un sistema Linux senza digitare ogni volta la password bastano i comandi ssh-keygen e ssh-copy-id e seguire le istruzioni descritte in questo articolo.

ssh-keygen permette di creare le chiavi pubbliche e private, mentre ssh-copy-id copia la chiave publica del client nella lista degli host autorizzati sul server remoto.

1° passo: creare le chiavi pubbliche e private sul client

Per prima cosa creiamo le nostre chiavi pubbliche e private sulla macchina client. Apriamo la console a riga di comando e digitiamo il comando ssh-keygen:

mark@local-host$ [Nota: qui siete nella console del client]
mark@local-host$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/mark/.ssh/id_rsa):[Premere il tasto Enter]
Enter passphrase (empty for no passphrase): [Premere il tasto Enter]
Enter same passphrase again: [Premere il tasto Enter]
Your identification has been saved in /home/mark/.ssh/id_rsa.
Your public key has been saved in /home/mark/.ssh/id_rsa.pub.
The key fingerprint is:
33:b3:fe:af:95:95:18:11:31:d5:de:96:2f:f2:35:f9
mark@local-host

2° passo: copiare la cave pubblica sul server remoto

A questo punto copiamo la chiave pubblica appena creata sul server remoto tramite il comando ssh-copy-id:

mark@local-host$ ssh-copy-id -i ~/.ssh/id_rsa.pub remote-host
mark@remote-host's password: [Inserisci la password del server remoto seguito dal tasto Enter]
Now try logging into the machine, with "ssh 'remote-host'", and check in:
.ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.

3° passo: login sul server remoto

Non ci resta che effettuare il login sul server remoto senza che ci venga richiesta la password di accesso:

mark@local-host$ ssh remote-host
Last login: Sun Nov 16 17:22:33 2008 from 192.168.1.2
[Nota: SSH non richiederà di inserire la password.]
mark@remote-host$ [Nota: adesso sei nel prompt del server remoto]

Come cercare la posizione geografica di un indirizzo IP dalla riga di comando

Se si desidera cercare la posizione geografica di un indirizzo IP esistono diversi servizi online, come ad esempio Geo IP Tool. Tra questi è possibile provare il servizio ipinfo.io. A differenza di altri, ipinfo.io fornisce API di geolocalizzazione basate su JSON, quindi puoi facilmente cercare la geolocalizzazione dalla riga di comando, usando strumenti come curl.

Per esempio:

$ curl ipinfo.io/216.58.205.163

{
"ip": "216.58.205.163",
"hostname": "mil04s28-in-f3.1e100.net",
"city": "Mountain View",
"region": "California",
"country": "US",
"loc": "37.4192,-122.0570",
"postal": "94043",
"org": "AS15169 Google LLC"
}

Homebrew vs MacPorts

Homebrew e MacPorts sono due diversi package manager che permettono di installare programmi e altri tool a riga di comando per estendere le funzionalità del sistema operativo.

Al momento Homebrew sembra essere il più popolare, grazie anche a un numero sostanzioso di pacchetti disponibili e costantemente aggiornati. La posizione predefinita in cui li installa è basata sull’utente, quindi i programmi possono essere eseguiti senza utilizzare una password “sudo” e questo è sicuramente la critica più grande dei puristi Unix. Homebrew utilizza anche più dipendenze fornite di serie con macOS, il che significa in sostanza che è più integrato con il sistema operativo, o almeno così dicono i suoi sostenitori. Il rovescio della medaglia è che molte di queste dipendenze potrebbero diventare presto obsolete: Apple infatti sembra prediligere software BSD non sempre aggiornato ma più testato. Inoltre potrebbe decidere di non includere qualcosa di queste dipendenze nella prossima versione o in un aggiornamento. In questo caso il software brew potrebbe smettere di funzionare e si dovrà procedere con una reinstallazione da zero.

I fan di Macports diranno che è stato quello per lungo tempo ha beneficiato del supporto di Apple e probabilmente lo è ancora. I pacchetti disponibili sono più numerosi, tuttavia non sono aggiornati quanto lo sono quelli di Homebrew. A quanto pare, a detta di alcuni, i ports impiegano poco più di un paio di giorni per aggiornare il pacchetto all’ultima versione.
Quando si installa un pacchetto, MacPorts lo mette in una posizione centrale ed è necessario utilizzare una password “sudo”. Per questi motivi MacPorts incontra il favore di molti utenti Unix. Un altro punto a suo favore è che non dipende da nessuna delle librerie fornite con macOS stesso perché scarica e installa le proprie. Il lato positivo è che i pacchetti Macports non sono così influenzati dagli aggiornamenti software di Apple e non si affidano a nessuna libreria di sistema obsoleta e preinstallata. Il rovescio della medaglia è che ti ritrovi due versioni diverse di certe librerie e dipendenze, occupando così più spazio sul disco.

La domanda su quale dei due sistemi sia il migliore non ha una ancora ricevuto una risposta valida per tutti. Entrambi hanno vantaggi e svantaggi: Homebrew è il più popolare in questo momento e il suo numero di pacchetti è in costante aumento, ma MacPorts sembra essere il più sicuro quando si tratta di installazioni e aggiornamenti. Molti sviluppatori scelgono di averli installati entrambi, così che se non riesci a trovare quello che ti serve su uno, usi l’altro.

Abilitare il web server su macOS

Nelle versioni precedenti del sistema operativo targato Apple c’era la possibilità di abilitare il web server integrato con un semplice click dal pannello Condivisione nelle Preferenze di Sistema. All’interno della propria Home vi era la cartella Siti dove si potevano creare le proprie  pagine html oppure php.

Purtroppo nelle versioni più recenti di macOS hanno tolto questa possibilità nonostante il web server Apache sia ancora presente. Ma per abilitarlo occorre armeggiare a basso livello dal Terminale.

Per primo apriamo il file /etc/apache2/httpd.conf con un editor di testo:

$ sudo nano /etc/apache2/httpd.conf

e modifichiamo la riga 177:

#LoadModule php7_module libexec/apache2/libphp7.so

in

LoadModule php7_module libexec/apache2/libphp7.so

Modifichiamo anche la riga 178 per abilitare il modulo Perl:

#LoadModule perl_module libexec/apache2/mod_perl.so

in

LoadModule perl_module libexec/apache2/mod_perl.so

Ora abilitiamo il modulo per i siti web personali alla riga 174:

#LoadModule userdir_module libexec/apache2/mod_userdir.so

in

LoadModule userdir_module libexec/apache2/mod_userdir.so

Modifichiamo anche la riga 511:

#Include /private/etc/apache2/extra/httpd-userdir.conf

in

Include /private/etc/apache2/extra/httpd-userdir.conf

Salviamo tutto e chiudiamo l’editor. Riapriamolo di nuovo per modificare il file /private/etc/apache2/extra/httpd-userdir.conf:

$ sudo vi /etc/apache2/extra/httpd-userdir.conf

e modifichiamo la riga 16:

#Include /private/etc/apache2/users/*.conf

in

Include /private/etc/apache2/users/*.conf

Salviamo anche queste modifiche e usciamo.

Se non esiste, creiamo la cartella Siti nella nostra home:

$ mkdir ~/Sites
$ echo "<html><body><h1>My site works</h1></body></html>" > ~/Sites/index.html.en

Adesso assicuriamoci dell’esistenza del file di configurazione relativo alla nostra home e se non esiste creiamolo:

$ sudo vi /etc/apache2/users/<your short user name>.conf

Assicuriamoci che il suo contenuto sia così:

<Directory "/Users/<your short user name>/Sites/">
AddLanguage en .en
AddHandler perl-script .pl
PerlHandler ModPerl::Registry
Options Indexes MultiViews FollowSymLinks ExecCGI
AllowOverride None
Require host localhost
</Directory>

Adesso verifichiamo la correttezza della configurazione scrivendo il comando:

$ apachectl configtest

e assicuriamoci che ritorni il messaggio:

Syntax OK

Avviamo Apache con il comando:

$ sudo apachectl start

e navighiamo all’url:

http://localhost

Dovremmo vedere qualcosa simile a:

It works!

Poi se ci indirizziamo all’url:

http://localhost/~<nome_breve>

dovremmo invece vedere:

My site works

Adesso occupiamoci di PHP, creando il file info.php:

$ echo "<?php echo phpinfo(); ?>" > ~/Sites/info.php

e proviamolo dal browser andando all’indirizzo:

http://localhost/~<nome_breve>/info.php

Dovremmo vedere tutte le info di configurazione dell’ambiente PHP.

Facciamo una cosa simile per Perl:

$ echo "print \$ENV{MOD_PERL} . qq{\n};" > ~/Sites/info.pl

e proviamolo dal browser andando all’indirizzo:

http://localhost/~<nome_breve>/info.pl

Dovremmo vedere la stringa "mod_perl/2.0.9".