Azure
docker
RHEL7

dockerで共有ディレクトリを利用したが、「Permission denied」が出てアクセスできない。

More than 1 year has passed since last update.

事象

dockerにてホストのディレクトリをコンテナと共有をしようと思ったが、「Permission denied」が出てアクセスできなかった。

使用した環境

サーバ:Microsoft Azure
OS:Red Hat Enterprise Linux 7.2
docker:version 1.10.3

事象が発生したコマンド

[user@host ~]$ mkdir testdir
[user@host ~]$ touch testdir/aaa.txt
[user@host ~]$ sudo docker run -i -t -v $HOME/testdir:/testdir ubuntu /bin/bash

#以下、コンテナ内のコマンド
root@a3eb3ad27df4:/# ls /testdir/
ls: cannot open directory '/testdir/': Permission denied

発生原因の仮説

No. 原因の仮説 結果
ホスト側ディレクトリのパーミッション設定が原因
dockerプロセスのユーザが原因
その他、何かのセキュリティ要素が原因 原因

仮説検証

仮説検証1:ホスト側ディレクトリのパーミッション

ホスト側ディレクトリのパーミッション設定の確認を行ってみる。

#ホスト側
[user@host ~]$ ls -l
total 0
drwxrwxr-x. 2 user user 20 Mar  6 08:03 testdir

次にコンテナ側ディレクトリのパーミッション設定の確認を行ってみる。

#ホスト側
[user@host ~]$ sudo docker run -i -t -v $HOME/testdir:/testdir ubuntu ls -l /
total 16
#略
drwxrwxr-x.   2 1000 1000   20 Mar  6 08:03 testdir
drwxrwxrwt.   2 root root    6 Jan 19 16:33 tmp
#略

ユーザとグループがおかしくなっていることが確認できました。
ホスト側のディレクトリとコンテナ側のユーザを同じ(root)にしてみたいと思います。

#ホスト側
[user@host ~]$ rm -df testdir
[user@host ~]$ ls -l
total 0
drwxr-xr-x. 2 root      root       6 Mar  7 04:29 testdir
[user@host ~]$ sudo docker run -i -t -v $HOME/testdir:/testdir ubuntu ls -l /
total 16
#略
drwxr-xr-x.   2 root root    6 Mar  7 04:29 testdir
drwxrwxrwt.   2 root root    6 Jan 19 16:33 tmp
#略

ホストとコンテナのディレクトリ所有ユーザが同じになりました。これでいけるはず!
再度コンテナでlsを実行します。

#ホスト側
[user@host ~]$ sudo docker run -i -t -v $HOME/testdir:/testdir ubuntu /bin/bash
#コンテナ側
root@826f647d35fb:/# ls -l testdir/
ls: cannot open directory 'testdir/': Permission denied

だめでした。パーミッションが原因ではないらしいです。

仮説検証2:dockerプロセスのユーザが原因

dockerサービスが何か得体のしれないユーザで動いているかもしれないので確認します。

[user@host ~]$ cat /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target
Wants=docker-storage-setup.service
Requires=rhel-push-plugin.socket

[Service]
Type=notify
NotifyAccess=all
EnvironmentFile=-/etc/sysconfig/docker
EnvironmentFile=-/etc/sysconfig/docker-storage
EnvironmentFile=-/etc/sysconfig/docker-network
Environment=GOTRACEBACK=crash
ExecStart=/usr/bin/docker-current daemon \
          --authorization-plugin=rhel-push-plugin \
          --exec-opt native.cgroupdriver=systemd \
          $OPTIONS \
          $DOCKER_STORAGE_OPTIONS \
          $DOCKER_NETWORK_OPTIONS \
          $ADD_REGISTRY \
          $BLOCK_REGISTRY \
          $INSECURE_REGISTRY
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
TimeoutStartSec=0
MountFlags=slave
Restart=on-abnormal

[Install]
WantedBy=multi-user.target

特にそれらしき設定も見つからず、dockerサービスの実行ユーザが原因ではないらしいです。

仮説検証3:何かのセキュリティ要因

パーミッション周りの設定だと思っていたのであっさり解決するかと思っていましたが、ダメでした。
職場のパイセンに相談してみたところ「SELinuxじゃね?」とのこと。そういや無効か設定した記憶がありません。

まずは一時的に無効化して試してみます。

#ホスト側
[user@host ~]$ getenforce
Enforcing
[user@host ~]$ sudo setenforce 0
[user@host ~]$ sudo docker run -i -t -v $HOME/testdir:/testdir ubuntu /bin/bash
#コンテナ側
root@fccb3b63af38:/# ls testdir/
root@fccb3b63af38:/# cd testdir/
root@fccb3b63af38:/testdir# echo 'testtext' > test.txt
root@fccb3b63af38:/testdir# exit
exit
#ホスト側
[user@host ~]$ cat testdir/test.txt
testtext

おおお!無事に見れました。SELinuxが原因だったようです。
さすがです。パイセン!

原因の掘り下げ

しかし、SELinuxを無効化しよう!が解決方法だと何か違う気もするのでさらに掘り下げます。
まずはラベルの確認をします。

#ホスト側
[user@host ~]$ sudo setenforce 1
[user@host ~]$ getenforce
Enforcing
[user@host ~]$ ls -Z
drwxr-xr-x. root      root      unconfined_u:object_r:user_home_t:s0 testdir
[user@host ~]$ sudo docker run -i -t -v $HOME/testdir:/testdir ubuntu /bin/bash
#コンテナ側
root@1a46f7be5d12:/# ls -Zl
total 16
drwxr-xr-x.   2 root root unconfined_u:object_r:user_home_t:s0                  21 Mar  7 05:01 testdir
drwxrwxrwt.   2 root root system_u:object_r:svirt_sandbox_file_t:s0:c120,c472    6 Jan 19 16:33 tmp
root@1a46f7be5d12:/# id
uid=0(root) gid=0(root) groups=0(root)

コンテナ側のディレクトリのラベルと共有したディレクトリのラベルに差がありますね。この辺のラベルを合わせれば上手く動くような気がします。
tmp:system_u:object_r:svirt_sandbox_file_t:s0:c120,c472
testdir:unconfined_u:object_r:user_home_t:s0
ラベルを自力で変更しようかとも思いましたが、dockerに既にいい感じにしてくれる機能が用意されていました。
オプション-vの最後に:Zをつけるといい感じにラベルを設定してくれます。

#ホスト側
[user@host ~]$ ls -Z
drwxr-xr-x. root      root      unconfined_u:object_r:user_home_t:s0 testdir
[user@host ~]$ sudo docker run -i -t -v $HOME/testdir:/testdir:Z ubuntu /bin/bash
#コンテナ側
root@dedc05f3a4c4:/# ls testdir/
test.txt
root@dedc05f3a4c4:/# cat testdir/test.txt
testtext
root@dedc05f3a4c4:/# exit
exit
#ホスト側
[user@host ~]$ ls -Z
drwxr-xr-x. root      root      system_u:object_r:svirt_sandbox_file_t:s0:c24,c110 testdir

testdirのラベルが変わっています。

ラベル
Before unconfined_u:object_r:user_home_t:s0
After system_u:object_r:svirt_sandbox_file_t:s0:c24,c110

:Zは匠です。

原因

SELinuxと適切にラベルが付与されていないのが原因

解決方法

-vオプションの最後に:zをつける。

[user@host ~]$ sudo docker run -i -t -v $HOME/testdir:/testdir:Z ubuntu /bin/bash