Autorizzazione negata durante l'accesso alla directory host in Docker


283

In breve: sto cercando di montare una directory host in Docker, ma non riesco ad accedervi dall'interno del contenitore, anche se le autorizzazioni di accesso sembrano buone.

I dettagli:

sto facendo

sudo docker run -i -v /data1/Downloads:/Downloads ubuntu bash

e poi

ls -al

Mi dà:

total 8892
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 .
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 ..
-rwxr-xr-x.   1 root root       0 Jun 18 14:34 .dockerenv
-rwx------.   1 root root 9014486 Jun 17 22:09 .dockerinit
drwxrwxr-x.  18 1000 1000   12288 Jun 16 11:40 Downloads
drwxr-xr-x.   2 root root    4096 Jan 29 18:10 bin
drwxr-xr-x.   2 root root    4096 Apr 19  2012 boot
drwxr-xr-x.   4 root root     340 Jun 18 14:34 dev
drwxr-xr-x.  56 root root    4096 Jun 18 14:34 etc
drwxr-xr-x.   2 root root    4096 Apr 19  2012 home

e molte più righe del genere (penso che questa sia la parte rilevante).

Se lo faccio

cd /Downloads
ls

il risultato è

ls: cannot open directory .: Permission denied

L'host è Fedora 20, con Docker 1.0.0 e go1.2.2.

Cosa non va?

Risposte:


269

Vedi questo post sul blog Atomic su Volumes e SELinux per la storia completa.

In particolare:

Questo è diventato più facile di recente da quando Docker ha finalmente unito una patch che verrà mostrata in docker-1.7 (Abbiamo portato la patch in docker-1.6 su RHEL, CentOS e Fedora).

Questa patch aggiunge il supporto per "z" e "Z" come opzioni sui montaggi di volume (-v).

Per esempio:

docker run -v /var/db:/var/db:z rhel7 /bin/sh

Farà automaticamente quanto chcon -Rt svirt_sandbox_file_t /var/db descritto nella pagina man.

Ancora meglio, puoi usare Z.

docker run -v /var/db:/var/db:Z rhel7 /bin/sh

Ciò etichetterà il contenuto all'interno del contenitore con l'etichetta MCS esatta con cui verrà eseguito il contenitore, fondamentalmente viene eseguito chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/dbin modo s0:c1,c2diverso per ciascun contenitore.


18
Funziona come un fascino. Altre soluzioni sono per lo più soluzioni alternative.
tuxdna,

4
cf. la sezione delle etichette del volume nella documentazione
docker

Oh, amico, funziona davvero. Alla fine l'ho trovato. Grazie molto! Esiste una documentazione ufficiale al riguardo?
Kirby,

1
A monte lo ha come ultimo paragrafo in questa sezione docs.docker.com/engine/reference/commandline/run/…
gregswift

1
E 'possibile fissare i permessi sotto SELinux durante il montaggio del volume in sola lettura, allo stesso tempo utilizzando entrambe le opzioni allo stesso tempo separate da una virgola: -v $(pwd):/app:ro,Z. Questo dovrebbe essere contrassegnato come la risposta corretta.
danirod,

264

È un problema di SELinux .

Puoi emettere temporaneamente

su -c "setenforce 0"

sull'host per accedere oppure aggiungere una regola SELinux eseguendo

chcon -Rt svirt_sandbox_file_t /path/to/volume

3
è / path / to / volume il percorso dell'host? In tal caso, non sembra che questa soluzione funzioni con i contenitori di dati?
Roy Truelove,

6
non dimenticare di fare su -c "setenforce 1" ... altrimenti funzionerà solo perché SELinux è ancora disattivato
vcarel

questo ha risolto il mio problema. grazie, spero che avranno una soluzione per questo.
Hokutosei,

19
L'aggiunta della regola di selinux è il modo migliore, poiché nella maggior parte dei casi non è una buona idea eseguire contenitori con modalità privilegiata.
Zoro_77,

7
Come ha detto Zoro_77, aggiungi una regola e stopdisablingselinux.com ;)
GabLeRoux

71

ATTENZIONE: questa soluzione presenta rischi per la sicurezza.

Prova a eseguire il contenitore come privilegiato:

sudo docker run --privileged=true -i -v /data1/Downloads:/Downloads ubuntu bash

Un'altra opzione (che non ho provato) sarebbe quella di creare un contenitore privilegiato e quindi creare contenitori non privilegiati al suo interno.


1
@JBernardo Quale delle due opzioni ha risolto il problema?
user100464

@ --privileged=true
utente100464

1
Non aiutare nel mio caso. Debian Whezzy con kernel 3.16 backport ma non ha attivato la configurazione SELinux. :(
aholbreich,

se stai usando docker-compositore aggiungi 'privileged: true'
Lionel Morrison,

35
Non farlo. --privilegedè un rischio per la sicurezza
Navin,

38

In genere, i problemi di autorizzazione con un mount del volume host sono dovuti al fatto che uid / gid all'interno del contenitore non ha accesso al file in base alle autorizzazioni uid / gid del file sull'host. Tuttavia, questo caso specifico è diverso.

Il punto alla fine della stringa di autorizzazione drwxr-xr-x., indica che SELinux è configurato. Quando si utilizza un mount host con SELinux, è necessario passare un'opzione aggiuntiva alla fine della definizione del volume:

  • L' zopzione indica che il contenuto del bind mount è condiviso tra più contenitori.
  • L' Zopzione indica che il contenuto di bind mount è privato e non condiviso.

Il comando di montaggio del volume sarebbe quindi simile a:

sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash

Per ulteriori informazioni sui supporti host con SELinux, consultare: https://docs.docker.com/storage/#configure-the-selinux-label


Per gli altri che riscontrano questo problema con i contenitori in esecuzione come utente diverso, è necessario assicurarsi che l'uid / gid dell'utente all'interno del contenitore disponga delle autorizzazioni per il file sull'host. Sui server di produzione, ciò avviene spesso controllando uid / gid nel processo di creazione dell'immagine per abbinare un uid / gid sull'host che ha accesso ai file (o, meglio ancora, non utilizzare i montaggi host in produzione).

Un volume con nome è spesso preferito per ospitare i montaggi perché inizializzerà la directory del volume dalla directory delle immagini, inclusi eventuali diritti e proprietà del file. Ciò accade quando il volume è vuoto e il contenitore viene creato con il volume indicato.

Gli utenti MacOS ora hanno OSXFS che gestisce automaticamente gli uid / gid tra l'host Mac e i container. Un posto in cui non aiuta sono i file dall'interno della VM incorporata che vengono montati nel contenitore, come /var/lib/docker.sock.

Per ambienti di sviluppo in cui l'host uid / gid può cambiare per sviluppatore, la mia soluzione preferita è avviare il contenitore con un punto di accesso in esecuzione come root, correggere l'uid / gid dell'utente all'interno del contenitore in modo che corrisponda al volume dell'host uid / gid e quindi utilizzare gosuper rilasciare dalla radice all'utente del contenitore per eseguire l'applicazione all'interno del contenitore. Lo script importante per questo è fix-permsnei miei script di immagini di base, che possono essere trovati su: https://github.com/sudo-bmitch/docker-base

La parte importante dello fix-permsscript è:

# update the uid
if [ -n "$opt_u" ]; then
  OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:)
  NEW_UID=$(stat -c "%u" "$1")
  if [ "$OLD_UID" != "$NEW_UID" ]; then
    echo "Changing UID of $opt_u from $OLD_UID to $NEW_UID"
    usermod -u "$NEW_UID" -o "$opt_u"
    if [ -n "$opt_r" ]; then
      find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \;
    fi
  fi
fi

Ciò porta l'UID dell'utente all'interno del contenitore, l'UID del file e, se non corrispondono, chiama usermodper regolare l'UID. Infine fa una ricerca ricorsiva per riparare tutti i file che non hanno cambiato gli utenti. Mi piace di più rispetto all'esecuzione di un contenitore con un -u $(id -u):$(id -g)flag perché il codice sopra indicato non richiede che ogni sviluppatore esegua uno script per avviare il contenitore e tutti i file al di fuori del volume di proprietà dell'utente avranno le autorizzazioni corrette.


Puoi anche fare in modo che la finestra mobile inizializzi una directory host da un'immagine usando un volume con nome che esegue un montaggio bind. Questa directory deve esistere in anticipo ed è necessario fornire un percorso assoluto alla directory host, diversamente dai volumi host in un file di composizione che possono essere percorsi relativi. La directory deve anche essere vuota per la finestra mobile per inizializzarla. Tre diverse opzioni per la definizione di un volume con nome in un montaggio bind sono:

  # create the volume in advance
  $ docker volume create --driver local \
      --opt type=none \
      --opt device=/home/user/test \
      --opt o=bind \
      test_vol

  # create on the fly with --mount
  $ docker run -it --rm \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=none,volume-opt=o=bind,volume-opt=device=/home/user/test \
    foo

  # inside a docker-compose file
  ...
  volumes:
    bind-test:
      driver: local
      driver_opts:
        type: none
        o: bind
        device: /home/user/test
  ...

Infine, se provi a utilizzare gli spazi dei nomi utente, scoprirai che i volumi host hanno problemi di autorizzazione perché gli uid / gid dei container vengono spostati. In quello scenario, è probabilmente più semplice evitare i volumi host e usare solo i volumi con nome.


32

Da access.redhat.com:Sharing_Data_Across_Containers :

Le impostazioni del volume dell'host non sono portatili, poiché dipendono dall'host e potrebbero non funzionare su nessun altro computer. Per questo motivo, non esiste un equivalente Dockerfile per il montaggio delle directory host sul contenitore. Inoltre, tenere presente che il sistema host non è a conoscenza della politica SELinux del contenitore. Pertanto, se viene applicata la politica SELinux, la directory host montata non è scrivibile nel contenitore, indipendentemente dall'impostazione rw. Attualmente, puoi aggirare questo problema assegnando il tipo di politica SELinux corretto alla directory host ":

chcon -Rt svirt_sandbox_file_t host_dir

Dove host_dir è un percorso della directory sul sistema host che è montato sul contenitore.

Sembra essere solo una soluzione alternativa, ma ci ho provato e funziona.


14

Ho verificato che chcon -Rt svirt_sandbox_file_t /path/to/volumefunziona e non è necessario eseguire come contenitore privilegiato.

Questo è su:

  • Docker versione 0.11.1-dev, build 02d20af / 0.11.1
  • CentOS 7 come host e contenitore con SELinux abilitato.

2
Vedere github.com/docker/docker/pull/5910 per supporto ufficiale per la rietichettatura all'interno di Docker.
cpuguy83,

13

Prova docker volume create.

mkdir -p /data1/Downloads
docker volume create --driver local --name hello --opt type=none --opt device=/data1/Downloads --opt o=uid=root,gid=root --opt o=bind
docker run -i -v hello:/Downloads ubuntu bash

Dai un'occhiata al documento https://docs.docker.com/engine/reference/commandline/volume_create/


3
Ho provato molte risposte su questo problema su SO, ma in realtà questo ha aiutato. Grazie!
Paul,

Ha risolto l'errore di autorizzazione. Ma ora se sto cercando di montare la posizione fisica monta voulme ???? @ cupen
kunal verma

1
@kunalverma Sì. Se non ti piace, ecco la risposta più semplice. stackoverflow.com/a/31334443/4909388
Cupen

4

Ho avuto un problema simile, il mio è stato causato da una mancata corrispondenza tra l'UID dell'host e l'UID dell'utente del contenitore. La correzione consisteva nel passare l'UID dell'utente come argomento alla build della finestra mobile e creare l'utente del contenitore con lo stesso UID.

Nel file Docker:

ARG UID=1000
ENV USER="ubuntu"
RUN useradd -u $UID -ms /bin/bash $USER

Nel passaggio di costruzione:

docker build <path/to/Dockerfile> -t <tag/name> --build-arg UID=$UID

Successivamente, l'esecuzione del contenitore e dei comandi secondo l'OP mi ha dato il risultato atteso.


1
Cosa succede se non si conosce l'UID fino al runtime? (Sto creando un'immagine per i colleghi, per impacchettare alcuni strumenti che riscrivono nel loro filesystem, ma hanno UID diversi). Immagino di poterlo mantenere root e solo adduser in esecuzione?
inger

Purtroppo non ho una buona risposta. Se qualcun altro ha una soluzione, sarei interessato anche a questa. Sospetto che la funzionalità del punto di accesso Docker potrebbe fornire una soluzione.
RoboCop87,

0

Ho risolto questo problema utilizzando un contenitore di dati, questo ha anche il vantaggio di isolare i dati dal livello dell'applicazione. Potresti eseguirlo in questo modo:

docker run --volumes-from=<container-data-name> ubuntu

Questo tutorial fornisce una buona spiegazione sull'uso dei contenitori di dati.


-1

Nella mia situazione il problema era diverso. Non so perché, ma anche se la directory sull'host era stata chmod 777eseguita su di essa, all'interno della finestra mobile era visibile come 755.

Correndo all'interno del contenitore è stato sudo chmod 777 my_volume_dirrisolto.


5
chmod 777non risolve quasi mai nulla.
Erki Aring

Mi dispiace, ma hai perso il punto. Il punto è che i privilegi del container interno sono stati abbassati e non possono essere riparati dall'esterno.
CodeSandwich,

-2

sudo -s ha fatto il trucco per me su MAC


1
Se stai effettuando il downvoting, lascia un commento e spiega perché. Ho riscontrato lo stesso identico problema e sono stato in grado di risolverlo con sudo -s.
Nachiket Joshi,

Non tutte le immagini della finestra mobile hanno sudo e non è possibile in tutti gli scenari.
SOFe

2
Non installare sudo sui contenitori. Un utente malintenzionato può utilizzare sudo all'interno di un contenitore.
Arnold Balliu,
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.