Archivi categoria: Computer

Articoli che riguardano i computer: software, hardware e modi d’utilizzo.

Samba, SSSD e SELinux su Red Hat

Di recente ho dovuto installare un server Red Hat Enterprise Linux 7, si tratta di una macchina che ospita un database Oracle, ma mi è stato chiesto di attivare anche alcune condivisioni tramite samba. Ho fatto tutti i passaggi consueti per l’installazione e configurazione, ma non funzionava nulla. Dopo due giorni di lavoro ho sistemato la macchina, superando vari ostacoli. Elenco qui i problemi più grossi e le relative soluzioni.

Autenticazione

La macchina è stata messa in dominio Windows per poter accettare connessioni dai computer aziendali. Per farlo è stato installato il server SSSD che permette l’integrazione con il dominio Windows e la mappatura di utenze e gruppi di dominio. Samba è stato configurato copiando il tutto da un’altra macchina, SunOS, che ospitava precedentemente le cartelle di rete. Quel samba usava Winbind per l’integrazione con il dominio, sicché anche qui è stato usato winbind.
Nelle utenze sul dominio Windows non sono presenti userid e groupid come su Linux, sicché tutti i programmi di interfaccia con il dominio fanno una mappatura che parte dal SID dell’utenza Windows e arrivare a userid e groupid di Linux. Ovviamente per un determinato utente la mappatatura deve essere sempre eguale, sicché questa associazione viene memorizzata in un file. Il file è diverso se si usa SSSD o se si usa Winbind. Ma la cosa che non sapevo è che anche l’algoritmo di mappatura è diverso, quindi quando samba riceve una richiesta di connessione, effettua l’autenticazione con Kerberos e poi mappa il SID dell’utenza Windows su una utenza locale, che però qui non veniva trovata. L’errore era:

[2022/12/22 10:37:04.668145, 1] ../../source3/auth/token_util.c:561(add_local_groups)
SID S-1-5-21-990198401-320236572-313593124-1040 -> getpwuid(11040) failed

in effetti l’utenza in questione aveva un uid diverso: 1092201040 anziché 11040

[linux]# id 'azienda\nome.utente'
uid=1092201040(nome.utente@azienda.dom) gid=1092200513(domain users@azienda.dom) gruppi=1092200513(domain users@azienda.dom)

mentre sul vecchio server era proprio 11040:

[SunOS] # id 'azienda\nome.utente'
uid=11040(AZIENDA\nome.utente) gid=10513(AZIENDA\domain users)

Per sistemare questa cosa ci sono due diverse possibilità. La più diffusa, ma secondo me peggiore, è di fare usare winbind anche a NSS, cambiando le tre righe nel file /etc/nssswitch.conf da

passwd: files sss
group: files sss
shadow: files sss

a

passwd: files winbind
group: files winbind
shadow: files winbind

la seconda è di cambiare l’algoritmo usato da SSSD per generare userid e groupid. Questo si fa nel file /etc/sssd/sssd.conf, dove, per il dominio in questione, ci sarà scritto che il backend è proprio il dominio tramite la configurazione id_provider=ad. Questo vuol dire che si possono usare anche le configurazioni di sssd-ad come quella che ci interessa: ldap_idmap_autorid_compat. Il valore predefinito è false, ma se viene aggiunta al file di configurazione e impostata a true, risolve il problema.

Una volta fatto questo, l’autenticazione dovrebbe cominciare a funzionare.

Accesso al file system

Quando si accede tramite samba, l’utenza sulla quale si viene mappati deve avere l’accesso alle directory e ai file da utilizzare. Se, ad esempio, la condivisione utilizza la directory /s6/work1/samba, allora sarà necessario che l’utente possa arrivarci. Per farlo è necessario che la directory e quelle padre, cioè /s6, /s6/work1 e /s6/work1/samba abbiano tutte i bit “r” e “x” accesi, cioè che siano leggibili (“r”) e che ci si possa spostare in quella directory (“x”).

Una volta fatto questo, si ottiene ancora l’errore:

[2022/12/22 12:23:30.517028, 0] ../../source3/smbd/service.c:784(make_connection_snum)
make_connection_snum: canonicalize_connect_path failed for service CARTELLA, path /s6/work1/samba

Questo perché è attivo SELinux. Quando samba lavora su un sistema con SELinux è necessario fare alcune operazioni in più:

indicare che la directory in questione deve essere accessibile a samba per una condivisione. Questo si fa con la policy samba_share_t. Il comando da usare per fare una prova è;

[linux]# chcon --recursive --type samba_share_t /s6/work1/samba

mentre quelli per rendere il tutto permanente sono;

[linux]# semanage fcontext --add --type samba_share_t "/s6/work1/samba(/.*)?"
[linux]# restorecon -R -v /s6/work1/samba/

Per verificare che il tutto abbia funzionato, date il comando:

[linux]# ls -ldZ /s6/work1/samba/ /s6/work1/ /s6/
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /s6/
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /s6/work1/
drwxrwxrwx+ root root unconfined_u:object_r:samba_share_t:s0 /s6/work1/samba/

A questo punto samba potrà accedere a quella directory e ai file ivi contenuti senza che SELinux la blocchi. Ma, se cercate di collegarvi ottenete ancora lo stesso errore:

[2022/12/22 14:05:14.602571, 0] ../../source3/smbd/service.c:784(make_connection_snum)
make_connection_snum: canonicalize_connect_path failed for service CARTELLA, path /s6/work1/samba

Ora però il problema è un altro, sempre legato a SELinux: ci sono delle attività che sono completamente inibite in samba a meno di attivare tramite la configurazione di SELinux. Perché sia possibile condividere una qualsiasi directory in lettura va usato il parametro samba_export_all_ro, perché sia possibile farlo anche in scrittura va usato il parametro samba_export_all_rw. I due si attivano in questo modo:

[linux]# setsebool -P samba_export_all_ro=1 samba_export_all_rw=1
[linux]# getsebool -a| grep samba
samba_create_home_dirs --> off
samba_domain_controller --> off
samba_enable_home_dirs --> off
samba_export_all_ro --> on
samba_export_all_rw --> on
samba_load_libgfapi --> off
samba_portmapper --> off
samba_run_unconfined --> off
samba_share_fusefs --> off
samba_share_nfs --> off
sanlock_use_samba --> off
tmpreaper_use_samba --> off
use_samba_home_dirs --> off
virt_use_samba --> off
[linux]# systemctl restart smb nmb winbind

A questo punto tutto dovrebbe funzionare.

grub: grub_file_filters not found

Qualche giorno fa uno dei computer dell’ufficio non si è acceso per bene: è partito grub2 e ha dato l’errore grub_file_filters not found.
Internet è decisamente prolifica nel trovare situazioni analoghe, ma per lo più si tratta di narrazioni di troubleshooting, senza indicare esattamente quali siano il problema e la soluzione.

E allora diciamolo chiamaramente: il problema è che la versione di grub scritta nell’MBR, cioè dentro il disco, non corrisponde a quella dei moduli presenti in /boot/grub. Questo può succedere per vari motivi: nel mio caso avevo installato grub sull’MBR di tutti i dischi del server (per poter fare il boot anche in caso di guasto di un disco), ma non avevo configurato correttamente questa cosa in debconf, sicché dopo gli aggiornamenti di grub, solo l’MBR del disco principale era stato aggiornato, lasciando gli altri MBR con la vecchia versione di grub. Questo era successo perché il sistema era stato installato con un solo disco e poi ampliato con gli altri. Appena si è rotto il disco principale, il BIOS ha letto grub dal secondo disco, grub ha caricato i moduli dalla directory /boot/grub che era su un RAID, ma la versione non combaciava.

La soluzione è quella di avere sempre grub allineato: ogni volta che si aggiorna il pacchetto si deve riscrivere grub su tutti i dischi dove è stato installato. Per farlo si può semplicemente riconfigurare grub con il comando

dpkg-reconfigure grub-pc

Linux Day 2022 a Torino

Il 22 ottobre 2022 sono stato al Linux Day di Torino, dove ho tenuto un intervento su come vengono memorizzati i dati (file, directory, device, raid, LVM). Non ho avuto modo di seguire molti altri interventi perché è stata un’occasione per rivedere di persona alcune persone che bene o male gravitano attorno al mondo Linux e all’open source in genere.

Lascio qui la presentazione in formato PDF; qui la presentazione HTML.

Opzioni di barman per il ripristino di un database PostgreSQL

La documentazione di barman non è sempre semplice da consultare, quindi aggioungo qui alcune note relative al comando di ripristino.

Creazione del file system per il ripristino, su macchina nomehost, aggiornato con tutti i WAL: barman recover --remote-ssh-command 'ssh postgres@nomehost' nome-master backup-id /path/destinazione/su/nomehost

Creazione del file system per il ripristino, su macchina nomehost, che verrà aggiornato con tutti i WAL scaricati all’avvio di postgres. Il comando per scaricare i WAL dal server barman è nel file recovery.conf: barman recover --remote-ssh-command 'ssh postgres@nomehost' --get-wal nome-master backup-id /path/destinazione/su/nomehost

Creazione del file system per il ripristino, su macchina nomehost, che verrà configurato come standby (che rimarrà sempre in recovery, attendendo sempre nuovi WAL). Il comando per la configurazione è nel file recovery.conf: barman recover --remote-ssh-command 'ssh postgres@nomehost' --standby-mode nome-master backup-id /path/destinazione/su/nomehost

Creazione del file system per il ripristino, su macchina nomehost, che verrà configurato come standby e messo in attesa per potervvi accedere. Il comando per la configurazione è nel file configurato come standby. Il comando per la configurazione è nel file recovery.conf: barman recover --remote-ssh-command 'ssh postgres@nomehost' --standby-mode --target-action pause nome-master backup-id /path/destinazione/su/nomehost

Creazione del file system per il ripristino, su macchina nomehost, aggiornato con tutti i WAL fino a data e orario specifico. La directory barman_wal conterrà i WAL necessari, il file recovery.conf i comandi necessari per il PITR: barman recover --remote-ssh-command 'ssh postgres@nomehost' --target-time '2022-06-15 16:58' nome-master backup-id /path/destinazione/su/nomehost

Per fare poi ripartire il database in modalità standby, nel caso che la versione di postgresql sia 12 o superiore, il file recovery.conf non viene usato e, anzi, blocca l’avvio di postgresql. I comandi vanni presi da quel file e integrati nel file postgresql.conf principale (dettagli qui).

Altra cosa importante: per fare ripartire postgresql (12 o superiore) in modalità recovery deve esistere il file chiamato standby.signal. In caso negativo, il cluster non partirà in maniera recovery, ma si aprirà normalmente alle connessioni in lettura e scrittura.

Appunti su come creare una CA e un certificato server con il KeyTool di Java

Queste sono note veloci da sistemare, ma possono già aiutare eventualmente altri, quindi le pubblico qui. Per semplicità la password dei keystore e delle chiavi è sempre la stessa, ma in alcuni casi deve essere veramente la stessa, ad esempio quando si deve usare il keystore generato in un connettore di Apache Tomcat.

Le cose importanti da notare sono: il certificato della CA deve avere il BasicConstraint che indica che è una CA. Non si tratta di un vincolo tecnico, ma i browser potrebbero poi non accettarlo come affidabile. Il certificato del server deve avere il KeyUsage corretto, altrimenti anche lui potrebbe essere scartato. Il comando per la generazione del certificato iniziale del server avrà quindi varie -ext .... per aggiungere le estensioni, che dovranno essere ricopiate identiche nel punto dell’emissione del certificato per il server da parte della CA.

  • Creazione di chiave privata e certificato radice per l’autorità, valido 7350 giorni (circa 20 anni). Questo viene messo nel keystore predefinito di java, nella home dell’utente, in un file chiamato .keystore e protetto da una password relativamente semplice. Il comando è: keytool -alias root -dname "CN=RootCA, OU=La mia unità organizzativa, O=La mia società, L=La mia località, ST=La mia provincia, C=IT" -genkeypair -storetype PKCS12 -storepass fs35623_WE -keypass fs35623_WE -keyalg RSA -keysize 4096 -validity 7350 -ext BasicConstraints=ca:true,PathLen:2 -ext KeyUsage=digitalSignature,keyEncipherment,keyCertSign -ext ExtendedKeyUsage=serverAuth,clientAuth
  • Creazione di chiave privata e certificato radice per il server, valido 7350 giorni (circa 20 anni). Questo viene messo nel keystore chiamato server.pfx e protetto da una password relativamente semplice. Il comando è: keytool -alias server -dname "cn=server.example.com, OU=La mia unità organizzativa, O=La mia società, L=La mia località, ST=La mia provincia, C=IT" -genkeypair -storetype PKCS12 -storepass fs35623_WE -keystore server.pfx -keypass fs35623_WE -keyalg RSA -keysize 4096 -validity 7300 -ext SAN=DNS:server.example.com -ext ExtendedKeyUsage=serverAuth -ext KeyUsage=digitalSignature,keyEncipherment
  • Copia temporanea del certificato della CA dal keystore predefinito di java a quello nel quale c’è il certificato del server. Il comando è: keytool -export -alias root -storetype PKCS12 -storepass fs35623_WE | keytool -import -alias root -storetype PKCS12 -keystore server.pfx -storepass fs35623_WE -noprompt -trustcacerts
  • Generazione della richiesta di firma del serve del certificato, che viene poi passata al comando per l’emissione del certificato da parte della CA, che viene poi passato al keystore origiario per essere memorizzato. Il comando è: keytool -alias server -certreq -storetype PKCS12 -storepass fs35623_WE -keyalg RSA -keystore server.pfx | keytool -alias root -gencert -storetype PKCS12 -storepass fs35623_WE -keyalg RSA -ext SAN=DNS:server.example.com -ext ExtendedKeyUsage=serverAuth -ext KeyUsage=digitalSignature,keyEncipherment -validity 7300 | keytool -alias server -importcert -storetype PKCS12 -storepass fs35623_WE -keyalg RSA -keystore server.pfx -noprompt -trustcacerts
  • Rimozione del certificato della CA dal keystore del server. Il comando è: keytool -delete -alias root -storetype PKCS12 -keystore server.pfx -storepass fs35623_WE
  • Esportazione del certificato della CA in un file, da importare nei sistemi che dovranno considerarlo affidabile. Il comando è: keytool -export -alias root -storetype PKCS12 -storepass fs35623_WE -rfc > root.pem