Docker コマンドで capabilities を追加または削除する方法

DockerBeginner
オンラインで実践に進む

はじめに

Docker はアプリケーションをコンテナ化するための強力なツールであり、コンテナの capabilities (機能) を管理する方法を理解することは、セキュリティとパフォーマンスを最適化する上で非常に重要です。このチュートリアルでは、Docker コマンドを使用して capabilities を追加および削除するプロセスを説明し、特定のニーズに合わせてコンテナ環境を調整できるようにします。

この実験 (Lab) では、Docker capabilities が何か、それらがどのようにコンテナのセキュリティを強化するか、そしてそれらを効果的に管理する方法を学びます。このチュートリアルを終える頃には、Docker コンテナから capabilities を自信を持って追加および削除できるようになるでしょう。

Docker Capabilities の理解

Docker capabilities (機能) は、コンテナに特定の Linux カーネルの権限を付与または取り消すことができるセキュリティ機能です。capabilities を実験する前に、それらが何であり、なぜ重要なのかを理解しましょう。

Docker Capabilities とは?

Docker の capabilities は、Linux カーネルの capability システムに基づいています。このシステムは、従来 root ユーザーに関連付けられていた特権を、個別のユニットに分割します。このアプローチは、従来の全か無かの root 特権モデルよりも安全です。

デフォルトでは、Docker コンテナは限られた一連の capabilities で実行され、機能性とセキュリティのバランスが適切に保たれています。ただし、アプリケーションの要件に基づいて capabilities を追加または削除する必要がある場合があります。

Docker コンテナのデフォルトの capabilities を調べてみましょう。以下のコマンドを実行してコンテナを起動し、その capabilities を表示します。

docker run --rm -it ubuntu:22.04 capsh --print

次のような出力が表示されるはずです。

Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Ambient set =
Current IAB: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
 secure-no-ambient-raise: no (unlocked)
uid=0(root) gid=0(root) groups=0(root)

この出力は、デフォルトでコンテナに付与されている capabilities を示しています。これらの capabilities は、コンテナがシステム内で何を実行できるかを制御します。

なぜ Capabilities が重要なのか

Docker capabilities を適切に管理することは、以下にとって重要です。

  1. セキュリティの強化: capabilities を制限することにより、コンテナが侵害された場合の潜在的な損害を軽減できます。
  2. きめ細かい制御: 完全な root アクセスを付与することなく、特定の特権操作を許可できます。
  3. 最小権限の原則: コンテナは、適切に機能するために必要な capabilities のみを持つべきです。

次に、Docker コンテナに capabilities を追加する方法を説明します。

Docker コンテナへの capabilities の追加

このステップでは、--cap-add フラグを使用して、Docker コンテナに特定の capabilities を追加する方法を学びます。これは、アプリケーションがデフォルトセットに含まれていない特定の特権を必要とする場合に役立ちます。

Capabilities を追加するための基本的な構文

Docker コンテナに capability を追加するための基本的な構文は次のとおりです。

docker run --cap-add=<CAPABILITY> <IMAGE> <COMMAND>

コンテナがさまざまなネットワーク関連の操作を実行できるようにする NET_ADMIN capability を追加してみましょう。

docker run --rm -it --cap-add=NET_ADMIN ubuntu:22.04 capsh --print

出力には、NET_ADMIN capability がコンテナに追加されたことが示されます。

Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap,cap_net_admin=ep

capabilities リストの最後に cap_net_admin が追加されていることに注意してください。

複数の Capabilities の追加

多くの場合、コンテナに複数の capabilities を追加する必要がある場合があります。これは、--cap-add フラグを複数回指定することで実行できます。

docker run --rm -it --cap-add=NET_ADMIN --cap-add=SYS_TIME ubuntu:22.04 capsh --print

このコマンドは、NET_ADMINSYS_TIME の両方の capabilities をコンテナに追加します。SYS_TIME capability は、コンテナがシステムクロックを変更できるようにします。

実用的な例:ネットワークインターフェースの変更

capabilities の実用的な使用例を示すために、NET_ADMIN capability を持つコンテナを作成し、ネットワークインターフェース設定の変更を試みます。

docker run --rm -it --cap-add=NET_ADMIN ubuntu:22.04 /bin/bash

これで、bash シェルを持つコンテナ内に入りました。ネットワークインターフェースを操作するために、iproute2 パッケージをインストールしましょう。

apt-get update && apt-get install -y iproute2

次に、ダミーのネットワークインターフェースを作成してみましょう。

ip link add dummy0 type dummy
ip link show dummy0

新しく作成されたダミーのネットワークインターフェースを示す出力が表示されるはずです。

6: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 2a:d5:cd:70:91:f4 brd ff:ff:ff:ff:ff:ff

この操作は、NET_ADMIN capability がないと失敗します。コンテナを終了するには、「exit」と入力します。

コンテナの Capabilities の表示

実行中のコンテナの capabilities を検査するには、docker inspect コマンドを使用できます。まず、追加された capabilities を持つコンテナをデタッチモードで起動しましょう。

docker run -d --name cap-test --cap-add=NET_ADMIN ubuntu:22.04 sleep 3600

次に、コンテナを検査してその capabilities を表示します。

docker inspect cap-test | grep -A 20 CapAdd

出力には、NET_ADMIN capability が追加されたことが示されます。

            "CapAdd": [
                "NET_ADMIN"
            ],

このステップの後でクリーンアップすることを忘れないでください。

docker stop cap-test
docker rm cap-test

Docker コンテナに capabilities を追加する方法を理解することで、セキュリティを維持しながら、コンテナが何を実行できるかについてより多くの制御を得ることができます。

Docker コンテナからの Capabilities の削除

このステップでは、--cap-drop フラグを使用して、Docker コンテナから capabilities を削除する方法を学びます。これは、最小権限の原則に従う重要なセキュリティプラクティスです。コンテナは、絶対に必要とする capabilities のみを持つべきです。

Capabilities を削除するための基本的な構文

Docker コンテナから capability を削除するための基本的な構文は次のとおりです。

docker run --cap-drop=<CAPABILITY> <IMAGE> <COMMAND>

ファイルの所有権の変更を許可する CHOWN capability を削除してみましょう。

docker run --rm -it --cap-drop=CHOWN ubuntu:22.04 capsh --print

出力では、cap_chown が capabilities の中に表示されなくなったことに気付くでしょう。

Current: cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep

複数の Capabilities の削除

--cap-drop フラグを複数回指定することで、複数の capabilities を削除できます。

docker run --rm -it --cap-drop=CHOWN --cap-drop=NET_RAW ubuntu:22.04 capsh --print

このコマンドは、コンテナから CHOWNNET_RAW の両方の capabilities を削除します。

実用的な例:Capability の制限のテスト

CHOWN capability を削除したコンテナを作成し、ファイルの所有権の変更を試みましょう。

docker run --rm -it --cap-drop=CHOWN ubuntu:22.04 /bin/bash

コンテナ内で、テストファイルを作成し、その所有権を変更してみましょう。

touch test_file
ls -l test_file
chown nobody:nogroup test_file

操作が許可されていないことを示すエラーメッセージが表示されるはずです。

chown: changing ownership of 'test_file': Operation not permitted

これは、CHOWN capability を削除すると、コンテナが root として実行されていても、コンテナがファイルの所有権を変更できなくなることを示しています。「exit」と入力してコンテナを終了します。

--cap-add と --cap-drop の両方の使用

--cap-add フラグと --cap-drop フラグの両方を同じコマンドで使用して、コンテナの capabilities を正確に制御できます。

docker run --rm -it --cap-add=NET_ADMIN --cap-drop=CHOWN ubuntu:22.04 capsh --print

このコマンドは、NET_ADMIN capability を追加し、CHOWN capability を削除します。

すべての Capabilities を削除し、特定のものを追加する

最大限のセキュリティのために、すべての capabilities を削除し、アプリケーションが必要とする特定の capabilities のみを追加できます。

docker run --rm -it --cap-drop=ALL --cap-add=NET_BIND_SERVICE ubuntu:22.04 capsh --print

このコマンドは、特権ポート(1024 未満)へのバインディングを許可する NET_BIND_SERVICE capability のみを持つコンテナを作成します。

すべての Capabilities が削除されたコンテナのテスト

すべての capabilities が削除されたコンテナを作成し、制限を観察してみましょう。

docker run -d --name no-caps --cap-drop=ALL ubuntu:22.04 sleep 3600

次に、コンテナにアタッチして、さまざまな操作を実行してみましょう。

docker exec -it no-caps /bin/bash

コンテナ内で、外部ホストに ping を試みます。

apt-get update && apt-get install -y iputils-ping
ping -c 1 google.com

ping に必要な raw ネットワークソケットを作成するための必要な capabilities がコンテナにないため、エラーが表示される可能性があります。

「exit」と入力してコンテナを終了し、クリーンアップします。

docker stop no-caps
docker rm no-caps

Docker コンテナから capabilities を削除する方法を理解することで、各コンテナが実行できることを厳密に制限することにより、コンテナ化されたアプリケーションのセキュリティを大幅に強化できます。

Capabilities 管理とセキュリティベストプラクティスの組み合わせ

この最終ステップでは、Docker の capabilities 管理を他のセキュリティベストプラクティスと組み合わせて、安全で最小限の権限を持つコンテナを作成する方法を探ります。

カスタム capabilities プロファイルを持つコンテナの作成

capabilities 管理を他のセキュリティ機能と組み合わせた、より複雑な例を作成しましょう。

docker run -d --name secure-container \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --read-only \
  --tmpfs /tmp \
  ubuntu:22.04 sleep 3600

このコマンドは以下を行います。

  • すべての capabilities を削除します
  • NET_BIND_SERVICE capability のみを追加します
  • コンテナのファイルシステムを読み取り専用にします
  • 書き込み操作のために /tmp に一時ファイルシステムを作成します

このコンテナを検査して、その設定を確認しましょう。

docker inspect secure-container | grep -A 5 CapAdd
docker inspect secure-container | grep -A 5 CapDrop
docker inspect secure-container | grep ReadonlyRootfs

これらのセキュリティ設定を確認する出力が表示されるはずです。

            "CapAdd": [
                "NET_BIND_SERVICE"
            ],
            "CapDrop": [
                "ALL"
            ],
"ReadonlyRootfs": true,

制限のテスト

安全なコンテナに接続して、制限をテストしましょう。

docker exec -it secure-container /bin/bash

コンテナ内で、システムファイルを変更してみましょう。

echo "test" > /etc/test

ファイルシステムが読み取り専用であるため、エラーが表示されるはずです。

bash: /etc/test: Read-only file system

次に、/tmp ディレクトリに書き込もうとします。

echo "test" > /tmp/test
cat /tmp/test

/tmp に書き込み可能な tmpfs をマウントしたため、これは機能するはずです。

test

「exit」と入力してコンテナを終了します。

非 root ユーザーでの Capabilities の使用

セキュリティをさらに高めるために、capabilities を管理しながら、非 root ユーザーとしてコンテナを実行できます。まず、非 root ユーザーと特定の capabilities を組み合わせた新しいコンテナを作成しましょう。

docker run -d --name nonroot-container \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --user 1000:1000 \
  ubuntu:22.04 sleep 3600

NET_BIND_SERVICE capability を追加し、非 root ユーザーとして実行しているにもかかわらず、Linux capabilities はデフォルトでは root として実行されているプロセスにのみ適用されることに注意してください。非 root ユーザーが capabilities を使用できるようにするには、setuid バイナリや ambient capabilities などの追加の設定が必要になります。

docker-compose での Capabilities

複数のコンテナを管理するために docker-compose を使用する場合は、docker-compose.yml ファイルで capabilities を指定できます。

version: "3"
services:
  webapp:
    image: ubuntu:22.04
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    read_only: true
    tmpfs:
      - /tmp

これにより、コンテナのデプロイメント全体で capabilities を管理するための一貫した方法が提供されます。

クリーンアップ

作成したコンテナをクリーンアップしましょう。

docker stop secure-container nonroot-container
docker rm secure-container nonroot-container

ベストプラクティスの概要

Docker capabilities を管理するためのベストプラクティスを以下に示します。

  1. すべての capabilities を削除し、必要なものだけを追加する
  2. capabilities 管理を他のセキュリティ機能と組み合わせる
    • 読み取り専用ファイルシステム
    • 非 root ユーザー
    • Seccomp プロファイル
    • AppArmor または SELinux
  3. コンテナの capabilities を定期的に監査する
  4. Docker とコンテナイメージを最新の状態に保つ
  5. コンテナの脆弱性スキャンツールを使用する

これらのプラクティスに従うことで、Docker コンテナのセキュリティを大幅に向上させることができます。

まとめ

この実験では、セキュリティと機能を強化するために、Docker コンテナの capabilities を効果的に管理する方法を学びました。以下に、達成した内容の要約を示します。

  1. Docker の capabilities が何であるか、そしてそれがコンテナセキュリティにとってなぜ重要であるかを理解しました。
  2. --cap-add フラグを使用してコンテナに capabilities を追加する方法を学び、コンテナが特定の特権操作を実行できるようにしました。
  3. --cap-drop フラグを使用して capabilities を削除し、最小権限の原則を実装する練習をしました。
  4. セキュアなコンテナ環境を作成するために、capabilities 管理を他のセキュリティ機能と組み合わせるためのベストプラクティスを探求しました。

これらのテクニックを適用することで、必要な権限を正確に持つコンテナを作成できます。これは、コンテナ化されたアプリケーションの潜在的な攻撃対象領域を大幅に削減し、正しく動作するために必要な機能を確実に提供します。

Docker のセキュリティ機能をさらに探求し、コンテナ化された環境で強力なセキュリティ体制を維持するために、コンテナの設定を定期的に監査および更新することを忘れないでください。