Quyền bị từ chối khi truy cập thư mục máy chủ trong Docker


282

Tóm lại: Tôi đang cố gắn một thư mục máy chủ trong Docker, nhưng sau đó tôi không thể truy cập nó từ bên trong container, ngay cả khi các quyền truy cập có vẻ tốt.

Các chi tiết:

tôi đang làm

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

và sau đó

ls -al

Nó đưa cho tôi:

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

và rất nhiều dòng như thế (tôi nghĩ đây là phần có liên quan).

Nếu tôi làm

cd /Downloads
ls

kết quả là

ls: cannot open directory .: Permission denied

Máy chủ lưu trữ là Fedora 20, với Docker 1.0.0 và go1.2.2.

Điều gì đang xảy ra?

Câu trả lời:


269

Xem bài viết trên blog Dự án nguyên tử này về Tập và TỰ TIN để biết toàn bộ câu chuyện.

Đặc biệt:

Điều này trở nên dễ dàng hơn gần đây vì Docker cuối cùng đã hợp nhất một bản vá sẽ xuất hiện trong docker-1.7 (Chúng tôi đã mang bản vá trong docker-1.6 trên RHEL, CentOS và Fedora).

Bản vá này thêm hỗ trợ cho "z" và "Z" dưới dạng tùy chọn trên ngàm âm lượng (-v).

Ví dụ:

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

Sẽ tự động làm chcon -Rt svirt_sandbox_file_t /var/db mô tả trong trang người đàn ông.

Thậm chí tốt hơn, bạn có thể sử dụng Z.

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

Điều này sẽ gắn nhãn nội dung bên trong container với nhãn MCS chính xác mà container sẽ chạy cùng, về cơ bản nó chạy chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/dbở nơi s0:c1,c2khác nhau cho mỗi container.


18
Công việc này như một cái duyên vậy. Các giải pháp khác chủ yếu là giải pháp.
tuxdna

4
xem phần nhãn khối lượng trong tài liệu
docker

Ồ, anh bạn, nó thực sự hoạt động. Cuối cùng tôi đã tìm thấy điều này. Cảm ơn nhiều! Có tài liệu chính thức nào về việc này không?
Kirby

1
Thượng nguồn có đoạn cuối cùng trong phần này docs.docker.com/engine/reference/commandline/run/ mẹo
gregswift

1
Có thể sửa các quyền trong SELinux trong khi gắn âm lượng ở chế độ chỉ đọc cùng một lúc bằng cách sử dụng cả hai tùy chọn cùng lúc được phân tách bằng dấu phẩy : -v $(pwd):/app:ro,Z. Điều này nên được đánh dấu là câu trả lời chính xác.
danirod

263

Đây là một vấn đề TỰ TIN .

Bạn có thể tạm thời phát hành

su -c "setenforce 0"

trên máy chủ để truy cập hoặc người nào khác thêm quy tắc SELinux bằng cách chạy

chcon -Rt svirt_sandbox_file_t /path/to/volume

3
là / path / to / volume đường dẫn của máy chủ? Nếu vậy, có vẻ như giải pháp này sẽ không hoạt động với các thùng chứa dữ liệu?
Roy Truelove

6
đừng quên thực hiện su -c "setenforce 1" ... nếu không nó sẽ chỉ hoạt động vì SELinux vẫn bị hủy kích hoạt
vcarel

Điều này đã giải quyết vấn đề của tôi. cảm ơn bạn, tôi hy vọng họ sẽ có một sửa chữa cho điều này.
Hokutosei

19
Thêm quy tắc selinux là cách tốt nhất, vì trong hầu hết các trường hợp, không nên chạy container với chế độ đặc quyền.
Zoro_77

7
Như Zoro_77 đã nói, hãy thêm quy tắc và stopdisablingselinux.com ;)
GabLeRoux

71

CẢNH BÁO: Giải pháp này có rủi ro bảo mật.

Hãy thử chạy container như đặc quyền:

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

Một tùy chọn khác (mà tôi chưa thử) sẽ là tạo một thùng chứa đặc quyền và sau đó tạo các thùng chứa không có đặc quyền bên trong nó.


1
@JBernardo Lựa chọn nào trong hai lựa chọn đã giải quyết vấn đề?
100464

@ user100464--privileged=true
JBernardo

1
Đừng giúp đỡ trong trường hợp của tôi. Debian Whezzy với kernel backport 3.16 nhưng không được kích hoạt cấu hình SELinux. :(
aholenameich

nếu bạn sử dụng trình soạn thảo docker, hãy thêm 'đặc quyền: đúng'
Lionel Morrison

35
Đừng làm điều này. --privilegedlà một rủi ro bảo mật
Navin

38

Thông thường, các vấn đề về quyền với gắn kết âm lượng máy chủ là do uid / gid bên trong vùng chứa không có quyền truy cập vào tệp theo quyền uid / gid của tệp trên máy chủ. Tuy nhiên, trường hợp cụ thể này là khác nhau.

Dấu chấm ở cuối chuỗi cấp phép drwxr-xr-x., biểu thị SELinux được định cấu hình. Khi sử dụng giá treo máy chủ với SELinux, bạn cần chuyển một tùy chọn bổ sung cho đến cuối định nghĩa âm lượng:

  • Các z tùy chọn chỉ ra rằng nội dung ràng buộc gắn kết được chia sẻ giữa nhiều vùng chứa.
  • Các Ztùy chọn chỉ ra rằng nội dung ràng buộc gắn kết là tư nhân và chia sẻ.

Lệnh mount âm lượng của bạn sau đó sẽ trông như sau:

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

Xem thêm về việc gắn kết máy chủ với SELinux tại: https://docs.docker.com/st Storage / # configure-the-kindinux-label


Đối với những người khác thấy vấn đề này với các container đang chạy như một người dùng khác, bạn cần đảm bảo uid / gid của người dùng bên trong container có quyền đối với tệp trên máy chủ. Trên các máy chủ sản xuất, điều này thường được thực hiện bằng cách kiểm soát uid / gid trong quá trình xây dựng hình ảnh để khớp với uid / gid trên máy chủ có quyền truy cập vào các tệp (hoặc thậm chí tốt hơn, không sử dụng gắn kết máy chủ trong sản xuất).

Một ổ đĩa có tên thường được ưu tiên để gắn kết máy chủ bởi vì nó sẽ khởi tạo thư mục âm lượng từ thư mục hình ảnh, bao gồm mọi quyền sở hữu tệp và quyền. Điều này xảy ra khi âm lượng trống và container được tạo với âm lượng được đặt tên.

Người dùng MacOS hiện có OSXFS tự động xử lý uid / gid giữa máy chủ và bộ chứa Mac. Một nơi không giúp được là các tệp từ bên trong VM được nhúng vào thùng chứa, như /var/lib/docker.sock.

Đối với các môi trường phát triển nơi uid / gid của máy chủ có thể thay đổi theo từng nhà phát triển, giải pháp ưa thích của tôi là khởi động container với một điểm truy cập chạy bằng root, sửa uid / gid của người dùng bên trong container để khớp với khối lượng uid / gid của máy chủ và sau đó sử dụng gosuđể thả từ root đến người dùng container để chạy ứng dụng bên trong container. Kịch bản quan trọng cho điều này nằm fix-permstrong tập lệnh hình ảnh cơ sở của tôi, có thể tìm thấy tại: https://github.com/sudo-bmitch/docker-base

Bit quan trọng từ fix-permskịch bản là:

# 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

Điều đó có được uid của người dùng bên trong container và uid của tệp và nếu chúng không khớp, hãy gọi usermodđể điều chỉnh uid. Cuối cùng, nó tìm thấy đệ quy để sửa bất kỳ tệp nào không thay đổi uid. Tôi thích điều này tốt hơn là chạy một thùng chứa có -u $(id -u):$(id -g)cờ vì mã điểm nhập ở trên không yêu cầu mỗi nhà phát triển chạy tập lệnh để khởi động vùng chứa và bất kỳ tệp nào ngoài khối lượng mà người dùng sở hữu sẽ được sửa quyền.


Bạn cũng có thể yêu cầu docker khởi tạo thư mục máy chủ từ một hình ảnh bằng cách sử dụng một ổ đĩa có tên thực hiện gắn kết liên kết. Thư mục này phải tồn tại trước và bạn cần cung cấp một đường dẫn tuyệt đối đến thư mục máy chủ, không giống như khối lượng máy chủ trong một tệp soạn thảo có thể là các đường dẫn tương đối. Thư mục cũng phải trống để docker khởi tạo nó. Ba tùy chọn khác nhau để xác định âm lượng được đặt tên cho giá treo liên kết trông như sau:

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

Cuối cùng, nếu bạn thử sử dụng không gian tên người dùng, bạn sẽ thấy rằng khối lượng máy chủ có vấn đề về quyền vì uid / gid của các container bị dịch chuyển. Trong kịch bản đó, có thể dễ dàng nhất để tránh khối lượng máy chủ và chỉ sử dụng khối lượng được đặt tên.


32

Từ access.redhat.com:Shared_Data_Across_Containers :

Cài đặt âm lượng máy chủ không thể di động được, vì chúng phụ thuộc vào máy chủ và có thể không hoạt động trên bất kỳ máy nào khác. Vì lý do này, không có Dockerfile tương đương để gắn các thư mục máy chủ vào container. Ngoài ra, hãy lưu ý rằng hệ thống máy chủ không có kiến ​​thức về chính sách TỰ ĐỘNG của container. Do đó, nếu chính sách SELinux được thi hành, thư mục máy chủ được gắn kết không thể ghi vào vùng chứa, bất kể cài đặt rw. Hiện tại, bạn có thể giải quyết vấn đề này bằng cách chỉ định loại chính sách SELinux thích hợp cho thư mục máy chủ ":

chcon -Rt svirt_sandbox_file_t host_dir

Trong đó host_dir là đường dẫn đến thư mục trên hệ thống máy chủ được gắn vào container.

Nó dường như chỉ là một cách giải quyết, nhưng tôi đã thử và nó hoạt động.


14

Tôi đã xác minh rằng chcon -Rt svirt_sandbox_file_t /path/to/volume nó hoạt động và bạn không phải chạy như một container đặc quyền.

Đây là trên:

  • Docker phiên bản 0.11.1-dev, xây dựng 02d20af / 0.11.1
  • CentOS 7 là máy chủ lưu trữ và bộ chứa có bật Selinux.

2
Xem github.com/docker/docker/pull/5910 để được hỗ trợ chính thức cho việc dán nhãn lại trong Docker.
cpuguy83

13

Hãy thử 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

Hãy xem tài liệu https://docs.docker.com/engine/reference/commandline/volume_create/


3
Đã thử rất nhiều câu trả lời về vấn đề này trên SO, nhưng thực sự điều này đã giúp ích. Cảm ơn!
Paul

Nó đã giải quyết được lỗi của sự cho phép. Nhưng bây giờ nếu tôi đang cố gắn vị trí vật lý thì nó sẽ gắn voulme ???? @ cupen
kunal verma

1
@kunalverma Vâng. Nếu bạn không thích nó, đây là câu trả lời dễ dàng hơn. stackoverflow.com/a/31334443/4909388
cupen

4

Tôi gặp vấn đề tương tự, lỗi của tôi là do sự không khớp giữa UID của máy chủ và UID của người dùng. Cách khắc phục là chuyển UID của người dùng làm đối số cho bản dựng docker và tạo người dùng chứa cùng UID.

Trong DockerFile:

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

Trong bước xây dựng:

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

Sau đó, chạy container và các lệnh theo OP đã cho tôi kết quả mong đợi.


1
Điều gì xảy ra nếu bạn không biết UID cho đến khi hết giờ? (Tôi đang xây dựng hình ảnh cho đồng nghiệp, để đóng gói một số công cụ ghi lại vào hệ thống tệp của họ, nhưng họ có các UID khác nhau). Tôi đoán tôi có thể giữ nó root và chỉ adduser khi chạy?
inger

Thật không may, tôi không có câu trả lời tốt cho điều đó. Nếu bất cứ ai khác có một giải pháp tôi cũng sẽ quan tâm đến nó. Tôi nghi ngờ chức năng nhập điểm Docker có thể cung cấp một giải pháp.
RoboCop87

0

Tôi đã giải quyết vấn đề đó bằng cách sử dụng bộ chứa dữ liệu, điều này cũng có lợi thế là cách ly dữ liệu khỏi lớp ứng dụng. Bạn có thể chạy nó như thế này:

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

Hướng dẫn này cung cấp một lời giải thích tốt về việc sử dụng các thùng chứa dữ liệu.


-1

Trong tình huống của tôi, vấn đề là khác nhau. Tôi không biết tại sao, nhưng ngay cả khi thư mục trên máy chủ đã chmod 777chạy trên nó, bên trong docker, nó vẫn hiển thị dưới dạng755 .

Chạy bên trong container sudo chmod 777 my_volume_dircố định nó.


5
chmod 777hầu như không bao giờ sửa chữa bất cứ điều gì.
Erki Aring

Tôi xin lỗi, nhưng bạn đã bỏ lỡ điểm. Vấn đề là các đặc quyền bên trong container đã được hạ xuống và nó không thể được sửa từ bên ngoài.
CodeSandwich

-2

sudo -s đã lừa tôi trên MAC


1
Nếu bạn đang xuống cấp, hãy để lại nhận xét và giải thích lý do. Tôi đã gặp vấn đề chính xác tương tự và tôi đã có thể giải quyết vấn đề này bằng sudo -s.
Nachiket Joshi

Không phải mọi hình ảnh docker đều có sudo và không thể có trong mọi kịch bản.
SOFe

2
Đừng cài đặt sudo trên container. Kẻ tấn công có thể sử dụng sudo bên trong một container.
Arnold Balliu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.