2016-02-09 53 views
48

ドッカーでは、コンテナ内で作成されたファイルは、ホストから検証するときに予測できない所有権を持つ傾向があります。ボリューム上のファイルの所有者は、デフォルトではroot(uid 0)ですが、root以外のユーザーアカウントがコンテナに関与してファイルシステムに書き込むとすぐに、所有者はホストの観点から多かれ少なかれランダムになります。Dockerと--userns-remap、ボリュームのパーミッションを管理してホストとコンテナ間でデータを共有する方法は?

dockerコマンドを呼び出すのと同じユーザーアカウントを使用してホストからボリュームデータにアクセスする必要がある場合は、問題です。

典型的な回避策が

  • (非ポータブル)Dockerfilesに作成時にユーザーのUIDを強制されている環境変数としてdocker runコマンドにホストユーザーのUIDを渡し、その後にいくつかのchownのコマンドを実行している
  • エントリポイントスクリプト内のボリューム。

これらのソリューションの両方を使用すると、コンテナの外にある実際のアクセス許可をいくらか制御できます。

私はこの問題の最終解決策としてユーザーネームスペースが必要であると予想していました。最近リリースされたバージョン1.10でいくつかのテストを実行し、デスクトップアカウントに--userns-remapを設定しました。しかし、マウントされたボリュームのファイル所有権を扱い易くすることができるとは確信していませんが、実際には反対になる可能性があります。

は、私は、この基本的なコンテナ

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

を開始し、ホストからのコンテンツを調べるとします

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

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

この番号「100000」は、私のホストユーザーのサブUIDですが、以来、私のユーザのUIDには対応していませんが、特権なしでtest.txtを編集することはできません。このサブユーザーは、ドッカー以外の私の実際の正規ユーザーとの親和性を持たないようです。マップされていません。

この記事の前半で説明した、ホストとコンテナ間のUIDの整列からなる回避策は、ネームスペースで発生するUID->sub-UIDマッピングのためにはもう機能しません。

次に、ドッカーを実行しているホストユーザーがボリュームで生成されたファイルを所有することを可能にする一方で、ユーザーネームスペースを有効にして(セキュリティを強化するために)ドッカーを実行する方法はありますか?

+0

私はあなたがホストネームスペースとコンテナの間でボリュームを共有しようとしているのであれば、ソリューションの一部にはならないと思います。 2番目のオプション(「ホストユーザーのUIDをdocker runコマンドに環境変数として渡し、エントリポイントスクリプト内のボリュームに対していくつかのchownコマンドを実行する」)がおそらく最適な解決策です。 – larsks

+3

Docker自体は、ホストマウントの書き込み可能なボリュームの使用を推奨していないようです。私はクラウドサービスを実行しておらず、自分自身の信頼できる画像のみを使用しているので、今やユーザNSのセキュリティ上の利点があまりにも多くの利便性を犠牲にする価値があるのか​​疑問に思っています。 –

+0

@StéphaneC。あなたはおそらくより良いアプローチを見つけましたか? – EightyEight

答えて

31

事前にユーザーとグループを事前に割り当てることができれば、ホストユーザーがコンテナー内の名前空間を持つユーザーに対応するような方法でUIDとGIDを割り当てることができます。

これは例です(Ubuntu 14.04、Docker 1)。10):

  1. 一定の数値IDを持つ一部のユーザーを作成します。/etc/subuid/etc/subgidファイルで

    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. 手動編集自動生成された下位のID範囲:

    ns1:500000:65536 
    

    を(そこに注意してくださいMAX_UIDMAX_GIDのためのns1-rootns1-user1のレコードはありません、

    DOCKER_OPTS="--userns-remap=ns1" 
    

    再起動デーモンservice docker restart/var/lib/docker/500000.500000ディレクトリが作成されていることを確認:その

  3. /etc/login.defs/etc/default/dockerでユーザーの名前空間を有効にします。

    さて、内側の容器はあなたがrootuser1を持っている、そしてホスト上 - ns1-rootns1-user1、マッチングのID

    とUPDATE: root以外のユーザーは、容器にIDを固定していることを保証するために(たとえば、user1 1000:1000)、イメージビルド中に明示的に作成します。

テストドライブ:

  1. mkdir /vol1 
    chown ns1-root:ns1-root /vol1 
    
  2. ボリュームのディレクトリを用意し

    docker run --rm -ti -v /vol1:/vol1 busybox sh 
    echo "Hello from container" > /vol1/file 
    exit 
    
  3. コンテナから、それを試してみてくださいホストから試してみてください

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

ないポータブルとハックのように見えますが、動作します。

+2

非常に興味深く+1に値する。しかし、イメージのuser1にUID 1000が割り当てられていることを確認する必要があります。そうしないと、ホスト上でUID 501000を受け取ることができません。 IDが1000に設定されたユーザで多くの異なるイメージを実行している場合、式が常に「subUID lower bound + UID in image」であることは絶対に確信していますか? –

+0

@StéphaneC。いい視点ね!画像内でのIDの固定に関する注意を追加しました。数式については、私自身のイメージをさらに試してみようと思います。もし何かを見つけたら答えを更新してください。 – amartynov

+0

ホストとコンテナの中で手作業でユーザーとグループを手配する場合、本当に "ユーザーネームスペース"機能が必要ですか? – Tristan

2

docker cp commandを使用すると、アクセス許可の問題を回避できます。

所有権は、宛先のユーザーおよびプライマリグループに設定されます。たとえば、コンテナにコピーされたファイルは、ルートユーザーのUID:GIDで作成されます。ローカルマシンにコピーされたファイルは、docker cpコマンドを呼び出したユーザーのUID:GIDで作成されます。ここで

あなたの例ではdocker cpを使用するように切り替えている:あなただけのコンテナからファイルを読みたい場合は

$ docker run -ti -v /data debian:jessie /bin/bash 
[email protected]:/# echo 'hello' > /data/test.txt 
[email protected]:/# 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 
$ 

しかし、あなたが名前のボリュームを必要としません。この例では、代わりにというボリュームの名前のコンテナを使用しています。

$ docker run -ti --name sandbox1 debian:jessie /bin/bash 
[email protected]:/# echo 'howdy' > /tmp/test.txt 
[email protected]:/# 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 
$ 

私はthis questionで説明したように、コンテナにファイルをコピーする際にボリュームが便利という名前を見つけます。

+0

しかし、 'docker cp'はデータの複製を伴います。さらに、文書によれば、コンテナにデータをコピーするときには、ルートユーザーに応じて所有権IDを設定します。これは、コンテナ化されたアプリケーションを実行しているアカウントではないことがよくあります。私はそれが私たちの問題をどのように解決するのか見当たりません。 –

+0

そうです、@Stéphane、データの複製が必要です。ただし、ファイルのコピーを作成すると、ホストとコンテナに異なる所有権とアクセス許可を割り当てることができます。 'docker cp'は、tarアーカイブをコンテナの内部または外部にストリームするときに、ファイルの所有権を完全に制御します。 tarファイルの各エントリの所有権とアクセス権を調整することができます。これにより、rootユーザーに制限されません。 –

関連する問題