Docker và --usern-remap, làm cách nào để quản lý quyền khối lượng để chia sẻ dữ liệu giữa máy chủ và vùng chứa?


96

Trong docker, các tệp được tạo bên trong vùng chứa có xu hướng có quyền sở hữu không thể đoán trước trong khi kiểm tra chúng từ máy chủ. Theo mặc định, chủ sở hữu của các tệp trên ổ đĩa là root (uid 0), nhưng ngay khi các tài khoản người dùng không phải root tham gia vào vùng chứa và ghi vào hệ thống tệp, chủ sở hữu ít nhiều trở nên ngẫu nhiên từ góc độ máy chủ.

Đó là một vấn đề khi bạn cần truy cập dữ liệu khối lượng từ máy chủ lưu trữ bằng cùng một tài khoản người dùng đang gọi các lệnh docker.

Các cách giải quyết điển hình là

  • buộc người dùng uID tại thời điểm tạo trong Dockerfiles (không di động)
  • chuyển UID của người dùng máy chủ tới docker runlệnh dưới dạng một biến môi trường và sau đó chạy một số chownlệnh trên các ổ đĩa trong một tập lệnh entrypoint.

Cả hai giải pháp này đều có thể cung cấp một số quyền kiểm soát đối với các quyền thực tế bên ngoài vùng chứa.

Tôi mong đợi không gian tên người dùng là giải pháp cuối cùng cho vấn đề này. Tôi đã chạy một số thử nghiệm với phiên bản 1.10 được phát hành gần đây và --usern-remap được đặt cho tài khoản máy tính để bàn của mình. Tuy nhiên, tôi không chắc rằng nó có thể làm cho quyền sở hữu tệp trên các ổ được gắn kết dễ dàng hơn để xử lý, tôi sợ rằng nó thực sự có thể ngược lại.

Giả sử tôi bắt đầu vùng chứa cơ bản này

docker run -ti -v /data debian:jessie /bin/bash
echo 'hello' > /data/test.txt
exit

Và sau đó kiểm tra nội dung từ máy chủ:

ls -lh /var/lib/docker/100000.100000/volumes/<some-id>/_data/

-rw-r--r-- 1 100000 100000 6 Feb  8 19:43 test.txt

Số '100000' này là UID phụ của người dùng máy chủ của tôi, nhưng vì nó không tương ứng với UID của người dùng của tôi, tôi vẫn không thể chỉnh sửa test.txt nếu không có đặc quyền. Người dùng phụ này dường như không có bất kỳ mối quan hệ nào với người dùng thông thường thực sự của tôi bên ngoài docker. Nó không được ánh xạ lại.

Các cách giải quyết được đề cập trước đó trong bài đăng này bao gồm việc căn chỉnh UID giữa máy chủ và vùng chứa không hoạt động nữa do UID->sub-UIDánh xạ xảy ra trong không gian tên.

Sau đó, có cách nào để chạy docker với không gian tên người dùng được bật (để cải thiện bảo mật), trong khi vẫn giúp người dùng máy chủ chạy docker có thể sở hữu các tệp được tạo trên ổ đĩa không?


Tôi nghĩ rằng nếu bạn đang chia sẻ khối lượng giữa máy chủ và vùng chứa thì không gian tên người dùng sẽ không phải là một phần của giải pháp. Tùy chọn thứ hai của bạn ("chuyển UID của người dùng máy chủ đến lệnh chạy docker dưới dạng biến môi trường và sau đó chạy một số lệnh chown trên các ổ đĩa trong tập lệnh entrypoint") có lẽ là giải pháp tốt nhất.
larsks

4
Bản thân Docker dường như không khuyến khích sử dụng khối lượng có thể ghi được gắn trên máy chủ. Vì tôi không chạy dịch vụ đám mây và chỉ sử dụng hình ảnh đáng tin cậy của riêng mình, nên giờ tôi đang tự hỏi liệu lợi ích bảo mật của NS người dùng có đáng để hy sinh nhiều tiện lợi như vậy không.
Stéphane C.

@ StéphaneC. Có lẽ bạn đã tìm thấy một cách tiếp cận tốt hơn?
EightyEight

4
Rất tiếc là không, không sử dụng không gian tên người dùng và chuyển UID từ máy chủ lưu trữ vẫn là lựa chọn của tôi. Tôi hy vọng sẽ có một cách thích hợp để lập bản đồ người dùng trong tương lai. Tôi nghi ngờ điều đó nhưng tôi vẫn để mắt đến.
Stéphane C.

Câu trả lời:


46

Nếu bạn có thể sắp xếp trước người dùng và nhóm trước, thì bạn có thể chỉ định UID và GID theo cách cụ thể để người dùng máy chủ lưu trữ tương ứng với người dùng có không gian tên bên trong vùng chứa.

Đây là một ví dụ (Ubuntu 14.04, Docker 1.10):

  1. Tạo một số người dùng có ID số cố định:

    useradd -u 5000 ns1
    
    groupadd -g 500000 ns1-root
    groupadd -g 501000 ns1-user1
    
    useradd -u 500000 -g ns1-root ns1-root
    useradd -u 501000 -g ns1-user1 ns1-user1 -m
    
  2. Chỉnh sửa thủ công các dải ID cấp dưới được tạo tự động trong /etc/subuid/etc/subgidcác tệp:

    ns1:500000:65536
    

    (lưu ý không có hồ sơ cho ns1-rootns1-user1đến hạn MAX_UIDMAX_GIDgiới hạn trong /etc/login.defs)

  3. Bật không gian tên người dùng trong /etc/default/docker:

    DOCKER_OPTS="--userns-remap=ns1"
    

    Khởi động lại daemon service docker restart, đảm bảo /var/lib/docker/500000.500000thư mục được tạo.

    Bây giờ, bên trong các vùng chứa bạn có rootuser1và trên máy chủ lưu trữ - ns1-rootns1-user1với các ID phù hợp

    CẬP NHẬT: để đảm bảo rằng người dùng không phải root có ID cố định trong vùng chứa (ví dụ: user1 1000: 1000), hãy tạo chúng một cách rõ ràng trong quá trình xây dựng hình ảnh.

Lái thử:

  1. Chuẩn bị một thư mục khối lượng

    mkdir /vol1
    chown ns1-root:ns1-root /vol1
    
  2. Hãy thử nó từ một thùng chứa

    docker run --rm -ti -v /vol1:/vol1 busybox sh
    echo "Hello from container" > /vol1/file
    exit
    
  3. Thử từ máy chủ

    passwd ns1-root
    login ns1-root
    cat /vol1/file
    echo "can write" >> /vol1/file
    

Không di động và trông giống như một bản hack, nhưng hoạt động.


3
Rất thú vị và xứng đáng được +1. Nhưng bạn vẫn cần đảm bảo rằng user1 trong hình ảnh của bạn được gán UID 1000. Nếu không, bạn không thể chắc chắn rằng nó sẽ nhận UID 501000 trên máy chủ. Btw, chúng ta có hoàn toàn chắc chắn rằng công thức luôn là subUID lower bound + UID in imagenếu chúng ta đang chạy nhiều hình ảnh khác nhau với một người dùng có ID được đặt thành 1000 không?
Stéphane C.

@ StéphaneC. Điểm tốt! Đã thêm ghi chú về việc sửa ID bên trong hình ảnh. Đối với công thức, tôi sẽ thử nghiệm thêm với hình ảnh của riêng tôi và sẽ cập nhật câu trả lời nếu tìm thấy bất cứ điều gì
amartynov

1
Nếu bạn sắp xếp người dùng và nhóm theo cách thủ công trong máy chủ lưu trữ và trong vùng chứa, bạn có thực sự cần tính năng "không gian tên người dùng" không?
Tristan

1
Không gian tên bạn tạo ngăn cách người dùng máy chủ lưu trữ với người dùng vùng chứa, nhưng bạn có thể cần nhiều không gian tên cho vùng chứa, đặc biệt khi hình ảnh chính thức (như hình ảnh mysql) tạo người dùng mà không có uid rõ ràng. Làm thế nào để bạn đối phó với nhiều không gian tên khi tùy chọn --usern-remap chỉ mong đợi một?
Tristan

2
@amartynov Tôi có thể hỏi tại sao bạn lại gặp khó khăn khi chỉ định UID (5000) cho người dùng "ns1" của mình không? Vì đó là tên (không phải UID) mà bạn tham chiếu trong các tệp subuid và subgid, có vẻ như người dùng này nhận được UID gì không quan trọng. Có phải tôi đang bỏ lỡ mối quan hệ nào đó không, vì sự tương đồng giữa 5000 và 500000 có thể gợi ý?
Jollymorphic

2

Một giải pháp là chỉ định động uid của người dùng theo thời gian xây dựng để phù hợp với máy chủ.

Ví dụ Dockerfile:

FROM ubuntu
# Defines argument which can be passed during build time.
ARG UID=1000
# Create a user with given UID.
RUN useradd -d /home/ubuntu -ms /bin/bash -g root -G sudo -u $UID ubuntu
# Switch to ubuntu user by default.
USER ubuntu
# Check the current uid of the user.
RUN id
# ...

Sau đó, xây dựng như:

docker build --build-arg UID=$UID -t mycontainer .

và chạy như:

docker run mycontainer

Nếu bạn đã có vùng chứa, hãy tạo vùng chứa trình bao bọc với những thứ sau Dockerfile:

FROM someexistingcontainer
ARG UID=1000
USER root
# This assumes you've the existing user ubuntu.
RUN usermod -u $UID ubuntu
USER ubuntu

Điều này có thể được gói gọn trong docker-compose.ymlnhư sau:

version: '3.4'
services:
  myservice:
    command: id
    image: myservice
    build:
      context: .
    volumes:
    - /data:/data:rw

Sau đó xây dựng và chạy như:

docker-compose build --build-arg UID=$UID myservice; docker-compose run myservice

1
Tôi sẽ không muốn nhìn không thân thiện nhưng đây thực sự là một trong những cách giải quyết được liệt kê trong câu hỏi ban đầu, nhưng không phải là giải pháp và không liên quan đến không gian tên người dùng.
Stéphane C.

@ StéphaneC. Bạn có thể bình luận về câu hỏi liên quan này? stackoverflow.com/questions/60274418/…
overexchange

-1

Bạn có thể tránh các vấn đề về quyền bằng cách sử dụng docker cplệnh .

Quyền sở hữu được đặt thành người dùng và nhóm chính tại đích. Ví dụ: các tệp được sao chép vào vùng chứa được tạo bằng UID:GIDngười dùng root. Các tệp được sao chép vào máy cục bộ được tạo với UID:GIDngười dùng đã gọi docker cplệnh.

Đây là ví dụ của bạn được chuyển sang sử dụng docker cp:

$ docker run -ti -v /data debian:jessie /bin/bash
root@e33bb735a70f:/# echo 'hello' > /data/test.txt
root@e33bb735a70f:/# exit
exit
$ docker volume ls
DRIVER              VOLUME NAME
local               f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93
$ sudo ls -l /var/lib/docker/100000.100000/volumes/f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93/_data
total 4
-rw-r--r-- 1 100000 100000 6 Oct  6 10:34 test.txt
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
e33bb735a70f        debian:jessie       "/bin/bash"         About a minute ago   Exited (0) About a minute ago                       determined_hypatia
$ docker cp determined_hypatia:/data/test.txt .
$ ls -l test.txt 
-rw-r--r-- 1 don don 6 Oct  6 10:34 test.txt
$ cat test.txt
hello
$ 

Tuy nhiên, nếu bạn chỉ muốn đọc tệp từ vùng chứa, bạn không cần ổ đĩa được đặt tên. Ví dụ này sử dụng một vùng chứa được đặt tên thay vì một tập đã đặt tên:

$ docker run -ti --name sandbox1 debian:jessie /bin/bash
root@93d098233cf3:/# echo 'howdy' > /tmp/test.txt
root@93d098233cf3:/# exit
exit
$ docker cp sandbox1:/tmp/test.txt .
$ ls -l test.txt
-rw-r--r-- 1 don don 6 Oct  6 10:52 test.txt
$ cat test.txt
howdy
$ 

Tôi thấy các tập được đặt tên hữu ích khi tôi muốn sao chép tệp vào một vùng chứa, như được mô tả trong câu hỏi này .


Nhưng docker cpliên quan đến việc nhân bản dữ liệu. Hơn nữa, theo tài liệu, khi sao chép dữ liệu vào vùng chứa, nó đặt ID quyền sở hữu theo người dùng gốc, thường không phải là tài khoản chạy ứng dụng được chứa. Tôi không biết nó giải quyết vấn đề của chúng ta như thế nào.
Stéphane C.

Bạn nói đúng, @ Stéphane, nó liên quan đến việc sao chép dữ liệu. Tuy nhiên, việc tạo bản sao của các tệp cho phép bạn chỉ định quyền sở hữu và quyền khác nhau trên máy chủ lưu trữ và trong vùng chứa. docker cpcung cấp cho bạn toàn quyền kiểm soát quyền sở hữu tệp khi bạn truyền trực tuyến lưu trữ tar vào hoặc ra khỏi vùng chứa. Bạn có thể điều chỉnh quyền sở hữu và quyền của từng mục nhập trong tệp tar khi truyền trực tuyến, vì vậy bạn không bị giới hạn ở người dùng root.
Don Kirkby
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.