Docker の capability --cap-add　及び --cap-drop オプションについて調べた

メモ。
以下を読ませて頂きました

+ [–cap-dropオプションを使ったDockerコンテナの安全性を高める工夫](https://postd.cc/secure-your-containers-with-this-one-weird-trick/)

+ [Docker privileged オプションについて](https://qiita.com/muddydixon/items/d2982ab0846002bf3ea8)

capablity について詳しい訳ではないため、認識が異なった部分などあればご指摘頂けますと助かります。

# TL:DR

+  Linux には、root が持っている絶対的な権限を小分けにし、 細かくした権限をプロセスに与えられるようにする機構がある。その細かい権限のことを、ケーパビリティ(capablity)と呼ぶらしい [ケーパビリティ で権限を少しだけ与える](http://www.usupi.org/sysad/183.html)
+ Docker ではデフォルトでいくつかの capability は有効化されている。具体的有効化されているものは[公式ドキュメント](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities)に記載ありで `pscap` コマンドでも確認出来る
+ `--cap-drop` オプションを指定することでデフォルトで有効化されている capability を無効化出来る
+ 逆に `--cap-add` オプションを指定することでデフォルトで無効化されている capability を有効化出来る
+ `--privileged` オプションを付与した場合、明示的に有効化されていない capability も利用でき、すべての capability が有効化されている
+ `--user` オプションを指定した場合、capablity が無効化(?)されていた(Root 以外は基本的に capablity がないためだと思われます）


# 環境

```bash
docker info
Containers: 59
 Running: 5
 Paused: 0
 Stopped: 54
Images: 27
Server Version: 18.06.1-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 468a545b9edcd5932818eb9de8e72413e616e86e
runc version: 69663f0bd4b60df09991c08812a60108003fa340
init version: fec3683
Security Options:
 seccomp
  Profile: default
Kernel Version: 4.14.77-80.57.amzn2.x86_64
Operating System: Amazon Linux 2
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 985.7MiB
Name: ip-172-31-30-50.ap-northeast-1.compute.internal
ID: M5OF:USUI:CHU4:NPLX:6TPC:DJ52:6C6O:DEHT:2BUM:WDHN:DSCO:HFHD
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false
```

# 試す

## --cap-drop

[Runtime privilege and Linux capabilities](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities)

>The following table lists the Linux capability options which are allowed by default and can be dropped.

と書いてあり、`CHOWN`はデフォルトでは許可されている。

```bash
$docker run -it ubuntu chown root:staff tmp
```

デフォルトで許可されている capability を無効化する場合 `--cap-drop `を指定する。

```bash
$docker run -it --cap-drop CHOWN ubuntu chown root:staff tmp
chown: changing ownership of 'tmp': Operation not permitted
```

capability は `pscap` で見れそうなので確認
Ubuntu の場合、`apt-get install libcap-ng-utils` で良さそう

[libcap-ng-utils_0.7.7-3.1_amd64.deb](https://ubuntu.pkgs.org/18.04/ubuntu-universe-amd64/libcap-ng-utils_0.7.7-3.1_amd64.deb.html)


```bash
# デフォルト
$docker run -it ubuntu /bin/bash
#apt-get update
#apt-get install libcap-ng-utils
#pscap -a
ppid  pid   name        command           capabilities
0     1     root        bash              chown, dac_override, fowner, fsetid, kill, setgid, setuid, setpcap, net_bind_service, net_raw, sys_chroot, mknod, audit_write, setfcap

# drop してみる
$docker run -it --cap-drop CHOWN ubuntu /bin/bash
#apt-get update
#apt-get install libcap-ng-utils
#pscap -a
ppid  pid   name        command           capabilities
0     1     root        bash              dac_override, fowner, fsetid, kill, setgid, setuid, setpcap, net_bind_service, net_raw, sys_chroot, mknod, audit_write, setfcap

```

確かに drop すると capability から `CHOWN` が無くなっていた。


ちなみに `--privileged` を付与するとどうなる？

```bash
$docker run -it --privileged --cap-drop CHOWN ubuntu chown root:staff tmp
```

成功してしまう
こちらも `pscap` で確認(細かいコマンドは除外）

```bash
# privilledge を付与すると capability full となり、すべて許可される
$docker run -it --privileged ubuntu /bin/bash 
# pscap -a
ppid  pid   name        command           capabilities
0     1     root        bash              full

# cap-drop しても full
$docker run -it --privileged --cap-drop CHOWN ubuntu /bin/bash
#pscap -a
ppid  pid   name        command           capabilities
0     1     root        bash              full

```

なるほど。


ちなみに `--user` オプションを変えるとどうなる？

```bash
$docker run --user nobody -it ubuntu whoami
nobody

# ユーザーのみ指定。権限がないのでエラー
$docker run --user nobody -it ubuntu chown root:staff tmp
chown: changing ownership of 'tmp': Operation not permitted

# priviledge をつけてもエラー
$docker run --privileged --user nobody -it ubuntu chown root:staff tmp
chown: changing ownership of 'tmp': Operation not permitted
```

capability も確認してみようと思ったが、入ってなかったのでさくっとイメージを作る。
(最初からこうすればよかった。。。)

```Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y \
    libcap-ng-utils
```

```bash
$docker build -t pscap-ubuntu .
```

確認。

```bash
# 何も出ない
$docker run --user nobody -it pscap-ubuntu pscap -a

# 何も出ない 
$docker run --privileged  --user nobody -it pscap-ubuntu pscap -a

```

もしかすると root 以外は capablity  はない？

[ケーパビリティ で権限を少しだけ与える](http://www.usupi.org/sysad/183.html)

> root のプロセスは、基本的にはすべてのケーパビリティを持っていますが、 必要のないケーパビリティを外していくことで、 セキュリティを向上させることができます。
>また、root でないプロセスは、基本的にはどのケーパビリティも持っていません。 ですが、実行するコマンドにケーパビリティが設定されている場合は、 そのケーパビリティを持つことができます。 

なるほど。


## --cap-add

以下を参考にさせて頂き検証。

[(ヽ´ω`) < Dockerで--cap-addオプションを試す](http://tsugihagi.hatenablog.com/entry/2014/10/07/214213)

デフォルトで許可されていない `SYS_TIME` を利用。

```bash
$docker run -it ubuntu date -s "2000/01/01 00:00:00"
date: cannot set date: Operation not permitted
Sat Jan  1 00:00:00 UTC 2000
```

想定通り NG。
許可してみる

```bash
$docker run -it --cap-add=SYS_TIME ubuntu date -s "2000/01/01 00:00:00"
```

エラーが無くなった。

`--privileged` を付与した場合も実行できてしまう

```bash
$docker run -it --privileged ubuntu date -s "2000/01/01 00:00:00"
Sat Jan  1 00:00:00 UTC 2000
```

これは先程の検証の通り、`--priviledge`を付与することですべての capability が許可されるためだと思われる。