Docker共有ボリュームのアクセス許可を管理する(最良の)方法は何ですか?


345

私はしばらくの間Dockerをいじっていて、永続データを処理するときに同じ問題を見つけ続けています。

私は自分を作成Dockerfileし、ボリュームを公開または使用--volumes-fromするために、私のコンテナ内のホストのフォルダをマウントします

ホスト上の共有ボリュームにどのようなアクセス許可を適用する必要がありますか?

私は2つのオプションを考えることができます:

  • これまでのところ、すべてのユーザーに読み取り/書き込みアクセス権を与えているので、Dockerコンテナーからフォルダーに書き込むことができます。

  • ユーザーをホストからコンテナーにマップして、より詳細なアクセス許可を割り当てることができるようにします。しかし、これが可能であるかどうか、そしてそれについてはあまりわかっていません。これまでのところ、私にできることすべては、いくつかのユーザとしてコンテナに実行されますdocker run -i -t -user="myuser" postgresが、このユーザーは、私のホストとは異なるUIDを持っているmyuserので、権限が仕事をしないでください。また、ユーザーのマッピングがセキュリティ上のリスクをもたらすかどうかもわかりません。

他の選択肢はありますか?

この問題をどのように扱っていますか?



1
このトピックについて詳しく説明しているこのスレッドにも興味があるかもしれません。groups.google.com
#!msg


現時点では、Dockerチームはホストディレクトリを指定されたuid / gidのボリュームとしてマウントするためのネイティブソリューションを実装する予定はありません。この問題に関する私のコメントと返信をご覧ください:github.com/docker/docker/issues/7198#issuecomment-230636074
Quinn Comendant

回答:


168

UPDATE 2016-03-02:Docker 1.9.0以降、Dockerはデータのみのコンテナー置き換えるボリューム名前を付けました。以下の回答は、私のリンクされたブログ投稿と同様に、Docker内のデータどのように考えるかという点で価値がありますが、名前付きボリュームを使用して、データコンテナーではなく、以下で説明するパターンを実装することを検討してください。


これを解決する標準的な方法は、データのみのコンテナを使用することだと思います。このアプローチでは、ボリュームデータへのすべてのアクセスは、データコンテナーを使用-volumes-fromするコンテナーを介して行われるため、ホストのuid / gidは重要ではありません。

たとえば、ドキュメントに記載されている使用例の1つは、データボリュームのバックアップです。これを行うには、別のコンテナを使用してバックアップを行います。また、ボリュームをマウントするためにtarも使用-volumes-fromします。したがって、grokの重要なポイントは、適切な権限でホスト上のデータにアクセスする方法を考えるのではなく、別のコンテナを介して、必要なこと(バックアップ、参照など)を行う方法を考えることです。 。コンテナー自体は一貫したuid / gidを使用する必要がありますが、ホスト上の何にもマップする必要がないため、移植性が維持されます。

これは私にとっても比較的新しいものですが、特定のユースケースがある場合は、遠慮なくコメントしてください。答えをさらに詳しく説明します。

更新:コメント内の特定の使用例では、some/graphiteグラファイトを実行するためのイメージsome/graphitedataと、データコンテナーとしてのイメージがある場合があります。したがって、ポートなどを無視するとDockerfile、イメージsome/graphitedataは次のようになります。

FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
  && useradd -r -g graphite graphite
RUN mkdir -p /data/graphite \
  && chown -R graphite:graphite /data/graphite
VOLUME /data/graphite
USER graphite
CMD ["echo", "Data container for graphite"]

データコンテナをビルドして作成します。

docker build -t some/graphitedata Dockerfile
docker run --name graphitedata some/graphitedata

some/graphiteDockerfileも同じUID / GIDのを取得する必要があり、そのためには、次のようになります。

FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
  && useradd -r -g graphite graphite
# ... graphite installation ...
VOLUME /data/graphite
USER graphite
CMD ["/bin/graphite"]

そしてそれは次のように実行されます:

docker run --volumes-from=graphitedata some/graphite

OK、これでグラファイトコンテナーと関連するデータのみのコンテナーに正しいユーザー/グループが提供されました(some/graphiteデータコンテナーのコンテナーを再利用することもできます。実行時にentrypoing / cmdをオーバーライドしますが、別の画像IMOはより明確です)。

ここで、データフォルダ内の何かを編集したいとします。そのため、ボリュームのホストへのバインドマウントとそこでの編集ではなく、そのジョブを実行する新しいコンテナーを作成します。それを呼ぶことができますsome/graphitetoolssome/graphite画像のように、適切なユーザー/グループも作成します。

FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
  && useradd -r -g graphite graphite
VOLUME /data/graphite
USER graphite
CMD ["/bin/bash"]

Dockerfile から継承するsome/graphitesome/graphitedata、Dockerfile内でこのDRY を作成するか、または新しいイメージを作成する代わりに、既存のイメージの1つを再利用します(必要に応じてentrypoint / cmdをオーバーライドします)。

今、あなたは単に実行します:

docker run -ti --rm --volumes-from=graphitedata some/graphitetools

そしてvi /data/graphite/whatever.txt。これは、すべてのコンテナに同じグラファイトユーザーがuid / gidが一致しているため、完全に機能します。

/data/graphiteホストからマウントすることはないため、ホストのuid / gidがgraphiteおよびgraphitetoolsコンテナー内で定義されたuid / gidにどのようにマップされるかは問題ではありません。これらのコンテナーは任意のホストにデプロイできるようになり、引き続き完全に機能します。

これについてのすてきなことは、graphitetoolsあらゆる種類の便利なユーティリティとスクリプトがあり、移植可能な方法で展開できることです。

更新2:この回答を書いた後、私はこのアプローチについてより完全なブログ投稿を書くことにしました。お役に立てば幸いです。

更新3:私はこの回答を修正し、詳細を追加しました。以前は、所有権と権限に関するいくつかの誤った前提が含まれていました。所有権は通常、ボリュームの作成時に割り当てられます。これは、ボリュームが作成されるときであるためです。こちらのブログをご覧ください。ただし、これは要件ではありません。データコンテナを「参照/ハンドル」として使用し、エントリポイントのchownを介して別のコンテナに所有権/権限を設定できます。このエントリはgosuで終了し、正しいユーザーとしてコマンドを実行します。誰かがこのアプローチに興味を持っている場合はコメントしてください。このアプローチを使用したサンプルへのリンクを提供できます。


35
データのみのコンテナでも同じ問題が発生するため、これは解決策ではないと思います。結局のところ、このコンテナはホストから共有されたボリュームを使用するため、それらの共有フォルダに対する権限を管理する必要があります。
Xabs 2014年

2
ホストからデータフォルダーを編集する必要がある場合があることを覚えておいてください(つまり、テストグラファイトキーの削除、JIRAテストホームフォルダーの削除、または最新の運用バックアップでの更新...)。コメントから理解できる限り、私は3番目のコンテナーを介してJIRAデータを更新するようなことをしているはずです。いずれにしても、新しいデータフォルダーにどのようなアクセス許可を適用します/data/newcontainerか?dockerrootとして実行していると思います(そうしないことは可能ですか?)また、データがメインコンテナーに直接マウントされている場合、またはデータ専用コンテナーを介してマウントされている場合、これらの権限に違いはありますか?
Xabs 2014年

2
精巧な返信をありがとう。機会があり次第、これをテストします。また、あなたのブログの投稿と、データコンテナに最小限の画像を使用することに関する投稿の両方を参考にしてください
Xabs 2014年

3
このアプローチの唯一の問題は、誤ってコンテナーを削除するのが非常に簡単なことです。それがたまたまあなたのデータコンテナであると想像してください。(CMIIW)データはまだ/var/lib/dockerどこかにあると思いますが、それでも大きな痛みを
伴います

3
「データコンテナーを「参照/ハンドル」として使用し、chownを介して別のコンテナーに所有権/権限をエントリポイントに設定することができます」... @Raman:これは、多くの権限の問題が発生した後、最終的に私を救ったセクションです考え出した。エントリーポイントスクリプトを使用し、これにアクセス許可を設定することは私にとってはうまくいきます。詳しい説明ありがとうございます。これまでにウェブで見つけた中で最高です。
Vanderstaaij、2015年

59

非常にエレガントなソリューションは、公式のredisイメージと一般的にすべての公式のイメージで見ることができます。

ステップバイステップのプロセスで説明されています:

  • 何よりも先にredisユーザー/グループを作成する

Dockerfileコメントに見られるように:

追加する依存関係に関係なく、ユーザーとグループを最初に追加して、IDが一貫して割り当てられるようにします

  • インストールgosu Dockerfileで

gosuはrootユーザーからの簡単なステップダウンのためのsu/の代替ですsudo。(Redisは常にredisユーザーと共に実行されます)

  • /dataボリュームを構成し、workdirとして設定します

VOLUME /dataコマンドで/ dataボリュームを構成することにより、Dockerボリュームまたはホストディレクトリにバインドマウントできる別のボリュームがで​​きます。

これをworkdir(WORKDIR /data)として構成すると、コマンドが実行されるデフォルトのディレクトリになります。

  • docker-entrypointファイルを追加し、デフォルトのCMD redis-serverでENTRYPOINTとして設定します

つまり、すべてのコンテナの実行はdocker-entrypointスクリプトを介して実行され、デフォルトで実行されるコマンドはredis-serverです。

docker-entrypoint現在のディレクトリ(/データ)と降圧の変更の所有権:単純な関数を実行するスクリプトであるrootredis実行するユーザーがredis-server。(実行されたコマンドがredis-serverでない場合、コマンドは直接実行されます。)

これには次の効果があります

/ dataディレクトリがホストにバインドマウントされている場合、docker-entrypointはユーザーの下でredis-serverを実行する前にユーザー権限を準備しredisます。

これにより、任意のボリューム構成でコンテナーを実行するためのセットアップが不要になるという安心感が得られます。

もちろん、異なるイメージ間でボリュームを共有する必要がある場合は、それらが同じユーザーID /グループIDを使用していることを確認する必要があります。そうしないと、最新のコンテナーが以前のコンテナーのユーザー権限をハイジャックします。


11
受け入れられた答えは有益ですが、それは私が実際に問題を解決するための標準的な方法を提供するこの答えを見つけるための許可を持つ欲求不満の道をたどる一週間だけを導いた。
m0meni 2015

3
ここでも非常によく説明されています:denibertovic.com/posts/handling-permissions-with-docker-volumes
kheraud

そう?docker内からボリュームを書き込み可能にするにはどうすればよいですか?スクリプトchownENTRYPOINTですか?
ガーマン、

34

これは間違いなくほとんどの状況で最良の方法ではありませんが、まだ言及されていないため、おそらく誰かを助けるでしょう。

  1. マウントホストボリュームのバインド

    Host folder FOOBAR is mounted in container /volume/FOOBAR

  2. コンテナーの起動スクリプトを変更して、関心のあるボリュームのGIDを見つけます

    $ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)

  3. ユーザーがこのGIDのグループに属していることを確認してください(新しいグループを作成する必要がある場合があります)。この例ではnobody、コンテナー内でユーザーとしてソフトウェアを実行するふりをするのでnobody、グループIDが等しいグループに属していることを確認します。TARGET_GID

  EXISTS=$(cat /etc/group | grep $TARGET_GID | wc -l)

  # Create new group using target GID and add nobody user
  if [ $EXISTS == "0" ]; then
    groupadd -g $TARGET_GID tempgroup
    usermod -a -G tempgroup nobody
  else
    # GID exists, find group name and add
    GROUP=$(getent group $TARGET_GID | cut -d: -f1)
    usermod -a -G $GROUP nobody
  fi

ホストボリュームのグループ権限を簡単に変更でき、それらの更新された権限がDockerコンテナー内で適用されることがわかっているので、これが好きです。これは、ホストフォルダー/ファイルへの許可や所有権の変更なしで発生します。

これは、コンテナ内の任意のグループに自分が追加したとしても、たまたまGIDを使用しているという危険はないと想定しているので、好きではありません。USERDockerfileの節と一緒に使用することはできません(ユーザーがroot権限を持っている場合を除きます)。また、それはハックの仕事を叫びます;-)

ハードコアになりたい場合は、明らかにこれを多くの方法で拡張できます。たとえば、サブファイル、複数のボリュームなどのすべてのグループを検索します。


4
これはマウントされたボリュームからファイルを読み取ることを目的としていますか?Dockerコンテナーを作成したユーザー以外のユーザーが所有していないファイルを書き込むためのソリューションを探しています。
ThorSummoner 2015

私はこのアプローチを2015年8月から使用しています。すべてがOKでした。コンテナー内に作成されたファイルの権限だけが異なっていました。両方のユーザー(コンテナーの内部と外部)は自分のファイルの所有権を持っていますが、このソリューションによって作成された同じグループに属していたため、どちらにも読み取りアクセスがありました。問題は、ユースケースが共通ファイルへの書き込みアクセスを課したときに始まりました。より大きな問題は、共有ボリュームにgitファイル(同じ本番環境で開発ソースファイルをテストするためのボリューム)があったことです。Gitは共有コードへのアクセスの問題について警告し始めました。
yucer 2016年

のより良いgrepは$TARGET_GIDを使用することだと思いますgrep ':$TARGET_GID:'。それ以外の場合、たとえば、コンテナにgid 10001があり、ホストが1000の場合、このチェックはパスしますが、パスしないはずです。
ロブドソン

16

わかりました、これはドッカーの問題#7198追跡されています

とりあえず、これは2番目のオプションを使用して処理しています。

ユーザーをホストからコンテナーにマップする

Dockerfile

#=======
# Users
#=======
# TODO: Idk how to fix hardcoding uid & gid, specifics to docker host machine
RUN (adduser --system --uid=1000 --gid=1000 \
        --home /home/myguestuser --shell /bin/bash myguestuser)

CLI

# DIR_HOST and DIR_GUEST belongs to uid:gid 1000:1000
docker run -d -v ${DIR_HOST}:${DIR_GUEST} elgalu/myservice:latest

更新私は現在、ハミーの 答えにもっと傾倒しています


1
コマンドを使用しid -u <username>id -g <username>id -G <username>代わりに特定のユーザーのユーザーIDとグループIDを取得するには
lolski


15
これは、ホスト間でのコンテナの移植性を破壊します。
ラマン

2
Dockerの問題#7198は、これに対するネイティブソリューションを実装しないという結論に達しました。私のコメントgithub.com/docker/docker/issues/7198#issuecomment-230636074の
Quinn Comendant 2016


12

あなたと同じように、ユーザー/グループをホストからDockerコンテナーにマップする方法を探していましたが、これはこれまでに見つけた最短の方法です。

  version: "3"
    services:
      my-service:
        .....
        volumes:
          # take uid/gid lists from host
          - /etc/passwd:/etc/passwd:ro
          - /etc/group:/etc/group:ro
          # mount config folder
          - path-to-my-configs/my-service:/etc/my-service:ro
        .....

これは私のdocker-compose.ymlからの抜粋です。

アイデアは、ホストからコンテナーにユーザー/グループのリストを(読み取り専用モードで)マウントすることです。そのため、コンテナーの起動後、ホストと同じuid-> username(およびグループ)の一致を持ちます。これで、ホストシステムで動作しているかのように、コンテナー内のサービスのユーザー/グループ設定を構成できます。

コンテナーを別のホストに移動する場合は、サービス構成ファイルのユーザー名をそのホストにあるものに変更するだけです。


これは素晴らしい答えです。システムの残りの部分を公開せずに、ベースシステムでファイルを処理するコンテナを実行する場合は非常に簡単です。
icarito

これが私のお気に入りの答えです。また、docker runコマンドを使用して、現在のユーザー名/グループを経由して同様の推奨事項を他の場所で確認しました-u $( id -u $USER ):$( id -g $USER )。ユーザー名を気にする必要はありません。これは、デフォルトで読み取り/書き込みアクセス権を持つファイル(バイナリーなど)を生成するローカル開発環境に適しています。
matthewcummings516

5

データのみのコンテナーを引き続き使用しますが、(同じuid / gidを持つという点で)アプリケーションコンテナーと同期する必要がないアプローチを次に示します。

おそらく、ログインシェルなしで、非ルート$ USERとしてコンテナ内のいくつかのアプリを実行したいとします。

Dockerfileで:

RUN useradd -s /bin/false myuser

# Set environment variables
ENV VOLUME_ROOT /data
ENV USER myuser

...

ENTRYPOINT ["./entrypoint.sh"]

次に、entrypoint.shで:

chown -R $USER:$USER $VOLUME_ROOT
su -s /bin/bash - $USER -c "cd $repo/build; $@"

5

Dockerコンテナーのルートを安全に変更するには、Dockerホストの使用--uidmap--private-uidsオプションを試してください

https://github.com/docker/docker/pull/4572#issuecomment-38400893

また--cap-drop、セキュリティのために、Dockerコンテナのいくつかの機能()を削除することもできます。

http://opensource.com/business/14/9/security-for-docker

UPDATEサポートが必要ですdocker > 1.7.0

更新バージョン1.10.0(2016-02-04)--userns-remapフラグを 追加https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2


私はdocker 1.3.2 build 39fa2fa(最新)を実行し--uidmapてい--private-uidsますが、オプションやオプションのトレースは表示されません。PRが成功せず、マージされなかったようです。
Leo Gallucci、2014年

それはコアにマージされません、もしあなたが望むなら、あなたはそれをどのようにパッチするかを使うかもしれません。現在では、一部の機能を制限して、ルート以外のユーザーからコンテナでアプリケーションを実行することのみが可能です。
2014年

2015年6月、私はこれがdocker 1.6.2に統合されているのを見ていません。あなたの答えはまだ有効ですか?
Leo Gallucci、2015年

1
問題はまだ解決していません。開発者は1.7バージョンでサポートを追加する必要があります。(--rootオプション) github.com/docker/docker/pull/12648
umount

2
開発者は、この機能を使用してリリースをもう一度移動したようです。Docker開発者の「icecrime」は"We apparently do have so some of conflicting designs between libnetwork and user namespaces ... and something we'd like to get in for 1.8.0. So don't think we're dropping this, we're definitely going to take a break after all these, and see how we need to reconsider the current design and integration of libnetwork to make this possible. Thanks!" github.com/docker/docker/pull/12648と言い ます。次の安定版を待つ必要があると思います。
2015年

4

私のアプローチは、現在のUID / GIDを検出し、コンテナー内にそのようなユーザー/グループを作成し、その下でスクリプトを実行することです。その結果、彼が作成するすべてのファイルは、ホスト上のユーザー(スクリプト)と一致します。

# get location of this script no matter what your current folder is, this might break between shells so make sure you run bash
LOCAL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# get current IDs
USER_ID=$(id -u)
GROUP_ID=$(id -g)

echo "Mount $LOCAL_DIR into docker, and match the host IDs ($USER_ID:$GROUP_ID) inside the container."

docker run -v $LOCAL_DIR:/host_mount -i debian:9.4-slim bash -c "set -euo pipefail && groupadd -r -g $GROUP_ID lowprivgroup && useradd -u $USER_ID lowprivuser -g $GROUP_ID && cd /host_mount && su -c ./runMyScriptAsRegularUser.sh lowprivuser"

3

ベース画像

この画像を使用:https : //hub.docker.com/r/reduardo7/docker-host-user

または

重要:これにより、ホスト間でのコンテナの移植性が失われます

1) init.sh

#!/bin/bash

if ! getent passwd $DOCKDEV_USER_NAME > /dev/null
  then
    echo "Creating user $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME"
    groupadd --gid $DOCKDEV_GROUP_ID -r $DOCKDEV_GROUP_NAME
    useradd --system --uid=$DOCKDEV_USER_ID --gid=$DOCKDEV_GROUP_ID \
        --home-dir /home --password $DOCKDEV_USER_NAME $DOCKDEV_USER_NAME
    usermod -a -G sudo $DOCKDEV_USER_NAME
    chown -R $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME /home
  fi

sudo -u $DOCKDEV_USER_NAME bash

2) Dockerfile

FROM ubuntu:latest
# Volumes
    VOLUME ["/home/data"]
# Copy Files
    COPY /home/data/init.sh /home
# Init
    RUN chmod a+x /home/init.sh

3)run.sh

#!/bin/bash

DOCKDEV_VARIABLES=(\
  DOCKDEV_USER_NAME=$USERNAME\
  DOCKDEV_USER_ID=$UID\
  DOCKDEV_GROUP_NAME=$(id -g -n $USERNAME)\
  DOCKDEV_GROUP_ID=$(id -g $USERNAME)\
)

cmd="docker run"

if [ ! -z "${DOCKDEV_VARIABLES}" ]; then
  for v in ${DOCKDEV_VARIABLES[@]}; do
    cmd="${cmd} -e ${v}"
  done
fi

# /home/usr/data contains init.sh
$cmd -v /home/usr/data:/home/data -i -t my-image /home/init.sh

4)ビルド docker

4)走れ!

sh run.sh

0

私の特定のケースでは、デプロイメントサーバーにnpmをインストールする必要がないように、ノードDockerイメージを使用してノードパッケージをビルドしようとしていました。コンテナーの外とホストマシンで、ノードDockerイメージが作成したnode_modulesディレクトリーにファイルを移動しようとするまで、それはうまくいきました。これは、rootが所有していたためにアクセス許可が拒否されました。この問題を回避するには、ディレクトリをコンテナからホストマシンにコピーします。ドッカーのドキュメントを介して...

ローカルマシンにコピーされたファイルは、docker cpコマンドを呼び出したユーザーのUID:GIDで作成されます。

これは、Dockerコンテナによって作成されたディレクトリの所有権を変更するために使用したbashコードです。

NODE_IMAGE=node_builder
docker run -v $(pwd)/build:/build -w="/build" --name $NODE_IMAGE node:6-slim npm i --production
# node_modules is owned by root, so we need to copy it out 
docker cp $NODE_IMAGE:/build/node_modules build/lambda 
# you might have issues trying to remove the directory "node_modules" within the shared volume "build", because it is owned by root, so remove the image and its volumes
docker rm -vf $NODE_IMAGE || true

必要に応じて、2番目のDockerコンテナを使用してディレクトリを削除できます。

docker run -v $(pwd)/build:/build -w="/build" --name $RMR_IMAGE node:6-slim rm -r node_modules

0

DockerホストとDockerコンテナ間でフォルダを共有するには、以下のコマンドを試してください

$ docker run -v "$(pwd):$(pwd)" -i -t ubuntu

-vフラグは、現在の作業ディレクトリをコンテナにマウントします。バインドマウントされたボリュームのホストディレクトリが存在しない場合、Dockerはホスト上にこのディレクトリを自動的に作成します。

ただし、ここには2つの問題があります。

  1. 共有ファイルはホストの他のユーザーが所有するため、非rootユーザーの場合、マウントされたボリュームに書き込むことはできません。
  2. コンテナー内でrootとしてプロセスを実行するべきではありませんが、ハードコードされたユーザーとして実行しても、ラップトップ/ジェンキンスのユーザーとは一致しません。

解決:

コンテナ:「testuser」というユーザーを作成します。デフォルトでは、ユーザーIDは1000から始まります。

ホスト:グループID 1000で「testgroup」と言うグループを作成し、ディレクトリを新しいグループ(testgroup


-5

Docker Composeを使用している場合は、コンテナーを特権モードで開始します。

wordpress:
    image: wordpress:4.5.3
    restart: always
    ports:
      - 8084:80
    privileged: true

2
これにより、ボリュームのマウントが容易になる可能性がありますが、Wordpressが特権モードで起動しましたか?それは恐ろしい考えです-それは妥協することを求めています。 wpvulndb.com/wordpresses/453
コリンハリントン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.