Odmowa dostępu do dostępu do katalogu hosta w Docker

283

Krótko mówiąc: próbuję zamontować katalog hosta w Dockerze, ale nie mogę uzyskać do niego dostępu z poziomu kontenera, nawet jeśli uprawnienia dostępu wyglądają dobrze.

Szczegóły:

robię

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

i wtedy

ls -al

To daje mi:

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

i wiele innych takich linii (myślę, że to odpowiednia część).

Jeśli zrobię

cd /Downloads
ls

wynik to

ls: cannot open directory .: Permission denied

Hostem jest Fedora 20, z Docker 1.0.0 i go1.2.2.

Co idzie nie tak?

użytkownik3753011
źródło

Odpowiedzi:

269

Zobacz ten post na blogu projektu Atomic o Volumes i SELinux, aby uzyskać pełną historię.

Konkretnie:

Ostatnio stało się to łatwiejsze, odkąd Docker w końcu połączył łatkę, która pojawi się w docker-1.7 (Nosiliśmy łatkę w docker-1.6 na RHEL, CentOS i Fedorze).

Ta poprawka dodaje obsługę „z” i „Z” jako opcji montowania woluminów (-v).

Na przykład:

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

Automatycznie wykona czynności chcon -Rt svirt_sandbox_file_t /var/db opisane na stronie man.

Co więcej, możesz użyć Z.

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

Spowoduje to oznaczenie zawartości wewnątrz kontenera dokładną etykietą MCS, z którą kontener będzie działał, w zasadzie działa chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/dbtam, gdzie s0:c1,c2różni się dla każdego kontenera.

gregswift
źródło
18
To działa jak urok. Inne rozwiązania to głównie obejścia.
tuxdna
4
por. sekcja etykiety woluminów w dokumentacji
dokera
Och, stary, to naprawdę działa. W końcu to znalazłem. Wielkie dzięki! Czy jest na to oficjalna dokumentacja?
Kirby
1
Upstream ma go jako ostatni akapit w tej sekcji docs.docker.com/engine/reference/commandline/run/…
gregswift,
1
Jest możliwe, aby naprawić uprawnienia pod SELinux podczas montażu głośności jako tylko do odczytu w tym samym czasie przy użyciu obu opcji jednocześnie oddzielone przecinkiem: -v $(pwd):/app:ro,Z. To powinno być oznaczone jako poprawna odpowiedź.
danirod
263

Jest to problem z SELinux .

Możesz tymczasowo wydać

su -c "setenforce 0"

na hoście, aby uzyskać dostęp lub dodać regułę SELinux, uruchamiając

chcon -Rt svirt_sandbox_file_t /path/to/volume
użytkownik3761313
źródło
3
jest / path / to / volume ścieżką hosta? Jeśli tak, to nie wydaje się, aby to rozwiązanie działało z kontenerami danych?
Roy Truelove,
6
nie zapomnij zrobić su -c "setenforce 1" ... inaczej to zadziała tylko dlatego, że SELinux jest nadal dezaktywowany
vcarel
to rozwiązało mój problem. dziękuję, mam nadzieję, że uda się to naprawić.
Hokutosei
19
Dodanie reguły selinux jest najlepszym sposobem, ponieważ w większości przypadków uruchamianie kontenerów w trybie uprzywilejowanym nie jest dobrym pomysłem.
Zoro_77
7
Jak powiedział Zoro_77, dodaj regułę i przestań wyłączaćselinux.com ;)
GabLeRoux
71

OSTRZEŻENIE: To rozwiązanie wiąże się z zagrożeniami bezpieczeństwa.

Spróbuj uruchomić kontener jako uprzywilejowany:

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

Inną opcją (której nie próbowałem) byłoby utworzenie uprzywilejowanego kontenera, a następnie utworzenie w nim kontenerów nieuprzywilejowanych.

John Phillips
źródło
1
@JBernardo Która z dwóch opcji rozwiązała problem?
user100464
@ user100464--privileged=true
JBernardo
1
Nie pomagaj w moim przypadku. Debian Whezzy z jądrem w wersji 3.16, ale nie aktywowanej konfiguracji SELinux. :(
aholbreich,
jeśli używasz Dockera-kompozytora, dodaj „uprzywilejowany: prawda”
Lionel Morrison
35
Nie rób tego. --privilegedstanowi zagrożenie bezpieczeństwa
Navin
38

Zazwyczaj problemy z uprawnieniami do montowania woluminu hosta są spowodowane tym, że identyfikator UID / GID w kontenerze nie ma dostępu do pliku zgodnie z uprawnieniami UID / GID pliku na hoście. Jednak ten konkretny przypadek jest inny.

Kropka na końcu ciągu uprawnień drwxr-xr-x.wskazuje, że SELinux jest skonfigurowany. Gdy używasz montowania hosta w SELinux, musisz przekazać dodatkową opcję na końcu definicji woluminu:

  • Ta zopcja wskazuje, że zawartość podłączenia wiązania jest współużytkowana przez wiele kontenerów.
  • Ta Zopcja wskazuje, że treść podłączenia powiązania jest prywatna i nieudostępniona.

Polecenie podłączenia woluminu wyglądałoby wtedy następująco:

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

Więcej informacji o podłączeniach hosta za pomocą SELinuksa można znaleźć na stronie : https://docs.docker.com/storage/#configure-the-selinux-label


W przypadku innych, którzy widzą ten problem z kontenerami działającymi jako inny użytkownik, musisz upewnić się, że identyfikator użytkownika / identyfikator użytkownika w kontenerze ma uprawnienia do pliku na hoście. Na serwerach produkcyjnych jest to często wykonywane przez kontrolowanie identyfikatora UID / GID w procesie kompilacji obrazu, aby dopasować identyfikator UID / GID na hoście, który ma dostęp do plików (lub jeszcze lepiej, nie używaj montowań hosta w produkcji).

Nazwany wolumin jest często preferowany zamiast montowania hosta, ponieważ zainicjuje on katalog woluminów z katalogu obrazów, w tym wszelkie prawa własności i uprawnienia do plików. Dzieje się tak, gdy wolumin jest pusty i kontener jest tworzony z nazwanym woluminem.

Użytkownicy systemu MacOS mają teraz system OSXFS, który automatycznie obsługuje identyfikatory uid / gid między hostem Mac a kontenerami. Jednym z miejsc, w którym nie pomaga, są pliki z wbudowanej maszyny wirtualnej, które są montowane w kontenerze, takie jak /var/lib/docker.sock.

W środowiskach programistycznych, w których identyfikator uid / gid hosta może się zmieniać w zależności od programisty, moim preferowanym rozwiązaniem jest uruchomienie kontenera z punktem wejścia działającym jako root, poprawienie identyfikatora uid / gid użytkownika w kontenerze, aby pasowało do identyfikatora uid / gid woluminu hosta, i następnie użyj, gosuaby upuścić z katalogu głównego do użytkownika kontenera, aby uruchomić aplikację w kontenerze. Ważny skrypt do tego znajduje się fix-permsw moich podstawowych skryptach graficznych, które można znaleźć na stronie : https://github.com/sudo-bmitch/docker-base

Ważnym fragmentem fix-permsskryptu jest:

# 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

To dostaje identyfikator użytkownika w kontenerze i identyfikator pliku, a jeśli się nie zgadzają, wzywa usermoddo dostosowania identyfikatora użytkownika. Na koniec wyszukuje rekursywnie, aby naprawić pliki, które nie zmieniły identyfikatora użytkownika. Podoba mi się to bardziej niż uruchamianie kontenera z -u $(id -u):$(id -g)flagą, ponieważ powyższy kod punktu wejścia nie wymaga od każdego programisty uruchomienia skryptu w celu uruchomienia kontenera, a wszelkie pliki poza woluminem, które są własnością użytkownika, zostaną poprawione.


Można również zlecić dokerowi zainicjowanie katalogu hosta z obrazu przy użyciu nazwanego woluminu, który wykonuje podłączenie wiązania. Ten katalog musi istnieć wcześniej i należy podać bezwzględną ścieżkę do katalogu hosta, w przeciwieństwie do woluminów hosta w pliku tworzenia, które mogą być ścieżkami względnymi. Katalog musi być również pusty, aby doker mógł go zainicjować. Wyglądają trzy różne opcje definiowania nazwanego woluminu dla montowania wiązania:

  # 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
  ...

Na koniec, jeśli spróbujesz użyć przestrzeni nazw użytkownika, okaże się, że woluminy hosta mają problemy z uprawnieniami, ponieważ uid / gid kontenerów są przesunięte. W tym scenariuszu prawdopodobnie najłatwiej jest uniknąć woluminów hosta i używać tylko woluminów nazwanych.

BMitch
źródło
32

Od access.redhat.com:Sharing_Data_Across_Containers :

Ustawienia głośności hosta nie są przenośne, ponieważ są zależne od hosta i mogą nie działać na żadnym innym komputerze. Z tego powodu nie ma odpowiednika Dockerfile do montowania katalogów hosta w kontenerze. Należy również pamiętać, że system hosta nie ma wiedzy o zasadach kontenera SELinux. Dlatego jeśli wymuszone są zasady SELinux, podłączonego katalogu hosta nie można zapisać w kontenerze, niezależnie od ustawienia rw. Obecnie można obejść ten problem, przypisując odpowiedni typ zasad SELinux do katalogu hosta „:

chcon -Rt svirt_sandbox_file_t host_dir

Gdzie katalog_hosta jest ścieżką do katalogu w systemie hosta, który jest podłączony do kontenera.

Wydaje się, że to tylko obejście, ale próbowałem i działa.

Thomas8
źródło
14

Sprawdziłem, że chcon -Rt svirt_sandbox_file_t /path/to/volumeto działa i nie musisz działać jako uprzywilejowany kontener.

To jest na:

  • Wersja Docker 0.11.1-dev, kompilacja 02d20af / 0.11.1
  • CentOS 7 jako host i kontener z włączonym SELinux.
jeff mccormick
źródło
2
Zobacz github.com/docker/docker/pull/5910, aby uzyskać oficjalne wsparcie dla ponownego etykietowania w Docker.
cpuguy83,
13

Spróbować 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

Spójrz na dokument https://docs.docker.com/engine/reference/commandline/volume_create/

cupen
źródło
3
Próbowałem wiele odpowiedzi na ten temat na SO, ale w rzeczywistości ta pomogła. Dzięki!
Paul
Rozwiązał błąd uprawnień. Ale teraz, gdy próbuję zamontować fizyczną lokalizację, montuje voulme ???? @ cupen
kunal verma
1
@kunalverma Tak. Jeśli ci się nie podoba, oto łatwiejsza odpowiedź. stackoverflow.com/a/31334443/4909388
cupen
4

Miałem podobny problem, mój był spowodowany niedopasowaniem między UID hosta a UID użytkownika kontenera. Rozwiązaniem było przekazanie UID użytkownika jako argumentu do kompilacji dokera i utworzenie użytkownika kontenera z tym samym UID.

W DockerFile:

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

W kroku kompilacji:

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

Następnie uruchomienie kontenera i poleceń zgodnie z OP dało mi oczekiwany wynik.

RoboCop87
źródło
1
Co zrobić, jeśli nie znasz identyfikatora UID do czasu wykonania? (Buduję obraz dla kolegów, aby spakować niektóre narzędzia, które zapisują z powrotem do swojego systemu plików, ale mają różne UID). Wydaje mi się, że mógłbym utrzymać rootowanie i tylko adduser w biegu?
inger
Niestety nie mam na to dobrej odpowiedzi. Jeśli ktoś ma jakieś rozwiązanie, zainteresowałbym się nim również. Podejrzewam, że funkcjonalność punktu wejścia Dockera może zapewnić rozwiązanie.
RoboCop87
0

Rozwiązałem ten problem, używając kontenera danych, ma to również tę zaletę, że izoluję dane od warstwy aplikacji. Możesz uruchomić go w następujący sposób:

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

To samouczek zawiera dobre objaśnienie korzystania z kontenerów danych.

tmsss
źródło
-1

W mojej sytuacji problem był inny. Nie wiem dlaczego, ale nawet jeśli katalog na hoście chmod 777działał na nim, wewnątrz dokera było to widoczne jako755 .

sudo chmod 777 my_volume_dirNaprawiono je w kontenerze .

CodeSandwich
źródło
5
chmod 777prawie nigdy niczego nie naprawia.
Erki Aring,
Przepraszam, ale nie rozumiesz sedna sprawy. Chodzi o to, że uprawnienia wewnątrz kontenera zostały obniżone i nie można go naprawić z zewnątrz.
CodeSandwich,
-2

sudo -s zrobił mi lewę na MAC

Nachiket Joshi
źródło
1
Jeśli przegłosujesz, zostaw komentarz i wyjaśnij dlaczego. Napotkałem dokładnie ten sam problem i udało mi się go rozwiązać przez sudo -s.
Nachiket Joshi,
Nie każdy obraz dokera ma sudo i nie jest to możliwe w każdym scenariuszu.
SOFe
2
Nie instaluj sudo na kontenerach. Atakujący może użyć sudo w pojemniku.
Arnold Balliu