(ヽ´ω`) < 助けてほしいマン

わからないことを助けてほしいマンが書くブログ

(ヽ´ω`) < DockerのOperation not permittedとの戦争

(ヽ´ω`) < Operation not permitted…

Dockerをさわりだして1週間だけど、たまーに何かのタイミングでOperation not permittedが出る。

どうもDockerのセキュリティ機能として、デフォルトでは特定の操作を制限するようになっているらしい。

(ヽ´ω`) < 具体的にはどんなこと?

例えばdateとかntpdateでコンテナの時間を変更するとか、

[root@localhost ~]# docker run -i -t --rm centos:centos6 /bin/bash

bash-4.1# date -s "2000/01/01 00:00:00"
date: cannot set date: Operation not permitted
Sat Jan  1 00:00:00 GMT 2000
bash-4.1# date
Sat Oct  4 12:28:08 BST 2014
bash-4.1#

ルーティングテーブルを操作したりとか

[root@localhost ~]# docker run -i -t --rm centos:centos6 /bin/bash

bash-4.1# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.42.1     0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0
bash-4.1# route add -net 192.168.0.0/24 gw 172.17.254.254 eth0
SIOCADDRT: Operation not permitted
bash-4.1#

(ヽ´ω`) < 無慈悲なnot permitted

(ヽ´ω`) < これ、なんで?

普通の使い方をするなら、上記のような事はあまりしないかもしれないけど、検証とか実験となるとこの辺りの制限が煩わしい。

Security - Docker Documentation

公式のドキュメントを読んでいくと、Linux Capabilitiesに基づいて権限を一部制限しているらしい。

(ヽ´ω`) < Linux Capabilities ??

以下のmanと@ITの記事に詳しく書いてある。 時刻の操作や、ネットワーク関連の操作などの、システムに重要な変更権限を分割することで、セキュリティを向上させる機能。

Man page of CAPABILITIES

権限を最小化するLinuxカーネルケーパビリティ − @IT

(ヽ´ω`) < んで、Dockerのデフォルトは?

公式のドキュメントにはざっくりと

  • deny all "mount" operations;
  • deny access to raw sockets (to prevent packet spoofing);
  • deny access to some filesystem operations, like creating new device nodes, changing the owner of files, or altering attributes (including the immutable flag);
  • deny module loading;
  • and many others.

との記述があるが、Githubのソースにははっきりと書いてあって(2014/10/04時点)

docker/default_template.go at master · docker/docker · GitHub

       Capabilities: []string{
            "CHOWN",
            "DAC_OVERRIDE",
            "FSETID",
            "FOWNER",
            "MKNOD",
            "NET_RAW",
            "SETGID",
            "SETUID",
            "SETFCAP",
            "SETPCAP",
            "NET_BIND_SERVICE",
            "SYS_CHROOT",
            "KILL",
            "AUDIT_WRITE",
        },

となっている。

上記一覧にはSYS_TIMENET_ADMINが無いので、先の時刻変更やルーティングテーブル変更がOperation not permittedとなる。

(ヽ´ω`) < さて、どうする

man docker-runや上記の公式ドキュメントにも書いてあるが、docker run--privilegedフラグを渡してやることで、起動するコンテナに権限を与えることができる。

実際にやってみる。

## 時刻の設定
[root@localhost ~]# docker run -i -t --rm --privileged centos:centos6 /bin/bash

bash-4.1# date -s "2000/01/01 00:00:00"
Sat Jan  1 00:00:00 GMT 2000
bash-4.1# date
Sat Jan  1 00:00:01 GMT 2000
bash-4.1#
## ルーティングテーブルの変更
[root@localhost ~]# docker run -i -t --rm --privileged centos:centos6 /bin/bash

bash-4.1# route add -net 192.168.0.0/24 gw 172.17.254.254 eth0
bash-4.1# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.42.1     0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0
192.168.0.0     172.17.254.254  255.255.255.0   UG    0      0        0 eth0
bash-4.1#

(ヽ´ω`) < …あれ?

(ヽ´ω`) < 何か違和感

Linux Capabilitiesに基いて、と書いたが--privilegedオプションだと権限の分割ができていないんじゃ…

と思ったら、新しいバージョンでは--cap-add--cap-dropオプションで細かく指定ができるようになっているらしい。

In addition to --privileged, the operator can have fine grain control over the capabilities using --cap-add and --cap-drop. By default, Docker has a default list of capabilities that are kept. Both flags support the value all, so if the operator wants to have all capabilities but MKNOD they could use:

$ sudo docker run --cap-add=ALL --cap-drop=MKNOD ...

For interacting with the network stack, instead of using --privileged they should use --cap-add=NET_ADMIN to modify the network interfaces.

らしいというのは、またもやCentOS7の2014/10/04現在のリポジトリにおいてあるバージョンでは、未だ未対応っぽい。あとからUbuntuでも入れて確認してみるか…