Izin ditolak saat mengakses direktori host di Docker

283

Singkatnya: Saya mencoba memasang direktori host di Docker, tetapi kemudian saya tidak dapat mengaksesnya dari dalam wadah, bahkan jika izin aksesnya terlihat bagus.

Rinciannya:

saya lakukan

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

lalu

ls -al

Ini memberi saya:

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

dan lebih banyak baris seperti itu (saya pikir ini adalah bagian yang relevan).

Jika aku melakukan

cd /Downloads
ls

hasilnya adalah

ls: cannot open directory .: Permission denied

Tuan rumah adalah Fedora 20, dengan Docker 1.0.0 dan go1.2.2.

Apa yang salah?

pengguna3753011
sumber

Jawaban:

269

Lihat posting blog Project Atomic ini tentang Volume dan SELinux untuk cerita selengkapnya.

Secara khusus:

Ini menjadi lebih mudah baru-baru ini sejak Docker akhirnya menggabungkan patch yang akan muncul di docker-1.7 (Kami telah membawa patch di docker-1.6 di RHEL, CentOS, dan Fedora).

Patch ini menambahkan dukungan untuk "z" dan "Z" sebagai opsi pada mount volume (-v).

Sebagai contoh:

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

Secara otomatis akan melakukan yang chcon -Rt svirt_sandbox_file_t /var/db dijelaskan di halaman manual.

Lebih baik lagi, Anda bisa menggunakan Z.

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

Ini akan memberi label konten di dalam wadah dengan label MCS yang tepat bahwa wadah akan berjalan, pada dasarnya itu berjalan di chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/dbmana s0:c1,c2berbeda untuk setiap wadah.

gregswift
sumber
18
Ini bekerja seperti pesona. Solusi lain sebagian besar adalah solusi.
tuxdna
4
lih. bagian label volume dalam dokumentasi buruh pelabuhan
maxschlepzig
Ya ampun, ini benar-benar berhasil. Saya akhirnya menemukan ini. Terimakasih banyak! Apakah ada dokumentasi resmi tentang ini?
Kirby
1
Upstream memilikinya sebagai paragraf terakhir di bagian ini docs.docker.com/engine/reference/commandline/run/…
gregswift
1
Hal ini dimungkinkan untuk memperbaiki perizinan di bawah SELinux saat mounting volume sebagai dibaca pada waktu yang sama dengan menggunakan kedua pilihan pada saat yang sama dipisahkan dengan koma: -v $(pwd):/app:ro,Z. Ini harus ditandai sebagai jawaban yang benar.
danirod
264

Ini adalah masalah SELinux .

Anda dapat mengeluarkan sementara

su -c "setenforce 0"

pada host untuk mengakses atau menambahkan aturan SELinux dengan menjalankan

chcon -Rt svirt_sandbox_file_t /path/to/volume
pengguna3761313
sumber
3
adalah / path / to / volume path host? Jika demikian, sepertinya solusi ini tidak akan berfungsi dengan wadah data?
Roy Truelove
6
jangan lupa untuk melakukan su -c "setenforce 1" ... kalau tidak itu akan berfungsi hanya karena SELinux masih dinonaktifkan
vcarel
ini menyelesaikan masalah saya. terima kasih, saya berharap mereka akan memperbaikinya.
Hokutosei
19
Menambahkan aturan selinux adalah cara terbaik, karena itu bukan ide yang baik dalam kebanyakan kasus untuk menjalankan kontainer dengan mode istimewa.
Zoro_77
7
Seperti yang dikatakan Zoro_77, tambahkan aturan dan stopdisablingselinux.com ;)
GabLeRoux
71

PERINGATAN: Solusi ini memiliki risiko keamanan.

Coba jalankan wadah sebagai hak istimewa:

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

Pilihan lain (yang belum saya coba) adalah membuat wadah istimewa dan kemudian membuat wadah non-istimewa di dalamnya.

John Phillips
sumber
1
@ Jernardo Manakah dari dua opsi yang memecahkan masalah?
user100464
@ user100464--privileged=true
JBernardo
1
Jangan membantu dalam kasus saya. Debian Whezzy dengan kernel 3,16 backported tetapi tidak mengaktifkan konfigurasi SELinux. :(
aholbreich
jika Anda menggunakan buruh pelabuhan-komposer tambahkan 'privilege: true'
Lionel Morrison
35
Jangan lakukan ini. --privilegedadalah risiko keamanan
Navin
38

Biasanya, masalah izin dengan pemasangan volume host adalah karena uid / gid di dalam wadah tidak memiliki akses ke file sesuai dengan izin uid / gid dari file pada host. Namun, kasus spesifik ini berbeda.

Titik di akhir string izin drwxr-xr-x.,, menunjukkan SELinux dikonfigurasi. Saat menggunakan host host dengan SELinux, Anda harus memberikan opsi tambahan ke akhir definisi volume:

  • The zpilihan menunjukkan bahwa mengikat gunung konten dibagi di antara beberapa kontainer.
  • The Zpilihan menunjukkan bahwa bind mount konten pribadi dan pembagiannya.

Perintah volume mount Anda akan terlihat seperti:

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

Lihat lebih lanjut tentang host host dengan SELinux di: https://docs.docker.com/storage/#configure-the-selinux-label


Untuk orang lain yang melihat masalah ini dengan wadah berjalan sebagai pengguna yang berbeda, Anda perlu memastikan uid / gid dari pengguna di dalam wadah memiliki izin ke file di host. Pada server produksi, ini sering dilakukan dengan mengendalikan uid / gid dalam proses pembuatan gambar agar sesuai dengan uid / gid pada host yang memiliki akses ke file (atau bahkan lebih baik, jangan menggunakan host host dalam produksi).

Volume bernama sering dipilih untuk meng-host mount karena akan menginisialisasi direktori volume dari direktori gambar, termasuk kepemilikan dan izin file apa pun. Ini terjadi ketika volume kosong dan wadah dibuat dengan volume bernama.

Pengguna MacOS sekarang memiliki OSXFS yang menangani uid / gid secara otomatis antara host Mac dan wadah. Satu tempat yang tidak membantu adalah file dari dalam VM tertanam yang bisa dipasang ke dalam wadah, seperti /var/lib/docker.sock.

Untuk lingkungan pengembangan tempat host uid / gid dapat berubah per pengembang, solusi pilihan saya adalah memulai wadah dengan entrypoint berjalan sebagai root, perbaiki uid / gid pengguna di dalam wadah agar sesuai dengan volume host uid / gid, dan lalu gunakan gosuuntuk menjatuhkan dari root ke pengguna wadah untuk menjalankan aplikasi di dalam wadah. Skrip penting untuk ini ada fix-permsdi skrip gambar dasar saya, yang dapat ditemukan di: https://github.com/sudo-bmitch/docker-base

Bit penting dari fix-permsskrip adalah:

# 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

Itu mendapatkan uid dari pengguna di dalam wadah, dan uid dari file, dan jika mereka tidak cocok, panggilan usermoduntuk menyesuaikan uid. Terakhir ia melakukan pencarian rekursif untuk memperbaiki file yang belum berubah. Saya suka ini lebih baik daripada menjalankan wadah dengan -u $(id -u):$(id -g)bendera karena kode entri di atas tidak mengharuskan setiap pengembang untuk menjalankan skrip untuk memulai wadah, dan file apa pun di luar volume yang dimiliki oleh pengguna akan memiliki izin mereka diperbaiki.


Anda juga dapat membuat buruh pelabuhan menginisialisasi direktori host dari sebuah gambar dengan menggunakan volume bernama yang melakukan mount mengikat. Direktori ini harus ada sebelumnya, dan Anda harus memberikan path absolut ke direktori host, tidak seperti volume host dalam file penulisan yang bisa menjadi path relatif. Direktori juga harus kosong untuk buruh pelabuhan untuk menginisialisasi. Tiga opsi berbeda untuk mendefinisikan volume bernama ke bind mount terlihat seperti:

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

Terakhir, jika Anda mencoba menggunakan ruang nama pengguna, Anda akan menemukan bahwa volume host memiliki masalah izin karena uid / gid dari wadah tersebut digeser. Dalam skenario itu, mungkin paling mudah untuk menghindari volume host dan hanya menggunakan volume bernama.

BMitch
sumber
32

Dari access.redhat.com:Sharing_Data_Across_Containers :

Pengaturan volume host tidak portabel, karena bergantung pada host dan mungkin tidak berfungsi pada mesin lain. Untuk alasan ini, tidak ada Dockerfile yang setara untuk memasang direktori host ke kontainer. Perlu diketahui juga bahwa sistem host tidak memiliki pengetahuan tentang kebijakan wadah SELinux. Oleh karena itu, jika kebijakan SELinux diberlakukan, direktori host yang dipasang tidak dapat ditulisi ke wadah, terlepas dari pengaturan rw. Saat ini, Anda dapat menyiasatinya dengan menetapkan tipe kebijakan SELinux yang tepat ke direktori host ":

chcon -Rt svirt_sandbox_file_t host_dir

Di mana host_dir adalah jalur ke direktori pada sistem host yang dipasang ke wadah.

Tampaknya hanya solusi, tetapi saya mencoba dan berhasil.

Thomas8
sumber
14

Saya memverifikasi bahwa chcon -Rt svirt_sandbox_file_t /path/to/volumeitu berfungsi dan Anda tidak harus menjalankan sebagai wadah istimewa.

Ini aktif:

  • Docker versi 0.11.1-dev, build 02d20af / 0.11.1
  • CentOS 7 sebagai host dan wadah dengan SELinux diaktifkan.
jeff mccormick
sumber
2
Lihat github.com/docker/docker/pull/5910 untuk dukungan resmi untuk penandaan ulang di Docker.
cpuguy83
13

Coba 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

Lihatlah dokumen https://docs.docker.com/engine/reference/commandline/volume_create/

cupen
sumber
3
Mencoba banyak jawaban tentang masalah ini pada SO, tetapi sebenarnya ini membantu. Terima kasih!
Paul
Itu memecahkan kesalahan izin. Tapi sekarang jika saya mencoba untuk me-mount lokasi fisik itu me-mount voulme ???? @ cupen
kunal verma
1
@kunalverma Ya. Jika Anda tidak menyukainya, inilah jawaban yang lebih mudah. stackoverflow.com/a/31334443/4909388
cupen
4

Saya memiliki masalah yang sama, masalah saya disebabkan oleh ketidakcocokan antara UID host dan UID pengguna kontainer. Cara mengatasinya adalah untuk lulus UID pengguna sebagai argumen untuk membangun buruh pelabuhan dan membuat pengguna wadah dengan UID yang sama.

Di DockerFile:

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

Pada langkah build:

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

Setelah itu, menjalankan wadah dan perintah sesuai OP memberi saya hasil yang diharapkan.

RoboCop87
sumber
1
Bagaimana jika Anda tidak tahu UID sampai run-time? (Saya sedang membangun gambar untuk coleagues, untuk mengemas beberapa alat yang menulis kembali ke sistem file mereka, tetapi mereka memiliki UID yang berbeda). Saya kira saya bisa tetap root dan hanya adduser yang berjalan?
inger
Sayangnya, saya tidak punya jawaban yang bagus untuk itu. Jika ada orang lain yang memiliki solusi saya akan tertarik juga. Saya menduga fungsionalitas pintu masuk Docker mungkin memberikan solusi.
RoboCop87
0

Saya menyelesaikan masalah itu dengan menggunakan wadah data, ini juga memiliki keuntungan untuk mengisolasi data dari lapisan aplikasi. Anda bisa menjalankannya seperti ini:

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

Tutorial ini memberikan penjelasan yang baik tentang penggunaan wadah data.

tmsss
sumber
-1

Dalam situasi saya masalahnya berbeda. Saya tidak tahu mengapa, tetapi bahkan jika direktori pada host punyachmod 777 berjalan di dalamnya, di dalam buruh pelabuhan itu terlihat 755.

Menjalankan di dalam wadah sudo chmod 777 my_volume_dirmemperbaikinya.

CodeSandwich
sumber
5
chmod 777hampir tidak pernah memperbaiki apa pun.
Erki Aring
Maaf, tapi Anda tidak mengerti intinya. Intinya adalah bahwa hak istimewa wadah di dalam diturunkan dan tidak bisa diperbaiki dari luar.
CodeSandwich
-2

sudo -s melakukan trik untuk saya di MAC

Nachiket Joshi
sumber
1
Jika Anda downvoting, tinggalkan komentar dan jelaskan alasannya. Saya mengalami masalah yang sama persis dan saya bisa menyelesaikan ini dengan sudo -s.
Nachiket Joshi
Tidak semua gambar buruh pelabuhan memiliki sudo, dan itu tidak mungkin di setiap skenario.
SOFe
2
Jangan pasang sudo di wadah. Seorang penyerang dapat menggunakan sudo di dalam sebuah wadah.
Arnold Balliu