Il servizio parte, il log si lamenta che non riesce ad aprire il dispositivo tun, e le rotte non compaiono mai. Eseguite capsh --print nella vostra shell e cap_net_admin è proprio lì, il che rende il guasto impossibile. Ciò che differisce tra la vostra shell e l'unità è la transizione dei privilegi, non la volontà del kernel di concedere la capacità. Percorrete i quattro controlli qui sotto in ordine e fermatevi al primo che spiega la differenza.

Separare una capacità mancante da un dispositivo nascosto

Due guasti sembrano uguali dalla riga di log. Un processo senza CAP_NET_ADMIN non può creare o configurare l'interfaccia del tunnel, e un processo il cui sandbox nasconde /dev/net/tun non può aprirla affatto. Aggiungere capacità non risolverà il secondo caso.

Controllate se il dispositivo esiste nello spazio dei nomi del servizio prima di modificare qualsiasi cosa. PrivateDevices=yes è una riga di irrobustimento comune che rimuove del tutto il nodo tun, e un ProtectSystem restrittivo può rendere il percorso di configurazione in sola lettura in un modo che si legge come un errore di permessi. Entrambi producono righe di log che menzionano il tunnel, ed è per questo che si dà la colpa alle capacità. Confermate prima che il nodo sia presente e apribile, poi proseguite.

Sapere quale insieme di capacità state guardando

Linux mantiene gli insiemi permesso, effettivo, ereditabile, limite e ambiente, e l'insieme ambiente è quello che sopravvive a un exec da parte di un utente non root. Le capacità di file sul binario possono trasferire diritti permessi ed effettivi all'exec, ma solo finché nulla nella catena blocca quel trasferimento.

È qui che sudo trae in inganno. Un comando eseguito tramite sudo -u avvia una nuova transizione di privilegi e l'insieme ambiente sparisce, quindi lo stesso controllo che riesce come root fallisce lì. Il gestore dei servizi è un'altra transizione ancora, e non concede nulla di ambiente se l'unità non lo dice.

Concedete la capacità nell'unità, non in un wrapper

Una sezione di servizio minima per un tunnel che deve creare un dispositivo e installare rotte si legge così.

[Unit]
Description=OpenVPN client, office profile
After=network-online.target

[Service]
Type=notify
User=openvpn
Group=openvpn
NoNewPrivileges=yes
AmbientCapabilities=CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_ADMIN
ExecStart=/usr/sbin/openvpn --config /etc/openvpn/office.conf

AmbientCapabilities mette il diritto nell'insieme ambiente prima che il processo parta, e CapabilityBoundingSet impedisce al processo di tenere qualcosa fuori da quella lista. NoNewPrivileges=yes blocca l'ottenimento di privilegi tramite setuid o capacità di file, mentre la capacità che l'unità concede esplicitamente vale ancora. Aggiungete CAP_NET_BIND_SERVICE solo quando il servizio deve legare una porta bassa, e non aggiungete mai CAP_SYS_ADMIN solo perché un thread di forum lo ha fatto.

Se l'unità avvolge il binario in sudo, rimuovete il wrapper. systemd applica già User=, e quello strato extra è il motivo più probabile per cui l'insieme ambiente è vuoto.

Verificate sul processo vivo, non sul file dell'unità

Leggete cosa ha applicato davvero il gestore, poi leggete il processo che ha generato.

unit=openvpn-client@office
systemctl show -p User -p AmbientCapabilities "$unit"
systemctl show -p MainPID --value "$unit" | xargs -r getpcaps
grep -E '^Cap(Eff|Amb)' /proc/$(systemctl show -p MainPID --value "$unit")/status

Se l'unità elenca la capacità e CapEff ancora non ce l'ha, un drop-in sta scavalcando l'impostazione o un passo ExecStartPre sta cambiando l'ambiente. Cercate il nome dell'unità nelle directory drop-in prima di dare per scontato che il file principale faccia fede, perché un file successivo vince in silenzio. Se sia l'unità sia il processo mostrano la capacità e il tunnel fallisce ancora, tornate ai controlli di dispositivo e percorso invece di allargare l'insieme limite. Allargarlo nasconde la causa reale e lascia il servizio più privilegiato di prima.

Preferite cedere i privilegi dopo l'avvio

OpenVPN può partire con privilegi e poi scendere a un account senza privilegi tramite le proprie opzioni user e group, con persist-key e persist-tun che mantengono il tunnel utilizzabile dopo. Questa disposizione restringe la finestra in cui il processo detiene diritti, e spesso si adatta meglio che avviare l'intero demone senza privilegi con capacità permanenti.

Qualunque modello scegliate, riavviate l'unità e ripetete i controlli dopo un riavvio, perché un servizio che funziona da una shell root interattiva e fallisce all'avvio è di solito una differenza di capacità, dispositivo o permessi di file. Annotate le impostazioni dell'unità accanto all'output delle capacità del processo, così il prossimo revisore vede se un aggiornamento di pacchetto o un drop-in ha spostato il confine.

Articoli correlati