Iscriviti al nostro blog

Esegui i container come root o come utente normale? Può sembrare una domanda così semplice da far cadere nella tentazione di rispondere troppo velocemente. Hai davvero così chiaro il modello delle minacce? Purtroppo potrebbe non essere così. Facciamo un po' di ordine con questo post.

Prima di poter rispondere alla domanda precedente, bisogna stabilire se stiamo parlando del motore per container (Podman, Docker, CRI-O, containerd, ecc.), del processo all'interno del container (apache, postgresql, mysql, ecc.) o dell'ID di processo a cui è mappato il container (le tre opzioni possono essere diverse). Potrebbe non essere così evidente a un primo sguardo. Il motore per container o il relativo processo secondario nei container possono essere eseguiti praticamente da qualsiasi utente.

Containers illustration Scopri di più su Red Hat Universal Base Image (UBI)

Cos'è l'utente root

Con l'avvento di Podman, i container rootless sono diventati una possibilità concreta. Dal momento che Podman crea i container come processi secondari diretti di se stesso, è semplice dimostrare l'esistenza di quattro opzioni possibili su cui riflettere. Ma cosa significa rootless? Per comprenderlo, bisogna capire cos'è l'utente root all'interno di un container. E per comprendere l'utente root all'interno di un container, bisogna capire cos'è l'utente root all'esterno di un container. Molto bene.

La seguente tabella mostra l'utente root all'interno e all'esterno del container (grazie a Vincent Batts che mi ha illustrato in modo molto chiaro questi concetti in occasione della DevConf.us 2019). Con questo schema dovresti iniziare a farti un'idea del concetto di rootless:

 

Table 1: Root inside and outside the container showing how users appear to the system

Sottolineiamo alcuni aspetti interessanti dell'esempio qui sopra.  Innanzitutto, le opzioni della riga di comando sono -i (interattivo) -t (terminale) e -u (utente): tutte insieme, offrono un terminale interattivo all'interno del container e specificano che il processo containerizzato deve essere eseguito come utente sync. Puoi effettuare ulteriori ricerche al riguardo digitando il comando 'man podman-run'. 

In secondo luogo, presta particolare attenzione a $, che indica l'esecuzione della shell come utente normale, e a # che indica l'esecuzione della shell come root. Queste sono tradizioni di Unix utili per spiegare cos'è l'utente root all'interno e all'esterno del container. 

In terzo luogo, nell'esempio precedente Podman si trova per definizione al di fuori del container e viene eseguito come root o come utente normale (fatherlinux), mentre all'interno del container la bash viene eseguita come root o utente normale (sync). Gli utenti presenti nel file /etc/passwd sul container host vengono utilizzati per Podman, mentre gli utenti presenti nel file /etc/passwd nell'immagine del container vengono utilizzati nel container in esecuzione. In altre parole, questi due file passwd implicano la possibilità di avere due set di utenti: uno all'esterno e l'altro all'interno del container. È proprio questo che semplificano gli spazi dei nomi utente.

Spazi dei nomi utente

Quando il kernel crea un processo in esecuzione all'interno di un container, lo spazio dei nomi utente mappa l'ID utente dei processi containerizzati a un ID utente diverso all'esterno del container. Diamo un'occhiata:

 

Table 2: Showing user IDs and username inside and outside container

Le opzioni della riga di comando sono -i (interattivo) -d (distacca) e -u (utente): tutte insieme, consentono di eseguire il container in background e specificano che il processo containerizzato deve essere eseguito come utente sync. Come indicato in precedenza, puoi effettuare ulteriori ricerche al riguardo digitando il comando man podman-run

Podman offre anche un interessante sottocomando denominato top, che consente di mappare l'utente sul container host all'utente nel container in esecuzione. L'esempio precedente dimostra che, durante l'esecuzione di un container come root, mappiamo l'utente sync (uid 5) nel container all'utente sync (uid 5) sul container host alla base. Di conseguenza, se un processo uscisse da questo container, lo stesso potrebbe essere eseguito con i privilegi dell'utente sync reale. 

Dall'altra parte, quando eseguiamo esattamente lo stesso container come utente normale (fatherlinux), mappa l'utente sync (uid 5) nel container in esecuzione all'uid 100004 sull'host del container alla base. Ma, un momento, perché non ha mappato l'utente sync (uid 5) a fatherlinux (uid 1000)?

Sostanzialmente perché, con i kernel e i pacchetti shadow-utils più recenti (useradd, passwd, ecc.), a ogni nuovo utente viene assegnata e messa a disposizione una serie di ID utente. Tradizionalmente, nei sistemi Unix ciascun utente aveva un solo ID, mentre ora gli utenti hanno a disposizione migliaia di UID da utilizzare all'interno dei container. 

Questo è particolarmente utile quando un container utilizza più utenti, ad esempio con l'esecuzione contemporanea di Apache e MySQL in un singolo container o pod oppure con l'esecuzione di un container sidecar con un agente eseguito come utente diverso. Ma da dove proviene questa mappatura? Da due file: /etc/subuid e /etc/subgid. Quando vengono aggiunti gli utenti in questi file si creano delle voci, tramite il comando usermod o manualmente tramite un amministratore di sistemi.

Approfondimento facoltativo sugli identificativi utente

Ecco un esempio di voci nel mio sistema. Con esse, l'utente fatherlinux può mappare fino a 65.535 ID utente nei container a ID utente reali sul sistema, a partire da 100.000. Per impostazione predefinita, l'utilizzo di shadow-utils (useradd, passwd, ecc.) su questo intervallo di ID utente è riservato a un solo utente. Il comando useradd riserva l'intervallo seguente all'utente successivo. In questo esempio si tratta dell'utente fred, a partire dall'ID utente 165536:

cat /etc/subuid fatherlinux:100000:65536 fred:165536:65536 cat /etc/subgid fatherlinux:100000:65536 fred:165536:65536

Questa mappa è visibile anche all'interno di un container:

 

Table 3: More on users inside and outside the container

Quando Podman viene eseguito come root, nel container è disponibile l'intero intervallo di ID utente (4294967295 == 32 bit). Tuttavia, quando Podman viene eseguito come fatherlinux, mappa l'utente root all'interno del container all'utente fatherlinux (1000) e l'utente sync (uid 5) a un UID nell'intervallo compreso tra 100.000 e 165.535. 

Si tratta di un'eccellente funzionalità di sicurezza, perché ora il motore per container e il processo containerizzato all'interno del container in esecuzione vengono eseguiti come utenti senza privilegi diversi. Il set di ID utente da 100.000 a 165.535 non dispone di privilegi speciali sul sistema, nemmeno come utente fatherlinux (1000), quindi, in caso di interruzione di un processo nel container, verrà severamente limitato sul container host. 

Un'altra domanda sorge spontanea: il sistema può esaurire gli UID se si aggiunge un gran numero di utenti? La risposta è sì, ma è improbabile, considerata la presenza di 4 miliardi di UID rappresentati da un numero a 32 cifre. Ciò significa che è possibile aggiungere a un sistema fino a 65.535 utenti (4294967295 diviso 65535). Tale valore dovrebbe essere sufficiente per la maggior parte degli scenari di utilizzo.

Prendiamo in esame un'ultima sfumatura dei container rootless. Il file /etc/subuid viene utilizzato per mappare l'utente all'interno del container a un utente esterno al container, ma l'utente (fatherlinux nell'esempio seguente) deve essere definito nell'immagine del container, altrimenti Podman non può avviare il container stesso:

podman run --user fatherlinux -it ubi8 bash

Output:

unable to find user fatherlinux: no matching entries in passwd file

Nel container è necessario specificare un ID utente presente nel file /etc/passwd all'interno dell'immagine del container. Questo è un altro esempio del legame intrinseco tra i container e il sistema operativo interno al container e del mantenimento della separazione dal sistema operativo dei container host. I container sono Linux.

Misure di difesa avanzate dei container

Questo concetto non è semplice da capire con il daemon docker per via del modello client-server. Con il modello client-server di docker, è possibile eseguire un container come root anche eseguendo il comando come utente normale, perché il daemon docker viene eseguito come root e quindi dispone di tutti i relativi privilegi. Ora dovrebbe essere molto più chiaro. Per sperimentarlo in prima persona, esegui i seguenti comandi:

 

Table 4: Commands to check user IDs

Per evitare che un utente che esegue un container ottenga l'accesso root all'host, bisogna eseguire il motore per container e il processo containerizzato come utente non root. In questo modo ci si avvale di più livelli di sicurezza tra il servizio (httpd, MySQL, ecc.) e le risorse con privilegi nel sistema operativo. L'esecuzione del motore per container come utente non root costituisce un livello di difesa e l'esecuzione del processo nel container come utente non root diverso ne offre un altro. 

Dan Walsh analizza in modo molto puntuale questo aspetto nell'articolo: Running Rootless Podman as a  non-root User. A livello macroscopico, un motore per container rootless come Podman ti consente di eseguirlo come il tuo account utente. All'interno del container puoi quindi utilizzare un set virtuale di utenti mappato a un set di ID utente controllato soltanto dal tuo account per i processi containerizzati. 

Ora dovresti avere un quadro più chiaro delle possibilità per l'utente root all'interno e all'esterno del container.


Sull'autore

At Red Hat, Scott McCarty is Senior Principal Product Manager for RHEL Server, arguably the largest open source software business in the world. Focus areas include cloud, containers, workload expansion, and automation. Working closely with customers, partners, engineering teams, sales, marketing, other product teams, and even in the community, he combines personal experience with customer and partner feedback to enhance and tailor strategic capabilities in Red Hat Enterprise Linux.

McCarty is a social media start-up veteran, an e-commerce old timer, and a weathered government research technologist, with experience across a variety of companies and organizations, from seven person startups to 20,000 employee technology companies. This has culminated in a unique perspective on open source software development, delivery, and maintenance.

Read full bio

Ricerca per canale

automation icon

Automazione

Le ultime novità sulla piattaforma di automazione che riguardano la tecnologia, i team e gli ambienti

AI icon

Intelligenza artificiale

Aggiornamenti sulle piattaforme che consentono alle aziende di eseguire carichi di lavoro IA ovunque

cloud services icon

Servizi cloud

Maggiori informazioni sul nostro portafoglio di servizi cloud gestiti

security icon

Sicurezza

Le ultime novità sulle nostre soluzioni per ridurre i rischi nelle tecnologie e negli ambienti

edge icon

Edge computing

Aggiornamenti sulle piattaforme che semplificano l'operatività edge

Infrastructure icon

Infrastruttura

Le ultime novità sulla piattaforma Linux aziendale leader a livello mondiale

application development icon

Applicazioni

Approfondimenti sulle nostre soluzioni alle sfide applicative più difficili

Original series icon

Serie originali

Raccontiamo le interessanti storie di leader e creatori di tecnologie pensate per le aziende