Linuxサーバーの管理でよくある判断ミスが「特権が必要だからrootで動かす」という発想です。ネットワークソケットを開きたい、rawパケットを扱いたい、ファイルのタイムスタンプを変更したい——こうした操作のたびにrootを与えていると、万が一プロセスが侵害された場合、攻撃者はサーバー全体の制御を握ることになります。
この問題を解決するのが、Linuxの**capabilities(ケーパビリティ)**という仕組みです。rootの権限を細かく分割し、「必要な権限だけをプロセスやバイナリに与える」ことで、最小権限の原則をLinuxカーネルレベルで実現できます。
この記事では、capabilitiesの概念からgetcap/setcap/capshの実践的な使い方、Docker・systemdへの応用まで、現場で使えるレベルで解説します。
Linuxのcapabilitiesとは?rootを細分化した「特権の最小単位」
従来のUnixシステムでは、プロセスの権限は「root(UID=0)」か「一般ユーザー」かの二択でした。ネットワークポートのバインドや特殊ファイルへのアクセスなど、特権が必要な操作はすべてroot権限を要求していたのです。
Linuxのcapabilities(カーネル2.2以降)は、このroot権限を40以上の独立した権限単位に分解します。それぞれを個別に付与・剥奪できるため、「ポート80をバインドする権限だけ持つが、ファイル所有者を変更する権限は持たない」という細やかな制御が可能になります。
| 従来の仕組み | capabilitiesを使った仕組み |
|---|---|
| root = すべての権限 | 必要な権限だけを個別付与 |
| 特権が必要 = root で動かす | 特定のcapabilityだけ付与して動かす |
| 侵害時は全権限が奪われる | 侵害されても被害範囲が限定される |
主要なcapabilitiesの種類と意味
capabilitiesは現在(Linux 6.x系)で41種類定義されています。セキュリティ観点で特に重要なものを押さえておきましょう。
サービス運用でよく使うcapabilities
・CAP_NET_BIND_SERVICE: 1024番未満のポート(80/443など)にバインドする権限。Webサーバーをroot以外で動かす際に使います
・CAP_NET_RAW: rawソケットの使用権限。pingコマンドやパケットキャプチャツールが使用しています
・CAP_NET_ADMIN: ネットワークインターフェース設定、ルーティングテーブル変更など。VPNクライアントがよく必要とします
・CAP_SYS_TIME: システムクロックの変更権限
・CAP_DAC_READ_SEARCH: ファイルのDAC(任意アクセス制御)読み取りを無視する権限
攻撃者が狙う危険なcapabilities
・CAP_SYS_ADMIN: 非常に広い権限を持つ。マウント操作・名前空間の変更など。「第2のroot」と呼ばれるほど危険
・CAP_SYS_PTRACE: 他プロセスへのptrace(デバッグ・追跡)権限。プロセスインジェクションに悪用可能
・CAP_DAC_OVERRIDE: すべてのファイルのDAC(パーミッション)を無視する権限
・CAP_SETUID / CAP_SETGID: 任意のUID/GIDへの変更権限。UID 0への昇格が可能になるケースがあります
・CAP_SYS_MODULE: カーネルモジュールのロード/アンロード権限。悪意あるモジュールの挿入が可能
capabilitiesの確認・設定コマンド実践ガイド
1. getcap でバイナリのcapabilitiesを確認する
システム上のバイナリに設定されたcapabilitiesはgetcapコマンドで確認できます。
# 特定のバイナリを確認する getcap /usr/bin/ping # システム全体をスキャン(rootまたはsudo不要) getcap -r / 2>/dev/null # 出力例 # /usr/bin/ping cap_net_raw=ep # /usr/sbin/tcpdump cap_net_admin,cap_net_raw=eip
出力形式の読み方を覚えておきましょう。`cap_net_raw=ep` の `=` 以降の文字が有効なセットを示します。
・e(Effective): 現在有効なcapability
・p(Permitted): 使用を許可されたcapability
・i(Inheritable): 子プロセスに継承可能なcapability
2. setcap でバイナリにcapabilitiesを設定・削除する
setcapコマンドで特定のバイナリにcapabilitiesを付与します。root権限が必要です。
# Node.jsアプリをrootなしでポート80にバインドできるようにする sudo setcap 'cap_net_bind_service=+ep' /usr/bin/node # Pythonスクリプトにrawソケット権限を与える(直接実行バイナリに設定) sudo setcap 'cap_net_raw=+ep' /usr/bin/python3.11 # capabilitiesを削除する(セキュリティ上不要になった場合) sudo setcap -r /usr/bin/ping # 設定を確認する getcap /usr/bin/node # /usr/bin/node cap_net_bind_service=ep
重要な注意点: setcapはシンボリックリンクには効きません。実際のバイナリ(実体ファイル)のパスに対して設定する必要があります。また、Pythonインタープリタへのcapability設定は、そのインタープリタで実行されるすべてのスクリプトに影響します。cap_net_rawをPython本体に設定するより、Cで書いた専用バイナリに限定する方がより安全です。
3. capsh でプロセスのcapabilitiesを確認・操作する
capshは現在のプロセスが持つcapabilitiesの確認と、特定のcapabilitiesでシェルを起動するテストに使います。
# 現在のプロセスのcapabilitiesを確認する capsh --print # 出力例(一般ユーザーの場合) # Current: = # Bounding set =cap_chown,cap_dac_override,...(全40+能力が列挙される) # Ambient set = # 特定のcapabilityのみを持つシェルを起動してテストする sudo capsh --caps='cap_net_bind_service+eip cap_setuid+eip' --user=www-data -- -i # /proc から直接確認する方法(スクリプトで使いやすい) cat /proc/$$/status | grep -i cap # CapInh: 0000000000000000 # CapPrm: 0000000000000000 # CapEff: 0000000000000000 # CapBnd: 000001ffffffffff # CapAmb: 0000000000000000
`/proc/$$/status` の16進数はcapsh --decode=で人間が読める形に変換できます。
# 16進数をcapability名に変換する capsh --decode=000001ffffffffff
攻撃者がcapabilitiesを悪用する手口
capabilitiesはセキュリティ強化の仕組みですが、設定ミスがあると攻撃者の侵入経路になります。特権昇格(Privilege Escalation)の調査フェーズで攻撃者がまず確認するのが、広すぎるcapabilitiesを持ったバイナリです。
よくある悪用パターン
・cap_net_rawの悪用: pingやtcpdumpに設定されている場合、通信の盗聴(スニッフィング)が可能。アクセス可能なユーザーを絞ることが重要
・cap_sys_adminの不用意な付与: コンテナ環境で`–privileged`フラグを使うと実質的にCAP_SYS_ADMINが付与され、コンテナエスケープのリスクが生じます
・インタープリタへの直接設定: python/perl/rubyなどのインタープリタに危険なcapabilityを設定すると、そのインタープリタで動くすべてのコードが権限を持ちます
ペネトレーションテストのフレームワークでも、capabilitiesの過剰設定は「低難度の特権昇格経路」として分類されています。定期的な棚卸しが必須です。
DockerとsystemdでのCapabilities活用法
1. Dockerコンテナのcapabilities制御
Dockerはデフォルトで一部のcapabilitiesを付与して起動しますが、不要なものは--cap-dropで削除し、必要なものだけを--cap-addで追加するのがベストプラクティスです。
# 全capabilitiesを削除した上で必要なものだけ追加する(最も安全) docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE \ -p 80:80 my-webserver:latest # docker-compose.yml での記述例 # services: # web: # image: my-webserver:latest # cap_drop: # - ALL # cap_add: # - NET_BIND_SERVICE
2. systemdサービスのcapabilities制限
systemdのサービスユニットファイルでもcapabilitiesを細かく制御できます。`CapabilityBoundingSet`でそのサービスが取得できる上限を設定し、`AmbientCapabilities`で実際に有効化します。
# /etc/systemd/system/my-webserver.service の例 [Service] User=www-data Group=www-data # ポート80/443にバインドするためだけのcapabilityを付与 # 他の全特権はBoundingSetから除外される CapabilityBoundingSet=CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_BIND_SERVICE # 追加のセキュリティ強化オプション NoNewPrivileges=yes PrivateTmp=yes ProtectSystem=strict
この設定により、www-dataユーザーとして動作するWebサーバーがポート80/443にバインドできる一方で、それ以外の特権操作は一切できない状態になります。仮にWebサーバープロセスが侵害されても、攻撃者が取得できる権限はCAP_NET_BIND_SERVICEのみです。
中小企業でも今日からできること
capabilitiesの完全な管理体制を一気に構築するのは難しくても、次の3ステップは今日から着手できます。
・ステップ1 — 現状把握: まず`getcap -r / 2>/dev/null`で全バイナリのcapabilitiesを棚卸しします。意図しない設定がないか確認しましょう
・ステップ2 — 不要なSUIDビットとの組み合わせ確認: `find / -perm -4000 2>/dev/null`でSUIDビット付きバイナリも同時に確認します。capabilitiesとSUIDは両方とも特権昇格の経路になりえます
・ステップ3 — 新規サービスはcapabilities設計を先行させる: 新しくサービスを立ち上げる際、「root権限が必要か」より先に「どのcapabilityが必要か」を考える習慣をつけましょう。CAP_NET_BIND_SERVICEが必要なだけなら、rootでsystemdサービスを動かす必要はありません
| 作業 | コマンド | 目的 |
|---|---|---|
| capabilities棚卸し | getcap -r / 2>/dev/null | 不要な設定の発見 |
| SUIDバイナリ確認 | find / -perm -4000 2>/dev/null | 特権昇格経路の把握 |
| 不要capabilityの削除 | setcap -r /path/to/binary | 攻撃面の最小化 |
| systemdサービス制限 | CapabilityBoundingSet=… | サービス単位の最小権限化 |
よくある誤解と注意点
・「rootで動かしても、capabilityを剥奪すれば安全」は誤り: rootプロセスはデフォルトで全capabilitiesを持ちます。capabilitiesを個別に剥奪する仕組み(例: `CapabilityBoundingSet=`)を明示的に使わない限り、rootで動かすことは依然としてリスクです
・CAP_SYS_ADMINは事実上のroot: このcapabilityは対象が非常に広く「実質的なroot権限」です。Docker等で安易に付与しないようにしましょう
・capabilitiesとSELinux/AppArmorは競合しない: capabilitiesはDAC(任意アクセス制御)レイヤー、SELinuxやAppArmorはMAC(強制アクセス制御)レイヤーです。両方を組み合わせることで多層防御になります
・シンボリックリンクへのsetcapは無効: 実体のバイナリパスに設定しないと効きません。`which python3`が返すパスがシンボリックリンクの場合は`readlink -f $(which python3)`で実体パスを確認しましょう
・ファイルシステムがcapabilitiesをサポートしているか確認: NFS等の一部ファイルシステムではxattrsが無効でcapabilitiesが保存できないケースがあります
Linuxの権限管理全般については、姉妹サイトLinuxMaster.JPでchmod・chown・sudoの基礎から詳しく解説しています。
本記事のまとめ
・Linuxのcapabilitiesはroot権限を40以上の細かい権限単位に分解した仕組みで、最小権限の原則をカーネルレベルで実現します
・getcapでバイナリの現在設定を確認、setcapで付与・削除、capshでプロセスの権限状態を検査します
・CAP_SYS_ADMINは実質的なroot権限を持つため、付与を避けるかDockerの`–privileged`フラグの使用を厳格に管理します
・systemdの`CapabilityBoundingSet`と`AmbientCapabilities`を組み合わせると、一般ユーザープロセスに必要最小限のcapabilityだけを安全に与えられます
・まずは`getcap -r / 2>/dev/null`でシステム全体を棚卸しし、意図しない設定がないかを確認することから始めましょう
| capability | 主な用途 | リスクレベル |
|---|---|---|
| CAP_NET_BIND_SERVICE | 1024番未満ポートへのバインド | 低(限定的) |
| CAP_NET_RAW | rawソケット・パケットキャプチャ | 中(通信盗聴可能) |
| CAP_DAC_OVERRIDE | パーミッション無視でファイルアクセス | 高(全ファイル読み書き可能) |
| CAP_SYS_ADMIN | マウント・名前空間変更など広範囲 | 最高(実質root) |
| CAP_SYS_MODULE | カーネルモジュールのロード | 最高(カーネル操作可能) |
Linuxのcapabilities、正しく設定できていますか?
「rootで動かしているから大丈夫」という思い込みが、攻撃者に特権昇格の足がかりを与えているかもしれません。
正しいセキュリティ知識を体系的に身につけたい方へ、メルマガで実践的なセキュリティ対策ノウハウをお届けしています。
