はじめに
「CAP_NET_RAW」というケーパビリティがありますが、セキュリティを考慮してコンテナ起動時に削除することができます。
このケーパビリティは「RAWソケットとPACKETソケットの使用を許可」を司っていいて、任意のパケットの送受信を行うために必要な権限となっています。
本記事ではCAP_NET_RAWが必要なpingコマンドを例に実際にコンテナを起動して挙動を確認しました。
環境情報
- Docker Version:19.03.5
Pingコマンドが打てない
Ubuntiイメージを起動してapt-get install iputils-ping
を行えばpingコマンドを押下でき
# docker run -it ubuntu
実際に利用できます。
# ping yahoo.co.jp PING yahoo.co.jp (182.22.59.229) 56(84) bytes of data. 64 bytes from 182.22.59.229 (182.22.59.229): icmp_seq=1 ttl=37 time=61.8 ms 64 bytes from 182.22.59.229 (182.22.59.229): icmp_seq=2 ttl=37 time=77.2 ms ...
ところが以下のようにコンテナを起動すると
$ docker run -it --cap-drop net_raw ubuntu
パーミッションエラーでpingが打てません。
# ping bash: /usr/bin/ping: Operation not permitted
もちろんファイルとしての権限は付与されています。
# ls -l /usr/bin/ping -rwxr-xr-x 1 root root 72776 ... /usr/bin/ping
straceで詳細を確認する
結論としては冒頭で述べた「CAP_NET_RAW」がpingコマンドに必要だからです。
# getcap /bin/ping /bin/ping = cap_net_raw+ep
よって例えばarping
のようなping相当のツールを落としてきても以下のように利用できません。
# arping yahoo.co.jp arping: libnet_init(LIBNET_LINK, <null>): libnet_open_link(): UID/EUID 0 or capability CAP_NET_RAW required
straceコマンドで中身を確認すると分かりますが
# strace arping yahoo.co.jp execve("/usr/sbin/arping", ["arping", "yahoo.co.jp"], 0x7ffc73334738 /* 8 vars */) = 0 ... socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) = -1 EPERM (Operation not permitted) close(-1) = -1 EBADF (Bad file descriptor) write(2, "arping: libnet_init(LIBNET_LINK,"..., 108arping: libnet_init(LIBNET_LINK, <null>): libnet_open_link(): UID/EUID 0 or capability CAP_NET _RAW required ) = 108 getuid() = 0 exit_group(1) = ? +++ exited with 1 +++
生パケットを打とうとしていることが分かります。
socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
終わりに
CAP_NET_RAWを持つプロセスは任意の内容のパケットを送信できるので、明確な必要がない場合は権限を削除してコンテナを起動することがベストプラクティスとなっています。コンテナであれば挙動が簡単に確認できるので、本記事を参考に手元でも試してみる事おススメします。
以上、ご参考になれば幸いです。