Un container LXC non privilegiato con un bind mount mostra spesso file e cartelle intestati a nobody:nogroup, anche quando sull'host i permessi sembrano corretti. Non è un difetto di Proxmox: dipende da come il kernel traduce gli identificatori utente tra container e host. Capire il meccanismo permette di scegliere con cognizione tra due soluzioni, il calcolo dei permessi sull'host e la mappatura personalizzata con lxc.idmap, ciascuna con compromessi di sicurezza diversi.
Container privilegiati e non privilegiati
In un container privilegiato gli identificatori coincidono con quelli dell'host: il root del container è il root dell'host e, in caso di evasione, a limitare i danni restano solo i meccanismi di isolamento (namespace, AppArmor, capabilities). In un container non privilegiato il kernel usa uno user namespace: l'intervallo di UID e GID visto dal container è traslato in un intervallo diverso sull'host, così il root del container è un utente senza privilegi sull'host.
Su Proxmox VE la traslazione predefinita parte da 100000 e copre 65536 identificatori, come dichiara la voce root:100000:65536 in /etc/subuid e /etc/subgid. La regola è UID host = 100000 + UID container.
| Utente nel container | UID nel container | UID sull'host |
|---|---|---|
| root | 0 | 100000 |
| www-data | 33 | 100033 |
| primo utente creato | 1000 | 101000 |
| nobody | 65534 | 165534 |
Il kernel verifica i permessi con gli ID dell'host: il container ne vede soltanto una traduzione. Un ID senza corrispondenza nel namespace compare come 65534 (nobody), ed è ciò che si osserva con un bind mount quando la cartella appartiene a un ID dell'host fuori dall'intervallo mappato, per esempio 1000. Rinunciare al container non privilegiato per aggirare il problema sposta il rischio sull'host: conviene correggere i permessi, non l'isolamento.
Il bind mount
Un bind mount espone una directory dell'host dentro il container. Per il container 101:
pct set 101 -mp0 /tank/dati,mp=/mnt/datiLa forma generale è pct set <vmid> -mp0 /percorso/host,mp=/percorso/container. Il comando aggiunge la riga mp0: /tank/dati,mp=/mnt/dati a /etc/pve/lxc/101.conf; il punto di mount è attivo dal successivo avvio del container. Alcune regole:
- La directory deve esistere sull'host e, in un cluster, su ogni nodo in cui il container può essere avviato o migrato (si veda Cluster Proxmox VE a tre nodi).
- Non si montano directory di sistema come
/,/varo/etc: la documentazione le indica come un rischio serio per l'host. - Il contenuto dei bind mount non è incluso nei backup di
vzdump: i dati vanno protetti a parte, come descritto in Strategia di backup 3-2-1 con Proxmox Backup Server.
Calcolare i permessi sull'host
Con la mappatura predefinita basta intestare la directory all'ID dell'host che corrisponde all'utente del container. Per l'UID e il GID 1000:
chown -R 101000:101000 /tank/datiLa verifica si fa con gli ID numerici, perché i nomi dipendono dal namespace in cui vengono risolti.
ls -ln /tank/datipct exec 101 -- ls -ln /mnt/dati-rw-r--r-- 1 101000 101000 0 Apr 8 10:00 nota.txt-rw-r--r-- 1 1000 1000 0 Apr 8 10:00 nota.txtIl metodo non richiede modifiche alla configurazione del container. Il limite è che sull'host i dati risultano intestati a un ID insolito: è scomodo se la stessa directory è condivisa con altri servizi, per esempio Samba o NFS, o se i file esistono già con un altro proprietario. Per impostazione predefinita tutti i container non privilegiati usano lo stesso intervallo, quindi un bind mount condiviso tra più container mostra ovunque gli stessi ID.
Mappatura personalizzata con lxc.idmap
Quando i file hanno già un proprietario reale sull'host, si può lasciare che un singolo ID attraversi il namespace senza traslazione: l'UID 1000 del container diventa l'UID 1000 dell'host, mentre tutti gli altri restano traslati. Per ogni tipo (u per gli UID, g per i GID) servono tre intervalli, che devono coprire da 0 a 65535 senza lacune né sovrapposizioni.
lxc.idmap = u 0 100000 1000
lxc.idmap = g 0 100000 1000
lxc.idmap = u 1000 1000 1
lxc.idmap = g 1000 1000 1
lxc.idmap = u 1001 101001 64535
lxc.idmap = g 1001 101001 64535Ogni riga ha la forma lxc.idmap = <tipo> <primo ID nel container> <primo ID sull'host> <quantità>. Qui gli ID da 0 a 999 vanno a 100000-100999, l'ID 1000 resta 1000 e gli ID da 1001 a 65535 vanno a 101001-165535: 1000 + 1 + 64535 fa 65536.
LXC avvia il container come root e applica la mappatura con newuidmap e newgidmap, che accettano solo gli ID delegati all'utente in /etc/subuid e /etc/subgid. La voce predefinita copre 100000-165535, quindi a root va delegato anche l'ID 1000.
echo 'root:1000:1' >> /etc/subuid
echo 'root:1000:1' >> /etc/subgidIl formato è utente:primo-id:quantità. Senza queste voci il container non si avvia e l'errore cita newuidmap o newgidmap; per diagnosticare conviene avviarlo in primo piano con lxc-start -F -n 101. La mappatura viene letta a ogni avvio, quindi il container va riavviato.
pct shutdown 101
pct start 101Attenzione
Mappare un ID senza traslazione riduce l'isolamento: un processo che gira come UID 1000 nel container agisce sull'host come UID 1000, con accesso a tutto ciò che quell'utente può leggere o scrivere, non solo alla directory condivisa. Conviene mappare un ID riservato allo scopo, per esempio un account di servizio dell'host senza shell di login, e non quello di un utente reale. L'ID dell'host non deve coincidere con quello del container: basta sostituire il secondo numero delle righe u 1000 1000 1 e g 1000 1000 1 (e le voci in subuid e subgid) con l'ID scelto, purché fuori dall'intervallo 100000-165535.
Importante
In un container già in uso, i file del suo filesystem che appartengono all'ID rimappato (per esempio la home dell'utente 1000, salvata su disco come 101000) risultano nobody dopo la modifica: Proxmox non li riallinea. Conviene applicare la mappatura a un container nuovo oppure correggere la proprietà dall'host a container fermo.
Suggerimento
Se più container devono solo condividere una directory, spesso basta mappare un GID e lavorare con i permessi di gruppo (directory con bit setgid e g+rwX): gli UID restano traslati e nessun utente dell'host viene esposto.
Nota
La documentazione delle versioni più recenti di Proxmox VE (serie 9.x) descrive anche un'opzione idmap per il singolo punto di mount, che evita di rimappare l'intero container. Conviene controllare che la versione in uso la supporti; lxc.idmap resta valido su Proxmox VE 8 e 9.
Verificare la mappatura
pct exec 101 -- cat /proc/self/uid_map 0 100000 1000
1000 1000 1
1001 101001 64535Il controllo definitivo consiste nel creare un file dal container e leggerne il proprietario numerico sull'host.
pct exec 101 -- su -s /bin/sh -c 'id && touch /mnt/dati/prova' utente-esempio
ls -ln /tank/dati/provauid=1000(utente-esempio) gid=1000(utente-esempio) groups=1000(utente-esempio)
-rw-r--r-- 1 1000 1000 0 Apr 8 10:05 provaCon la mappatura personalizzata l'UID è 1000 su entrambi i lati; con quella predefinita sull'host sarebbe 101000. Per una diagnosi rapida:
- Proprietario
nobodynel container: l'ID dell'host non rientra nell'intervallo mappato. - Container che non parte dopo la modifica: voce mancante in
subuidosubgid, oppure intervalli che non sommano 65536. - Permesso negato con gli ID corretti: controllare i permessi delle directory superiori; con i bind mount nei container non privilegiati le ACL non sono utilizzabili.