Continuando con la serie degli spazi dei nomi, questo articolo copre il PID spazio dei nomi. Se vuoi una panoramica generale di tutti gli spazi dei nomi, dai un'occhiata al primo articolo. In precedenza, hai creato un nuovo mnt spazio dei nomi. È interessante notare che, come hai scoperto, anche dopo aver creato un nuovo mnt namespace, avevi ancora accesso agli ID di processo (PID) dell'host originale. Quando hai provato a montare /proc namespace, hai ricevuto il permesso negato piuttosto sconcertante errore, come mostrato di seguito:
root@new-mnt$ mount -t proc proc /procmount:permesso negato (sei root?)root@new-mnt$ whoamiroot
Sebbene tu possa creare tutti i tipi di montaggio nel nuovo spazio dei nomi di montaggio, non puoi interagire o modificare /proc . In questo articolo, passo attraverso il PID namespace e dimostra come puoi usarlo, insieme a mnt namespace, per proteggere ulteriormente il tuo contenitore alle prime armi.
[ Ai lettori è piaciuto anche: Come funzionano gli spazi dei nomi PID di Linux con i container ]
Cosa sono gli ID processo?
Prima di entrare direttamente nel PID namespace, penso che sia una buona idea fornire solo un po' di background sul motivo per cui questo spazio dei nomi è importante.
Quando un processo viene creato sulla maggior parte dei sistemi operativi simili a Unix, gli viene assegnato uno specifico identificatore numerico chiamato ID processo (PID). Questo PID aiuta a identificare un processo in modo univoco anche se sono presenti due processi che condividono lo stesso nome leggibile. Ad esempio, se ci sono più sessioni ssh attive su un sistema ed è necessario chiudere una connessione specifica, il PID fornisce all'amministratore un modo per assicurarsi che la sessione corretta sia chiusa.
Tutti questi processi sono tracciati in uno speciale file system chiamato procfs
. Sebbene questo file system possa tecnicamente essere montato ovunque, la maggior parte degli strumenti (e delle convenzioni) si aspettano i procfs
da montare sotto /proc
. Se fai un elenco di /proc
, vedrai una cartella per ogni processo attualmente in esecuzione sul tuo sistema. All'interno di questa cartella ci sono tutti i tipi di file speciali utilizzati per tenere traccia di vari aspetti del processo. Ai fini di questo articolo, questi file non sono importanti. È sufficiente sapere che /proc
è dove la maggior parte dei sistemi simili a Unix memorizza le informazioni relative ai processi su un sistema in esecuzione.
Lo spazio dei nomi PID
Uno dei motivi principali del PID namespace serve a consentire l'isolamento del processo. Più precisamente, come dice la pagina man:
Gli spazi dei nomi PID isolano lo spazio dei numeri ID del processo, il che significa che i processi in spazi dei nomi PID diversi possono avere lo stesso PID.
Questo è importante perché significa che è possibile garantire che i processi non abbiano un PID in conflitto con qualsiasi altro processo. Quando si considera un singolo sistema, ovviamente, non vi è alcuna possibilità che i PID siano in conflitto perché il sistema incrementa continuamente il numero ID del processo e non assegna mai lo stesso numero due volte. Quando si ha a che fare con contenitori su più macchine, questo problema diventa più importante. Come descritto nella pagina man:
Gli spazi dei nomi PID consentono ai contenitori di fornire funzionalità come la sospensione/ripresa dell'insieme di processi nel contenitore e la migrazione del contenitore su un nuovo host mentre i processi all'interno del contenitore mantengono gli stessi PID.
A parte l'isolamento, il sistema PID funziona quasi identica a quella al di fuori dello spazio dei nomi. Gli ID di processo all'interno del nuovo spazio dei nomi iniziano da 1 , con il primo processo considerato init processi. L'inizializzazione il processo viene gestito in modo molto diverso da tutti gli altri PID su un host. Ciò ha implicazioni particolari per il sistema in esecuzione che non rientrano nell'ambito di questa serie. Se sei interessato a maggiori informazioni, consulta la sezione "Segnali e processo di inizializzazione" dell'articolo Spazi dei nomi LWN.
Ciò che è degno di nota, tuttavia, è che qualunque processo abbia PID 1 è vitale per la longevità dei namespace. Se PID 1 viene terminato per qualsiasi motivo, il kernel invierà un SIGKILL
a tutti i processi rimanenti nello spazio dei nomi, chiudendo di fatto lo spazio dei nomi.
Esplorazione degli spazi dei nomi PID
Se ti stai chiedendo, come me, se puoi annidare PID namespace, la risposta è sì. In effetti, il kernel fa spazio a un massimo di 32 PID nidificati spazi dei nomi. Questa è considerata una relazione a senso unico. Ciò significa che il genitore può vedere i PID di figli, nipoti, ecc. Tuttavia, non può vedere nessuno dei PID dei suoi antenati. Considera quanto segue:
[utente@localhost ~] sudo unshare -fp /bin/bash[root@localhost ~] sleep 90000 &[root@localhost ~] ps -efUID PID PPID C STIME TTY TIME CMD[troncato ].. ...root 11627 11620 0 09:16 pts/0 00:00:00 sudo unshare -fp /bin/bashroot 11633 11627 0 09:17 pts/0 00:00:00 unshare -fp /bin/bashroot 1 0 4 1 3 0 4 09:17 pts/0 00:00:00 /bin/bashroot 11639 11634 0 09:17 pts/0 00:00:00 sleep 90000root 11641 11634 0 09:17 pts/0 0 0 :00:[ps root @localhost ~] sudo unshare -fp /bin/bash[root@localhost ~] sleep 8000 &[root@localhost ~] ps -ef[troncato ].....UID PID PPID C STIME TTY TIME CMDroot 11650 11634 0 09 :17 pts/0 00:00:00 sudo unshare -fp /bin/bashroot 11654 11650 0 09:17 pts/0 00:00:00 unshare -fp /bin/bashroot 11655 11654 0 09:17 pts/0: 00:00 /bin/bashroot 11661 11655 0 09:17 pts/0 00:00:00 sonno 8000root 11671 11655 0 09:17 p ts/0 00:00:00 ps -ef
Noterai che ho troncato l'output perché il PID lo spazio dei nomi appare per avere pieno accesso a tutti i PID in /proc
. Osserva cosa succede se tenti di interrompere un processo che si trova in un predecessore:
[root@localhost ~] kill -9 11361bash:kill:(11361) - Nessun processo simile
Perchè è questo? In poche parole, strumenti tradizionali come ps
non sono in grado di riconoscere lo spazio dei nomi e in realtà vengono letti da /proc
directory. Se hai eseguito un ls /proc
, vedresti comunque tutte le cartelle e i file di prima perché, come discusso nell'ultimo articolo, il PID namespace eredita tutto il mnt monta lo spazio dei nomi. Affronterò questa situazione in seguito. Per ora, torna all'esempio in questione.
In un'altra shell, identifica i processi dormienti:
[user@localhost ~] ps -ef |grep sleeproot 11639 11634 0 09:17 pts/0 00:00:00 sleep 90000root 11661 11655 0 09:17 pts/0 00:00:00 sleep 800
Se vuoi verificare che questi processi siano in spazi dei nomi diversi, dovrai trovare il bash
PID di processo. Ricorda, dal momento che hai eseguito sudo unshare -fp /bin/bash
, il bash
processo è l'inizializzazione processo nel nuovo spazio dei nomi. Pertanto, è il PID che verrà collegato all'ID dello spazio dei nomi. Prendiamo i PID:
[root@localhost ~] ps -ef |grep bashroot 11627 11620 0 09:16 pts/0 00:00:00 sudo unshare -fp /bin/bashroot 11633 11627 0 09:17 pts/0 00 :00:00 unshare -fp /bin/bashroot 11634 11633 0 09:17 pts/0 00:00:00 /bin/bashroot 11650 11634 0 09:17 pts/0 00:00:00 sudo unshare -fp /bin/ bashroot 11654 11650 0 09:17 pts/0 00:00:00 unshare -fp /bin/bashroot 11655 11654 0 09:17 pts/0 00:00:00 /bin/bash
Puoi vedere i PID 11634 e 11655 nell'uscita. Se lo confronti con l'output di lsns
(elenca gli spazi dei nomi), vedrai quanto segue:
Come puoi vedere, gli ID dello spazio dei nomi sono diversi e quindi i processi si trovano in spazi dei nomi diversi.
Ora che hai stabilito che gli spazi dei nomi sono effettivamente diversi, diamo un'occhiata all'ascendenza PID menzionata prima. Puoi farlo identificando il NSpid attributo di un dato PID nel /proc
directory, come mostrato di seguito:
sudo cat /proc/11655/status |grep NspidNSpid: 11655 6 1
Le colonne vengono lette da sinistra a destra e indicano il PID nei rispettivi namespace. Il PID più a sinistra è lo spazio dei nomi primario o radice. In questo caso, ha un PID di 11655 , un PID secondario di 6 e un PID terziario di 1 . Poiché gli spazi dei nomi possiedono ogni PID discendente namespace, puoi pensarlo in questo modo:
- Sull'host, il
bash
processo che eseguesleep 8000
comando ha un PID di 11655 . - Dentro il primo "contenitore", il
bash
processo che eseguesleep 8000
comando ha un PID di 6 . - All'interno del secondo "contenitore" nidificato, il PID è 1 . Questo è il contenitore che ha effettivamente avviato il processo.
Ognuno di questi bash
è stato creato all'interno del proprio spazio dei nomi ma è visibile al genitore (in questo caso, il root spazio dei nomi).
/proc, PID e utenti non privilegiati
Il lettore attento avrebbe notato che, negli ultimi due articoli, un utente normale potrebbe creare entrambi gli utente e non spazi dei nomi. In questo articolo, ho utilizzato sudo
comando. Questo perché non puoi creare un PID namespace da solo con un utente senza privilegi. La risposta è combinare più creazioni di spazi dei nomi in un unico evento. Esistono diverse soluzioni per il montaggio di /proc
come utente non privilegiato.
Se provi semplicemente a creare un nuovo utente namespace, otterrai uno strano risultato:
[ user@localhost ~] unshare -Urp-bash:fork:Impossibile allocare memory-bash-5.1# ps -ef-bash:fork:Impossibile allocare memory-bash-5.1# ls-bash:fork:Impossibile allocare memoria
Cosa sta succedendo qui? Ricorda come il primo processo all'interno di un nuovo PID namespace diventa init processi? In questo caso, la shell corrente non può spostare gli spazi dei nomi. Esiste nella radice namespace e quando hai creato un nuovo PID namespace, il sistema non sapeva come gestirlo. La soluzione a questo è avere il fork del processo stesso. Ciò consente alla shell corrente di diventare un processo figlio di unshare
comando. Usando il -f
flag risulta nella creazione dello spazio dei nomi:
[ utente@localhost ~] unshare -Urfp[ root@localhost ~]
Tuttavia, vedi ancora la contaminazione di /proc
punto di montaggio. Ci sono due soluzioni a questo. Innanzitutto, puoi creare un nuovo mnt namespace e quindi rimontare /proc
te stesso:
[ user@localhost ~]$ unshare -Urpmf[ root@localhost ~]# mount -t proc proc /proc[ root@localhost ~]# ps -efUID PID PPID C STIME TTY TIME CMDroot 1 0 0 09:31 pts/0 00:00:00 -bashroot 10 1 0 09:31 pts/0 00:00:00 ps -ef
In effetti, per molti anni questa è stata l'unica opzione, ma un flag --mount-proc
è stato creato qualche tempo fa per farlo in un unico passaggio. La pagina man recita:
Appena prima di eseguire il programma, montare il filesystem proc al punto di montaggio (l'impostazione predefinita è /proc). Ciò è utile quando si crea un nuovo spazio dei nomi PID. Implica anche la creazione di un nuovo spazio dei nomi di montaggio poiché il montaggio /proc altrimenti rovinerebbe i programmi esistenti sul sistema. Il nuovo filesystem proc è esplicitamente montato come privato (con MS_PRIVATE|MS_REC).
Quindi, quindi, potresti vedere riferimenti al seguente comando:
annulla condivisione -Urpf --mount-proc
Questo crea un nuovo mnt namespace durante il montaggio di /proc
per te.
Inserimento di uno spazio dei nomi
Per ridurre la complessità, sono uscito dagli spazi dei nomi creati in precedenza. Ho creato un nuovo spazio dei nomi con il seguente comando:
unshare -Urfp --mount-proc
Ho anche creato un diverso sonno
processo solo per aiutare a identificare lo spazio dei nomi. Dato che ho un solo nuovo spazio dei nomi, posso usare lsns
comando per determinare il PID corretto:
[ user@localhost ~]$ lsns |grep bash4026532965 pid 2 13142 user -bash
Quindi esegui nsenter
comando:
sudo nsenter -t 13142 -a
Il -a
flag dice a nsenter
comando per inserire tutti gli spazi dei nomi di quel PID. sudo
è richiesto con il -a
flag, altrimenti non sarai in grado di passare a tutti gli spazi dei nomi appropriati. Ora dovresti essere in grado di elencare tutti i PIDS in questo NS:
[ Impara le basi dell'uso di Kubernetes in questo cheat sheet gratuito. ]
Conclusione
Il PID lo spazio dei nomi è importante quando si tratta di costruire ambienti isolati. Consente ai processi di avere i propri PID indipendentemente dal sistema host. In un mondo in cui più host possono essere coinvolti nell'orchestrazione di ambienti isolati (container), diventa fondamentale disporre di una struttura che garantisca PID univoci durante il congelamento e la migrazione dei processi. Inoltre, per motivi di sicurezza, se stai eseguendo spazi dei nomi per l'isolamento delle applicazioni, il PID lo spazio dei nomi è fondamentale per prevenire la fuga di informazioni attraverso i processi in esecuzione di un host.
Se combinato con l'utente e non namespace, il PID namespace fornisce una grande protezione senza richiedere i privilegi di root. I browser moderni come Firefox e Vivaldi utilizzano gli spazi dei nomi per fornire il sandbox del browser. Nel prossimo articolo mostrerò la rete namespace e scopri come puoi continuare a costruire il tuo container manualmente aggiungendo componenti di rete discreti.