ปฏิเสธสิทธิ์ในการเข้าถึงไดเรกทอรีโฮสต์ใน Docker


283

กล่าวโดยย่อ: ฉันกำลังพยายามติดตั้งไดเรกทอรีโฮสต์ใน Docker แต่ฉันไม่สามารถเข้าถึงได้จากภายในคอนเทนเนอร์แม้ว่าสิทธิ์การเข้าถึงจะดูดี

รายละเอียด:

ฉันกำลังทำ

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

แล้ว

ls -al

มันทำให้ฉัน:

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

และอีกหลายบรรทัดเช่นนั้น (ฉันคิดว่านี่เป็นส่วนที่เกี่ยวข้อง)

ถ้าฉันทำ

cd /Downloads
ls

ผลลัพธ์ที่ได้คือ

ls: cannot open directory .: Permission denied

โฮสต์คือ Fedora 20 พร้อม Docker 1.0.0 และ go1.2.2

เกิดอะไรขึ้น?

คำตอบ:


269

ดูโพสต์บล็อกของโครงการ Atomic เกี่ยวกับ Volumes และ SELinuxสำหรับเรื่องราวทั้งหมด

โดยเฉพาะ:

สิ่งนี้ทำได้ง่ายขึ้นเมื่อเร็ว ๆ นี้เนื่องจากในที่สุด Docker ได้รวมแพตช์ซึ่งจะปรากฏใน docker-1.7 (เราได้ทำการติดตั้ง patch ใน docker-1.6 บน RHEL, CentOS และ Fedora)

แพตช์นี้เพิ่มการรองรับ "z" และ "Z" เป็นตัวเลือกบนเมานต์โวลุ่ม (-v)

ตัวอย่างเช่น:

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

จะทำตามที่chcon -Rt svirt_sandbox_file_t /var/db อธิบายไว้ในหน้าคู่มือโดยอัตโนมัติ

ยิ่งไปกว่านั้นคุณสามารถใช้ Z

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

วิธีนี้จะติดป้ายเนื้อหาภายในคอนเทนเนอร์ด้วยป้าย MCS ที่แน่นอนที่คอนเทนเนอร์จะทำงานด้วยโดยทั่วไปจะทำงานchcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/dbที่s0:c1,c2แตกต่างกันสำหรับแต่ละคอนเทนเนอร์


18
งานนี้มีเสน่ห์เหมือนกัน โซลูชันอื่น ๆ ส่วนใหญ่จะแก้ไขปัญหา
tuxdna

4
cf เลย ส่วนไดรฟ์ข้อมูลในเอกสารนักเทียบท่า
maxschlepzig

โอ้มันใช้ได้ผลจริงๆ ในที่สุดฉันก็พบสิ่งนี้ ขอบคุณมาก! มีเอกสารอย่างเป็นทางการเกี่ยวกับเรื่องนี้หรือไม่?
เคอร์บี้

1
อัปสตรีมมีไว้เป็นย่อหน้าสุดท้ายในส่วนนี้ docs.docker.com/engine/reference/commandline/run/…
gregswift

1
มันเป็นไปได้ในการแก้ไขปัญหาสิทธิ์ภายใต้ SELinux -v $(pwd):/app:ro,Zขณะติดตั้งไดรฟ์เป็นอ่านได้อย่างเดียวในเวลาเดียวกันโดยใช้ตัวเลือกทั้งสองอย่างในเวลาเดียวกันคั่นด้วยเครื่องหมายจุลภาค: ควรทำเครื่องหมายเป็นคำตอบที่ถูกต้อง
danirod

264

มันเป็นปัญหาของSELinux

คุณสามารถออกชั่วคราว

su -c "setenforce 0"

บนโฮสต์เพื่อเข้าถึงหรือเพิ่มกฎ SELinux โดยการเรียกใช้

chcon -Rt svirt_sandbox_file_t /path/to/volume

3
คือ / path / to / volume เส้นทางของโฮสต์? ถ้าใช่ดูเหมือนว่าโซลูชันนี้จะทำงานกับที่เก็บข้อมูลหรือไม่
Roy Truelove

6
อย่าลืมที่จะทำ su -c "setenforce 1" ... มิฉะนั้นจะใช้งานได้เพียงเพราะ SELinux ยังคงปิดการใช้งานอยู่
vcarel

สิ่งนี้แก้ปัญหาของฉันได้ ขอบคุณฉันหวังว่าพวกเขาจะมีการแก้ไขสำหรับเรื่องนี้
Hokutosei

19
การเพิ่มกฎ selinux เป็นวิธีที่ดีที่สุดเนื่องจากไม่ใช่ความคิดที่ดีในกรณีส่วนใหญ่ในการเรียกใช้คอนเทนเนอร์ด้วยโหมดสิทธิพิเศษ
Zoro_77

7
ดังที่ Zoro_77 กล่าวเพิ่มกฎและstopdisablingselinux.com ;)
GabLeRoux

71

คำเตือน: วิธีนี้มีความเสี่ยงด้านความปลอดภัย

ลองเรียกใช้คอนเทนเนอร์ด้วยสิทธิพิเศษ:

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

ตัวเลือกอื่น (ที่ฉันยังไม่ได้ลอง) คือการสร้างคอนเทนเนอร์ที่มีสิทธิใช้งานแล้วสร้างคอนเทนเนอร์ที่ไม่มีสิทธิ์ภายใน


1
@JBernardo ตัวเลือกใดในสองที่แก้ปัญหาได้
user100464

@ user100464--privileged=true
JBernardo

1
อย่าช่วยในกรณีของฉัน Debian Whezzy ที่มีเคอร์เนล backported 3.16 แต่ไม่ได้เปิดใช้งานการกำหนดค่า SELinux :(
aholbreich

ถ้าคุณใช้นักแต่งเพลงนักแต่งเพลงให้เพิ่ม 'สิทธิพิเศษ: จริง'
Lionel Morrison

35
อย่าทำอย่างนี้. --privilegedคือความเสี่ยงด้านความปลอดภัย
Navin

38

โดยทั่วไปปัญหาเกี่ยวกับสิทธิ์ของการเมานต์ไดรฟ์ข้อมูลโฮสต์เป็นเพราะ uid / gid ภายในคอนเทนเนอร์ไม่มีการเข้าถึงไฟล์ตามการอนุญาต uid / gid ของไฟล์บนโฮสต์ อย่างไรก็ตามกรณีเฉพาะนี้แตกต่างกัน

จุดที่ท้ายสุดของสตริงการอนุญาตdrwxr-xr-x.แสดงว่า SELinux ได้รับการกำหนดค่า เมื่อใช้โฮสต์เมาท์กับ SELinux คุณจะต้องผ่านตัวเลือกพิเศษไปยังจุดสิ้นสุดของคำจำกัดความของโวลุ่ม:

  • zตัวเลือกที่แสดงให้เห็นว่าผูกติดเนื้อหาที่ใช้ร่วมกันระหว่างหลายคอนเทนเนอร์
  • Zตัวเลือกที่แสดงให้เห็นว่าเนื้อหาที่ผูกติดเป็นส่วนตัวและยกเลิกการแชร์

คำสั่งเพิ่มความดังของคุณจะมีลักษณะดังนี้:

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

ดูข้อมูลเพิ่มเติมเกี่ยวกับการติดตั้งโฮสต์ด้วย SELinux ได้ที่: https://docs.docker.com/storage/#configure-the-selinux-label


สำหรับคนอื่น ๆ ที่เห็นปัญหานี้กับคอนเทนเนอร์ที่ทำงานเป็นผู้ใช้อื่นคุณต้องแน่ใจว่า uid / gid ของผู้ใช้ที่อยู่ในคอนเทนเนอร์นั้นได้รับอนุญาตให้ใช้ไฟล์บนโฮสต์ บนเซิร์ฟเวอร์ที่ใช้งานจริงมักจะทำโดยการควบคุม uid / gid ในกระบวนการสร้างอิมเมจเพื่อจับคู่ uid / gid บนโฮสต์ที่มีการเข้าถึงไฟล์ (หรือดีกว่าไม่ใช้โฮสต์เมานต์ในการผลิต)

ไดรฟ์ข้อมูลที่มีชื่อมักจะต้องการโฮสต์เมาต์เนื่องจากจะเริ่มต้นไดเรกทอรีไดรฟ์ข้อมูลจากไดเรกทอรีรูปภาพรวมถึงความเป็นเจ้าของแฟ้มและสิทธิ์ สิ่งนี้จะเกิดขึ้นเมื่อปริมาตรว่างเปล่าและสร้างภาชนะด้วยปริมาตรที่ตั้งชื่อไว้

ขณะนี้ผู้ใช้ MacOS มีOSXFSซึ่งจัดการ uid / gid โดยอัตโนมัติระหว่างโฮสต์ Mac และคอนเทนเนอร์ ที่เดียวที่ไม่ช่วยคือไฟล์จากภายใน VM ที่ฝังไว้ซึ่งติดตั้งในคอนเทนเนอร์เช่น /var/lib/docker.sock

สำหรับสภาพแวดล้อมการพัฒนาที่โฮสต์ uid / gid อาจเปลี่ยนแปลงต่อผู้พัฒนาโซลูชันที่ฉันต้องการคือเริ่มต้นคอนเทนเนอร์ด้วยจุดเข้าใช้งานเป็น root ให้แก้ไข uid / gid ของผู้ใช้ภายในคอนเทนเนอร์เพื่อจับคู่ปริมาณโฮสต์ uid / gid และ จากนั้นใช้gosuเพื่อดร็อปจากรูทไปยังผู้ใช้คอนเทนเนอร์เพื่อรันแอ็พพลิเคชันภายในคอนเทนเนอร์ สคริปต์ที่สำคัญสำหรับสิ่งนี้อยู่fix-permsในสคริปต์ภาพพื้นฐานของฉันซึ่งสามารถดูได้ที่: https://github.com/sudo-bmitch/docker-base

บิตที่สำคัญจากfix-permsสคริปต์คือ:

# 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

ที่ได้รับ uid ของผู้ใช้ภายในภาชนะและ uid ของไฟล์และหากพวกเขาไม่ตรงกันโทรusermodเพื่อปรับ uid ในที่สุดมันจะค้นหาแบบเรียกซ้ำเพื่อแก้ไขไฟล์ใด ๆ ที่ไม่ได้เปลี่ยน uid ฉันชอบสิ่งนี้ดีกว่าการใช้คอนเทนเนอร์ที่มีการ-u $(id -u):$(id -g)ตั้งค่าสถานะเนื่องจากรหัสจุดเข้าใช้งานด้านบนไม่ต้องการให้นักพัฒนาแต่ละคนเรียกใช้สคริปต์เพื่อเริ่มการทำงานของคอนเทนเนอร์และไฟล์ใด ๆ ที่อยู่นอกไดรฟ์ข้อมูลที่เป็นเจ้าของโดยผู้ใช้


คุณยังสามารถให้นักเทียบท่าเริ่มต้นไดเรกทอรีโฮสต์จากอิมเมจโดยใช้โวลุ่มที่ตั้งชื่อซึ่งดำเนินการเชื่อมต่อแบบผูก ไดเรกทอรีนี้จะต้องมีอยู่ล่วงหน้าและคุณต้องระบุเส้นทางที่แน่นอนไปยังไดเรกทอรีโฮสต์ซึ่งแตกต่างจากปริมาณโฮสต์ในไฟล์เขียนซึ่งสามารถเป็นเส้นทางญาติ ไดเรกทอรีจะต้องว่างเปล่าเพื่อให้นักเทียบท่าเริ่มต้นได้ สามอ็อพชันที่แตกต่างกันสำหรับการกำหนดวอลุ่มที่กำหนดชื่อให้กับ bind mount มีลักษณะดังนี้:

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

สุดท้ายถ้าคุณลองใช้เนมสเปซผู้ใช้คุณจะพบว่าโฮสต์ปริมาณมากมีปัญหาเรื่องสิทธิ์เนื่องจากคอนเทนเนอร์ของ uid / gid ถูกเปลี่ยน ในสถานการณ์สมมตินั้นอาจเป็นเรื่องที่ง่ายที่สุดในการหลีกเลี่ยงปริมาณโฮสต์และใช้ชื่อโวลุ่มเท่านั้น


32

จากaccess.redhat.com:Sharing_Data_Across_Containers :

การตั้งค่าระดับเสียงโฮสต์ไม่สามารถเคลื่อนย้ายได้เนื่องจากจะขึ้นอยู่กับโฮสต์และอาจไม่สามารถทำงานกับเครื่องอื่นได้ ด้วยเหตุผลนี้จึงไม่มี Dockerfile ที่เทียบเท่าสำหรับการติดตั้งไดเรกทอรีโฮสต์เข้ากับคอนเทนเนอร์ นอกจากนี้โปรดทราบว่าระบบโฮสต์ไม่มีความรู้เกี่ยวกับนโยบายคอนเทนเนอร์ SELinux ดังนั้นหากมีการบังคับใช้นโยบาย SELinux ไดเรกทอรีโฮสต์ที่เมาท์จะไม่สามารถเขียนลงในคอนเทนเนอร์ได้ไม่ว่าจะมีการตั้งค่า rw หรือไม่ก็ตาม ขณะนี้คุณสามารถหลีกเลี่ยงปัญหานี้ได้โดยกำหนดประเภทนโยบาย SELinux ที่เหมาะสมให้กับไดเรกทอรีโฮสต์ ":

chcon -Rt svirt_sandbox_file_t host_dir

โดยที่ host_dir เป็นพา ธ ไปยังไดเร็กทอรีบนระบบโฮสต์ที่เชื่อมต่อกับคอนเทนเนอร์

ดูเหมือนว่าจะเป็นเพียงวิธีแก้ปัญหา แต่ฉันพยายามแล้วก็ใช้งานได้


14

ฉันตรวจสอบแล้วว่าchcon -Rt svirt_sandbox_file_t /path/to/volumeใช้งานได้และคุณไม่จำเป็นต้องเรียกใช้เป็นคอนเทนเนอร์ที่มีสิทธิ์

นี่คือเมื่อ:

  • นักเทียบท่ารุ่น 0.11.1-dev, build 02d20af / 0.11.1
  • CentOS 7 เป็นโฮสต์และคอนเทนเนอร์ที่เปิดใช้งาน SELinux

2
ดูgithub.com/docker/docker/pull/5910สำหรับการสนับสนุนอย่างเป็นทางการสำหรับการติดตั้งใหม่ภายใน Docker
cpuguy83

13

ลอง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

ดูเอกสารhttps://docs.docker.com/engine/reference/commandline/volume_create/


3
พยายามคำตอบมากมายเกี่ยวกับปัญหานี้ใน SO แต่จริงๆแล้วสิ่งนี้ช่วยได้ ขอบคุณ!
พอล

มันแก้ไขข้อผิดพลาดของการอนุญาต แต่ตอนนี้ถ้าฉันพยายามที่จะติดตั้งสถานที่ทางกายภาพมันเมาน voulme ???? @ cupen
kunal verma

1
@kunalverma ใช่ หากคุณไม่ชอบนี่คือคำตอบที่ง่ายกว่า stackoverflow.com/a/31334443/4909388
cupen

4

ฉันมีปัญหาที่คล้ายกันฉันเกิดจากความไม่ตรงกันระหว่าง UID ของโฮสต์และ UID ของผู้ใช้ของคอนเทนเนอร์ การแก้ไขคือการส่ง UID ของผู้ใช้เป็นอาร์กิวเมนต์ไปยังตัวสร้างนักเทียบท่าและสร้างผู้ใช้ของคอนเทนเนอร์ด้วย UID เดียวกัน

ใน DockerFile:

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

ในขั้นตอนการสร้าง:

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

หลังจากนั้นเรียกใช้คอนเทนเนอร์และคำสั่งตาม OP ให้ผลลัพธ์ตามที่คาดหวังไว้


1
ถ้าคุณไม่รู้จัก UID จนกว่าจะถึงเวลาทำงาน (ฉันกำลังสร้างอิมเมจสำหรับ coleagues เพื่อจัดทำเครื่องมือบางอย่างซึ่งเขียนกลับไปยังระบบไฟล์ของพวกเขา แต่พวกเขามี UID ที่แตกต่างกัน) ฉันเดาว่าฉันสามารถเก็บไว้เป็น root ได้และมีเพียงผู้ใช้เท่านั้นที่ทำงานได้หรือไม่
inger

ฉันไม่มีคำตอบที่ดีสำหรับเรื่องนี้โชคไม่ดี หากใครมีวิธีแก้ไขฉันก็จะสนใจมันเช่นกัน ฉันสงสัยว่าฟังก์ชั่นจุดเข้าใช้งาน Docker อาจมีวิธีแก้ปัญหา
RoboCop87

0

ฉันแก้ไขปัญหานั้นโดยใช้ data container สิ่งนี้มีข้อดีของการแยกข้อมูลออกจากเลเยอร์แอปพลิเคชัน คุณสามารถเรียกใช้เช่นนี้:

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

บทช่วยสอนนี้ให้คำอธิบายที่ดีเกี่ยวกับการใช้คอนเทนเนอร์ข้อมูล


-1

ในสถานการณ์ของฉันปัญหานั้นแตกต่างกัน ฉันไม่รู้ว่าทำไม แต่ถึงแม้ว่าไดเรกทอรีบนโฮสต์ได้chmod 777ทำงานอยู่ภายในตัวเทียบมันก็มองเห็นได้755ทำงานบนภายในนักเทียบท่ามันก็มองเห็นเป็น

การทำงานภายในคอนเทนเนอร์ได้sudo chmod 777 my_volume_dirรับการแก้ไข


5
chmod 777แทบจะไม่เคยแก้ไขอะไรเลย
Erki Aring

ฉันขอโทษ แต่คุณพลาดประเด็นไปแล้ว ประเด็นก็คือสิทธิ์ในตู้คอนเทนเนอร์ลดลงและไม่สามารถแก้ไขได้จากภายนอก
CodeSandwich

-2

sudo -s ทำเคล็ดลับสำหรับฉันบน MAC


1
หากคุณเป็น downvoting อย่าแสดงความคิดเห็นและอธิบายว่าทำไม ฉันพบปัญหาเดียวกันที่แน่นอนและฉันสามารถแก้ไขได้โดย sudo -s
Nachiket Joshi

ไม่ใช่ทุกภาพนักเทียบท่าที่มี sudo และเป็นไปไม่ได้ในทุกสถานการณ์
SOFe

2
อย่าติดตั้ง sudo บนตู้คอนเทนเนอร์ ผู้โจมตีสามารถใช้ sudo ภายในคอนเทนเนอร์ได้
อาร์โนลด์ Balliu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.