Due ricette di minimo privilegio incollate insieme non producono un dispiegamento più severo. Un modello lascia che il demone parta con privilegi e scenda a un account senza privilegi dopo l'inizializzazione; l'altro fa avviare il servizio dal gestore con un'identità limitata fin dalla prima istruzione. Ognuno funziona da solo, e la combinazione produce spesso un servizio che non sa fare bene nessuno dei due compiti. Il resto di questo testo percorre la decisione in ordine.

Due modelli, un solo proprietario del passaggio

Il primo modello appartiene al demone. Le opzioni OpenVPN della versione community user e group cambiano identità dopo che tunnel e chiavi sono impostati, e persist-key insieme a persist-tun mantengono quelle risorse utilizzabili in seguito.

Il secondo modello appartiene al gestore dei servizi. Un'impostazione systemd User= o Group= decide l'identità con cui parte il processo, e le direttive sulle capacità decidono cosa può detenere. Scegliere tra i modelli è una questione di packaging prima che di sicurezza, e il manutentore del pacchetto ha già risposto. Il vostro compito è trovare quella risposta invece di inventare una terza opzione.

Entrambi sono legittimi. L'errore è trattarli come strati di un unico progetto, perché il secondo modello può rendere il cambio di identità del primo un'operazione che al processo non è più consentito eseguire.

Decidete dove cambia l'identità

Se l'unità parte già come account dedicato, aggiungere un'istruzione del demone per diventare un altro account richiede una transizione setuid che un servizio indurito non avrebbe mai dovuto fare. Il guasto appare come errore di permesso all'avvio invece che come messaggio di policy chiaro. Si legge come una capacità mancante, il che spinge la gente verso un insieme di limiti più ampio invece che verso la questione dell'identità.

Leggete cosa fornisce davvero il pacchetto installato prima di modificare qualcosa, compresa la sua directory drop-in. Alcune unità omettono deliberatamente il passaggio proprio del demone perché il gestore se ne occupa già, e altre si affidano a quelle opzioni per il cambio dopo l'inizializzazione. Rimuovere l'una o l'altra senza sapere quale modello avete ereditato è il modo in cui un servizio funzionante smette di avviarsi.

Scrivete il modello scelto in una riga: di proprietà del gestore o del demone. Ogni direttiva successiva deve essere coerente con quella frase, e un'unità mista va trattata come un difetto e non come un compromesso.

Le capacità sono limiti, non concessioni

Un insieme di limiti di capacità dice cosa un processo può detenere al massimo. È un tetto, e elencarvi una capacità non concede nulla di per sé, perciò un'unità con un insieme di limiti generoso può comunque non riuscire a creare un tunnel.

Ciò che mette davvero una capacità nell'insieme ambientale di un servizio è AmbientCapabilities=. Il riferimento di esecuzione di systemd documenta le due direttive separatamente, e questa distinzione spiega la maggior parte dei consigli confusi sulle capacità che si trovano online.

Aggiungete una capacità solo dopo che l'operazione che fallisce l'ha identificata. Un insieme di limiti più ampio nasconde la causa reale e lascia il servizio più privilegiato di quanto il progetto intendesse. Rende anche l'unità più difficile da rivedere, perché il tetto non descrive più il lavoro. Rimuovete la capacità extra una volta corretto il difetto reale.

Mappate l'autorità lungo il ciclo di vita

Elencate cosa deve fare il processo in ogni fase: avvio, stato stabile, riautenticazione e smontaggio. La creazione dell'interfaccia, le modifiche di rotta, la lettura di una chiave protetta e l'invocazione di un helper non avvengono tutte nello stesso momento né con gli stessi requisiti. Ordinate l'elenco per fase prima di ordinarlo per capacità.

Le opzioni di persistenza conservano risorse attraverso la rinegoziazione, e non concedono permessi che non sono mai stati detenuti. Una chiave che il processo non può leggere all'avvio resterà illeggibile anche dopo, qualunque cosa dicano i flag di persistenza. I flag conservano ciò che già funzionava.

Usate un account dedicato invece di uno condiviso. Gli sviluppatori di OpenVPN mettono in guardia dall'abitudine di usare nobody come esempio generico, perché altri servizi sull'host potrebbero già girare con quell'account e l'isolamento che credete di avere non c'è.

Le funzioni che cambiano il carico locale, come l'offload del canale dati o una build che collega in modo diverso, possono spostare quali operazioni servono. Rivedete la mappa quando cambia il pacchetto, non solo quando qualcosa si rompe.

Scrivete il piano e conservate l'accesso di ripristino

Un registro di dispiegamento dovrebbe nominare il gestore, l'identità di avvio, l'identità stabile prevista e ogni concessione con l'operazione che la richiede. È quel registro che rende rivedibile il cambiamento successivo invece che sperimentale.

Tenete disponibile l'accesso alla console mentre modificate, perché un'unità che fallisce all'avvio è difficile da riparare da remoto. Provate un riavvio e un riavvio completo prima di dichiarare concluso il cambiamento. Un'unità che sopravvive a un riavvio può comunque fallire prima che la rete sia attiva.

Il successo è un ciclo di vita di autorità minima compreso, non un processo che per caso gira sotto un nome diverso da root.

Articoli correlati