Docker und --userns-remap, wie werden Volume-Berechtigungen verwaltet, um Daten zwischen Host und Container auszutauschen?


92

In Docker haben Dateien, die in Containern erstellt wurden, in der Regel einen unvorhersehbaren Besitz, während sie vom Host aus überprüft werden. Der Eigentümer der Dateien auf einem Volume ist standardmäßig root (UID 0). Sobald jedoch Nicht-Root-Benutzerkonten in den Container eingebunden sind und in das Dateisystem schreiben, werden die Eigentümer aus Host-Sicht mehr oder weniger zufällig.

Dies ist ein Problem, wenn Sie mit demselben Benutzerkonto, das die Docker-Befehle aufruft, auf Datenträgerdaten vom Host zugreifen müssen.

Typische Problemumgehungen sind

  • Erzwingen von Benutzer-UIDs zur Erstellungszeit in Docker-Dateien (nicht portierbar)
  • Übergeben der UID des Hostbenutzers an den docker runBefehl als Umgebungsvariable und Ausführen einiger chownBefehle auf den Volumes in einem Einstiegspunktskript.

Beide Lösungen können eine gewisse Kontrolle über die tatsächlichen Berechtigungen außerhalb des Containers geben.

Ich habe erwartet, dass Benutzernamensräume die endgültige Lösung für dieses Problem darstellen. Ich habe einige Tests mit der kürzlich veröffentlichten Version 1.10 und --userns-remap durchgeführt, die auf mein Desktop-Konto eingestellt sind. Ich bin mir jedoch nicht sicher, ob es den Umgang mit Dateien auf bereitgestellten Volumes erleichtern kann. Ich befürchte, dass es tatsächlich das Gegenteil sein könnte.

Angenommen, ich starte diesen Basiscontainer

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

Überprüfen Sie anschließend den Inhalt des Hosts:

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

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

Diese Nummer '100000' ist eine Unter-UID meines Hostbenutzers. Da sie jedoch nicht der UID meines Benutzers entspricht, kann ich test.txt immer noch nicht ohne Berechtigungen bearbeiten. Dieser Unterbenutzer scheint keine Affinität zu meinem tatsächlichen regulären Benutzer außerhalb von Docker zu haben. Es ist nicht zurück abgebildet.

Die zuvor in diesem Beitrag erwähnten Problemumgehungen, die darin bestanden, UIDs zwischen dem Host und dem Container auszurichten, funktionieren aufgrund der UID->sub-UIDim Namespace auftretenden Zuordnung nicht mehr .

Gibt es dann eine Möglichkeit, Docker mit aktiviertem Benutzernamensraum auszuführen (um die Sicherheit zu verbessern), während der Hostbenutzer, der Docker ausführt, weiterhin die auf Volumes generierten Dateien besitzen kann?


Ich denke, wenn Sie Volumes zwischen dem Host und dem Container gemeinsam nutzen, werden Benutzernamensräume nicht Teil der Lösung sein. Ihre zweite Option ("Übergeben der UID des Hostbenutzers an den Docker-Ausführungsbefehl als Umgebungsvariable und anschließendes Ausführen einiger Chown-Befehle auf den Volumes in einem Einstiegspunktskript") ist wahrscheinlich die beste Lösung.
Larsks

4
Docker selbst scheint die Verwendung von vom Host bereitgestellten beschreibbaren Volumes nicht zu fördern. Da ich keinen Cloud-Dienst betreibe und nur meine eigenen vertrauenswürdigen Images verwende, frage ich mich jetzt, ob der Sicherheitsvorteil des Benutzers NS es wert ist, so viel Komfort zu opfern.
Stéphane C.

@ StéphaneC. Haben Sie vielleicht einen besseren Ansatz gefunden?
Achtundachtzig

4
Leider nein, es ist immer noch meine Wahl, keinen Benutzernamensraum zu verwenden und UIDs vom Host zu übergeben. Ich hoffe, dass es in Zukunft einen geeigneten Weg gibt, Benutzer zuzuordnen. Ich bezweifle es, aber trotzdem halte ich ein Auge offen.
Stéphane C.

Antworten:


45

Wenn Sie Benutzer und Gruppen im Voraus vorab anordnen können, können Sie UIDs und GIDs so spezifisch zuweisen, dass Hostbenutzer Benutzern mit Namespace in Containern entsprechen.

Hier ist ein Beispiel (Ubuntu 14.04, Docker 1.10):

  1. Erstellen Sie einige Benutzer mit festen numerischen IDs:

    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. Bearbeiten Sie automatisch generierte untergeordnete ID-Bereiche in /etc/subuidund /etc/subgidDateien manuell :

    ns1:500000:65536
    

    (Beachten Sie, dass es keine Aufzeichnungen für ns1-rootund ns1-user1aufgrund von MAX_UIDund MAX_GIDGrenzen in gibt. /etc/login.defs)

  3. Aktivieren Sie Benutzernamensräume in /etc/default/docker:

    DOCKER_OPTS="--userns-remap=ns1"
    

    Starten Sie den Daemon neu service docker restartund stellen Sie sicher, dass das /var/lib/docker/500000.500000Verzeichnis erstellt wurde.

    Jetzt haben Sie in Containern rootund user1und auf dem Host - ns1-rootund ns1-user1mit passenden IDs

    UPDATE: Um sicherzustellen, dass Nicht-Root-Benutzer feste IDs in Containern haben (z. B. Benutzer1 1000: 1000), erstellen Sie diese explizit während der Image-Erstellung.

Probefahrt:

  1. Bereiten Sie ein Volume-Verzeichnis vor

    mkdir /vol1
    chown ns1-root:ns1-root /vol1
    
  2. Probieren Sie es aus einem Behälter

    docker run --rm -ti -v /vol1:/vol1 busybox sh
    echo "Hello from container" > /vol1/file
    exit
    
  3. Versuchen Sie es vom Host

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

Nicht tragbar und sieht aus wie ein Hack, funktioniert aber.


3
Sehr interessant und verdient eine +1. Sie müssen jedoch weiterhin sicherstellen, dass Benutzer1 in Ihrem Image die UID 1000 zugewiesen hat. Andernfalls können Sie nicht sicher sein, ob die UID 501000 auf dem Host empfangen wird. Übrigens sind wir uns absolut sicher, dass die Formel immer subUID lower bound + UID in imagedann lautet, wenn wir viele verschiedene Bilder mit einem Benutzer ausführen, dessen ID auf 1000 gesetzt ist?
Stéphane C.

@ StéphaneC. Guter Punkt! Hinweis zum Korrigieren von IDs in Bildern hinzugefügt. Was die Formel
betrifft

1
Wenn Sie Benutzer und Gruppen manuell in Hosts und Containern anordnen, benötigen Sie wirklich die Funktion "Benutzernamensraum"?
Tristan

1
Der von Ihnen erstellte Namespace trennt Hostbenutzer von Containerbenutzern. Möglicherweise benötigen Sie jedoch mehrere Namespace für Container, insbesondere wenn offizielle Bilder (wie das MySQL-Namespace) einen Benutzer ohne explizite UID erstellen. Wie gehen Sie mit mehreren Namespaces um, wenn die Option --userns-remap nur einen erwartet?
Tristan

2
@amartynov Darf ich fragen, warum Sie sich die Mühe gemacht haben, eine UID (5000) für Ihren Benutzer "ns1" anzugeben? Da es sich um den Namen (nicht die UID) handelt, auf den Sie in den Subuid- und Subgid-Dateien verweisen, sollte es anscheinend keine Rolle spielen, welche UID dieser Benutzer erhält. Vermisse ich eine Beziehung, wie die Ähnlichkeit zwischen 5000 und 500000 vermuten lässt?
Jollymorphic

3

Eine Problemumgehung besteht darin, die Benutzer-UID während der Erstellungszeit dynamisch dem Host zuzuweisen.

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

Dann bauen als:

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

und laufen als:

docker run mycontainer

Wenn Sie bereits einen Container haben, erstellen Sie einen Wrapper-Container mit den folgenden Angaben Dockerfile:

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

Dies kann wie folgt eingepackt werden docker-compose.yml:

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

Dann erstellen und ausführen als:

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

1
Ich möchte nicht unfreundlich aussehen, aber dies ist tatsächlich eine der Problemumgehungen, die in der ursprünglichen Frage aufgeführt sind, aber keine Lösung und bezieht sich nicht auf Benutzernamensräume.
Stéphane C.

@ StéphaneC. Können Sie diese verwandte Frage kommentieren? stackoverflow.com/questions/60274418/…
Überaustausch

0

Mit dem docker cpBefehl können Sie Berechtigungsprobleme vermeiden .

Die Eigentümerschaft wird auf den Benutzer und die primäre Gruppe am Ziel festgelegt. Beispielsweise werden Dateien, die in einen Container kopiert wurden, mit UID:GIDdem Root-Benutzer erstellt. Auf den lokalen Computer kopierte Dateien werden mit dem UID:GIDdes Benutzers erstellt, der den docker cpBefehl aufgerufen hat .

Hier ist Ihr Beispiel umgeschaltet, um zu verwenden 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
$ 

Wenn Sie jedoch nur Dateien aus einem Container lesen möchten, benötigen Sie das angegebene Volume nicht. In diesem Beispiel wird ein benannter Container anstelle eines benannten Volumes verwendet:

$ 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
$ 

Ich finde benannte Volumes nützlich, wenn ich Dateien in einen Container kopieren möchte, wie in dieser Frage beschrieben .


Aber docker cpbeinhaltet das Duplizieren von Daten. Darüber hinaus werden laut Dokument beim Kopieren von Daten in einen Container Eigentümer-IDs entsprechend dem Root-Benutzer festgelegt, bei dem es sich häufig nicht um das Konto handelt, auf dem die containerisierte App ausgeführt wird. Ich verstehe nicht, wie es unser Problem löst.
Stéphane C.

Sie haben Recht, @ Stéphane, es geht darum, Daten zu duplizieren. Wenn Sie jedoch Kopien der Dateien erstellen, können Sie dem Host und dem Container unterschiedliche Eigentumsrechte und Berechtigungen zuweisen. docker cpSie haben die volle Kontrolle über den Dateieigentum, wenn Sie ein Teerarchiv in einen Container oder aus einem Container streamen. Sie können den Besitz und die Berechtigungen jedes Eintrags in der TAR-Datei beim Streamen anpassen, sodass Sie nicht auf den Root-Benutzer beschränkt sind.
Don Kirkby
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.