Docker e --userns-remap, come gestire le autorizzazioni del volume per condividere dati tra host e container?


96

Nella finestra mobile, i file creati all'interno dei contenitori tendono ad avere una proprietà imprevedibile durante l'ispezione dall'host. Il proprietario dei file su un volume è root (uid 0) per impostazione predefinita, ma non appena gli account utente non root sono coinvolti nel contenitore e scrivono nel file system, i proprietari diventano più o meno casuali dal punto di vista dell'host.

È un problema quando è necessario accedere ai dati del volume dall'host utilizzando lo stesso account utente che sta chiamando i comandi docker.

Le soluzioni alternative tipiche sono

  • forzare gli utenti UID al momento della creazione in Dockerfiles (non portabile)
  • passando l'UID dell'utente host al docker runcomando come variabile di ambiente e quindi eseguendo alcuni chowncomandi sui volumi in uno script entrypoint.

Entrambe queste soluzioni possono fornire un certo controllo sulle autorizzazioni effettive all'esterno del contenitore.

Mi aspettavo che gli spazi dei nomi degli utenti fossero la soluzione finale a questo problema. Ho eseguito alcuni test con la versione 1.10 rilasciata di recente e --userns-remap impostato sul mio account desktop. Tuttavia, non sono sicuro che possa rendere la proprietà dei file sui volumi montati più facile da gestire, temo che possa effettivamente essere l'opposto.

Supponiamo che avvii questo contenitore di base

docker run -ti -v /data debian:jessie /bin/bash
echo 'hello' > /data/test.txt
exit

Quindi ispeziona il contenuto dall'host:

ls -lh /var/lib/docker/100000.100000/volumes/<some-id>/_data/

-rw-r--r-- 1 100000 100000 6 Feb  8 19:43 test.txt

Questo numero "100000" è un sub-UID del mio utente host, ma poiché non corrisponde all'UID del mio utente, non posso ancora modificare test.txt senza privilegi. Questo utente secondario non sembra avere alcuna affinità con il mio utente normale effettivo al di fuori di finestra mobile. Non è mappato indietro.

Le soluzioni alternative menzionate in precedenza in questo post che consistevano nell'allineare gli UID tra l'host e il contenitore non funzionano più a causa della UID->sub-UIDmappatura che si verifica nello spazio dei nomi.

Quindi, esiste un modo per eseguire docker con lo spazio dei nomi utente abilitato (per una maggiore sicurezza), pur consentendo all'utente host che esegue docker di possedere i file generati sui volumi?


Penso che se stai per condividere volumi tra l'host e il contenitore, gli spazi dei nomi utente non faranno parte della soluzione. La tua seconda opzione ("passare l'UID dell'utente host al comando docker run come variabile di ambiente e quindi eseguire alcuni comandi chown sui volumi in uno script entrypoint") è probabilmente la soluzione migliore.
Larsks

4
Docker stesso non sembra incoraggiare l'uso di volumi scrivibili montati su host. Poiché non sto eseguendo un servizio cloud e utilizzo solo le mie immagini affidabili, ora mi chiedo se il vantaggio per la sicurezza dell'utente NS valga la pena sacrificare così tanta comodità.
Stéphane C.

@ StéphaneC. hai trovato forse un approccio migliore?
EightyEight

4
Sfortunatamente no, non usare lo spazio dei nomi utente e passare gli UID dall'host è ancora la mia opzione di scelta. Spero che in futuro ci sarà un modo corretto per mappare gli utenti. Ne dubito, ma tengo gli occhi aperti.
Stéphane C.

Risposte:


46

Se è possibile predisporre in anticipo utenti e gruppi, è possibile assegnare UID e GID in modo specifico in modo che gli utenti host corrispondano agli utenti con spazio dei nomi all'interno dei contenitori.

Ecco un esempio (Ubuntu 14.04, Docker 1.10):

  1. Crea alcuni utenti con ID numerici fissi:

    useradd -u 5000 ns1
    
    groupadd -g 500000 ns1-root
    groupadd -g 501000 ns1-user1
    
    useradd -u 500000 -g ns1-root ns1-root
    useradd -u 501000 -g ns1-user1 ns1-user1 -m
    
  2. Modifica manualmente gli intervalli di ID subordinati generati automaticamente in /etc/subuide /etc/subgidfile:

    ns1:500000:65536
    

    (nota che non ci sono record per ns1-roote ns1-user1dovuti a MAX_UIDe MAX_GIDlimiti in /etc/login.defs)

  3. Abilita spazi dei nomi utente in /etc/default/docker:

    DOCKER_OPTS="--userns-remap=ns1"
    

    Riavvia il demone service docker restart, assicurati che la /var/lib/docker/500000.500000directory sia creata.

    Ora, all'interno dei contenitori hai roote user1, e sull'host ns1-roote ns1-user1, con ID corrispondenti

    AGGIORNAMENTO: per garantire che gli utenti non root abbiano ID fissi nei contenitori (es. User1 1000: 1000), crearli esplicitamente durante la creazione dell'immagine.

Test di guida:

  1. Prepara una directory del volume

    mkdir /vol1
    chown ns1-root:ns1-root /vol1
    
  2. Provalo da un contenitore

    docker run --rm -ti -v /vol1:/vol1 busybox sh
    echo "Hello from container" > /vol1/file
    exit
    
  3. Prova dall'host

    passwd ns1-root
    login ns1-root
    cat /vol1/file
    echo "can write" >> /vol1/file
    

Non è portatile e sembra un hack, ma funziona.


3
Molto interessante e merita un +1. Ma dovresti comunque assicurarti che all'utente1 nella tua immagine sia assegnato l'UID 1000. Altrimenti non puoi essere sicuro che riceverà l'UID 501000 sull'host. A proposito, siamo assolutamente sicuri che la formula sia sempre subUID lower bound + UID in imagese stiamo eseguendo molte immagini diverse con un utente con ID impostato su 1000?
Stéphane C.

@ StéphaneC. Buon punto! Aggiunta una nota sulla correzione degli ID all'interno delle immagini. Per quanto riguarda la formula, sperimenterò ulteriormente con le mie immagini e aggiornerò la risposta se trovo qualcosa
amartynov

1
Se organizzi manualmente utenti e gruppi nell'host e nei contenitori, hai davvero bisogno della funzione "spazio dei nomi utente"?
Tristan

1
Lo spazio dei nomi che crei separa gli utenti degli host dagli utenti del contenitore, ma potresti aver bisogno di più spazi dei nomi per i contenitori, specialmente quando le immagini ufficiali (come quella mysql) creano un utente senza uid esplicito. Come gestisci più spazi dei nomi quando l'opzione --userns-remap ne prevede solo uno?
Tristan

2
@amartynov Posso chiederti perché ti sei preso la briga di specificare un UID (5000) per il tuo utente "ns1"? Poiché è il nome (non l'UID) a cui fai riferimento nei file subuid e subgid, sembra che non dovrebbe importare quale UID ottiene questo utente. Mi manca qualche relazione, come potrebbe suggerire la somiglianza tra 5000 e 500000?
Jollymorphic

2

Una soluzione alternativa consiste nell'assegnare dinamicamente l'UID dell'utente al momento della compilazione in modo che corrisponda all'host.

Esempio Dockerfile:

FROM ubuntu
# Defines argument which can be passed during build time.
ARG UID=1000
# Create a user with given UID.
RUN useradd -d /home/ubuntu -ms /bin/bash -g root -G sudo -u $UID ubuntu
# Switch to ubuntu user by default.
USER ubuntu
# Check the current uid of the user.
RUN id
# ...

Quindi crea come:

docker build --build-arg UID=$UID -t mycontainer .

ed esegui come:

docker run mycontainer

Se hai un contenitore esistente, crea un contenitore wrapper con quanto segue Dockerfile:

FROM someexistingcontainer
ARG UID=1000
USER root
# This assumes you've the existing user ubuntu.
RUN usermod -u $UID ubuntu
USER ubuntu

Questo può essere avvolto docker-compose.ymlcome:

version: '3.4'
services:
  myservice:
    command: id
    image: myservice
    build:
      context: .
    volumes:
    - /data:/data:rw

Quindi crea ed esegui come:

docker-compose build --build-arg UID=$UID myservice; docker-compose run myservice

1
Non vorrei sembrare scortese ma questa è in realtà una delle soluzioni alternative elencate nella domanda originale, ma non una soluzione e non è correlata agli spazi dei nomi utente.
Stéphane C.

@ StéphaneC. Puoi commentare questa domanda correlata? stackoverflow.com/questions/60274418/...
overexchange

-1

È possibile evitare problemi di autorizzazione utilizzando il docker cpcomando .

La proprietà è impostata sull'utente e sul gruppo principale nella destinazione. Ad esempio, i file copiati in un contenitore vengono creati con UID:GIDl'utente root. I file copiati sulla macchina locale vengono creati con UID:GIDil nome dell'utente che ha richiamato il docker cpcomando.

Ecco il tuo esempio passato all'uso docker cp:

$ docker run -ti -v /data debian:jessie /bin/bash
root@e33bb735a70f:/# echo 'hello' > /data/test.txt
root@e33bb735a70f:/# exit
exit
$ docker volume ls
DRIVER              VOLUME NAME
local               f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93
$ sudo ls -l /var/lib/docker/100000.100000/volumes/f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93/_data
total 4
-rw-r--r-- 1 100000 100000 6 Oct  6 10:34 test.txt
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
e33bb735a70f        debian:jessie       "/bin/bash"         About a minute ago   Exited (0) About a minute ago                       determined_hypatia
$ docker cp determined_hypatia:/data/test.txt .
$ ls -l test.txt 
-rw-r--r-- 1 don don 6 Oct  6 10:34 test.txt
$ cat test.txt
hello
$ 

Tuttavia, se si desidera solo leggere i file da un contenitore, non è necessario il volume denominato. Questo esempio usa un contenitore denominato invece di un volume denominato:

$ docker run -ti --name sandbox1 debian:jessie /bin/bash
root@93d098233cf3:/# echo 'howdy' > /tmp/test.txt
root@93d098233cf3:/# exit
exit
$ docker cp sandbox1:/tmp/test.txt .
$ ls -l test.txt
-rw-r--r-- 1 don don 6 Oct  6 10:52 test.txt
$ cat test.txt
howdy
$ 

Trovo che i volumi con nome siano utili quando voglio copiare file in un contenitore, come descritto in questa domanda .


Ma docker cpimplica la duplicazione dei dati. Inoltre, secondo il documento, quando si copiano i dati in un contenitore, imposta gli ID di proprietà in base all'utente root, che spesso non è l'account che esegue l'app containerizzata. Non vedo come risolva il nostro problema.
Stéphane C.

Hai ragione, @ Stéphane, si tratta di duplicare i dati. Tuttavia, la creazione di copie dei file consente di assegnare proprietà e autorizzazioni diverse sull'host e nel contenitore. docker cpti dà il pieno controllo sulla proprietà dei file quando esegui lo streaming di un archivio tar dentro o fuori un contenitore. È possibile regolare la proprietà e le autorizzazioni di ciascuna voce nel file tar durante lo streaming, quindi non sei limitato all'utente root.
Don Kirkby
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.