setcap・getcapコマンドでLinuxのケーパビリティを設定する方法|root不要で特権ポートとrawソケットを安全に実現する

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Linuxtips, セキュリティ > setcap・getcapコマンドでLinuxのケーパビリティを設定する方法|root不要で特権ポートとrawソケットを安全に実現する
「Webサーバーを80番ポートで起動しようとしたらroot権限が必要と言われた」
「pingコマンドをrootでなければ実行できなくなっている──なぜ?」

こうした疑問の答えが、Linuxのcapabilities(ケーパビリティ)という仕組みにあります。Linuxが「rootかそれ以外か」の二択から脱却するために Linux 2.2 で導入された機能で、root権限を約40種類の独立した特権(capability)に分割します。setcapコマンドで実行ファイルに必要なcapabilityだけを付与すれば、フルのroot権限を与えなくても特権操作を安全に委任できます。

この記事では、setcapgetcapコマンドの使い方から、systemdのAmbientCapabilitiesCapabilityBoundingSetによる本番サービスへの適用まで、実際のサーバーでの出力例とともに解説します。RHEL 9 / Rocky Linux 9 / Ubuntu 24.04 LTSで動作確認済みです。

この記事のポイント

・setcapでCAP_NET_BIND_SERVICEを付与すれば、root不要で80/443番ポートへのバインドができる
・getcapで現在のファイルケーパビリティを確認し、setcap -r でいつでも取り消せる
・systemdのAmbientCapabilitiesを使うとパッケージ更新後もケーパビリティ設定が維持される
・CAP_SYS_ADMINのような広大なcapabilityは最終手段──他のcapabilityで代替できないか先に検討する


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linuxのcapabilitiesとは何か(root権限を分割する仕組み)

昔のUnix系OSは「root(UID=0)かそれ以外か」の二択でした。root以外のプロセスが1024番未満のポートにバインドしようとすると「Permission denied」になり、rawソケットを使おうとしても同様でした。このため、一部の特権操作しか必要がなくても、サービスをrootとして起動するか、setuid rootのバイナリを使うしかありませんでした。

setuid rootには問題があります。ファイルにsetuidビットが立っていると、プロセスはフルのroot権限で動きます。脆弱性が発見された場合、攻撃者は一気にrootを手に入れられます。

これを解決するために Linux 2.2(1999年)でPOSIXケーパビリティが導入されました。現在のLinuxカーネルには約40種類のcapabilityが定義されており、ケーパビリティはプロセスごと・ファイルごとに設定できます。

プロセスのケーパビリティセット:Effective(実際に有効)・Permitted(保持できる上限)・Inheritable(exec後に子プロセスに引き継げる)の3種
ファイルのケーパビリティセット:Effectiveビット・Permittedセット・Inheritableセット。setcapコマンドで設定し、拡張属性(xattr)としてファイルシステムに保存される

「ファイルにケーパビリティが設定されている実行ファイルを非rootユーザーが実行すると、そのcapabilityだけが有効になる」──これがsetcapによる最小権限設計の核心です。

主要なcapabilityの種類と用途

Linuxのcapabilityは約40種類ありますが、現場でよく使う代表的なものを以下に整理します。

Capability名 できること 代表的な用途
CAP_NET_BIND_SERVICE 1024番未満のポートにバインド node.js / Python で80/443番を非rootで起動
CAP_NET_RAW rawソケット・パケットソケットの使用 ping・traceroute・arpingを非rootで実行
CAP_NET_ADMIN ネットワーク設定の変更(ルーティング・インターフェース操作等) tcコマンド・ip routeの変更
CAP_DAC_OVERRIDE ファイルパーミッションのDAC制限を無視 どのファイルでも読み書き可(危険。他のcapで代替を検討)
CAP_SETUID 任意のUIDへの切り替え sudo・su等の特権昇格ツール
CAP_SYS_ADMIN 非常に広範な操作(マウント・sysctl変更等) 最後の手段。他のcapabilityで代替を先に検討する
CAP_AUDIT_WRITE カーネル監査ログへの書き込み PAM認証ログ記録
CAP_CHOWN ファイルのUID/GIDを任意に変更 バックアップツール・デプロイスクリプト
設計原則:必要なcapabilityを絞り込み、CAP_SYS_ADMINは最終手段にします。「CAP_SYS_ADMINを付ければ動く」という解決策は、事実上フルroot権限に近い権限を与えることになり、最小権限の原則に反します。

getcapコマンドでファイルのケーパビリティを確認する

1. libcap をインストールする

getcapsetcapコマンドはlibcapパッケージに含まれています。まず以下でインストール済みか確認します。

# RHEL 9 / Rocky Linux 9 でインストール確認 [user@server01 ~]$ rpm -q libcap libcap-2.48-9.el9_2.x86_64 # 入っていない場合はインストールする [root@server01 ~]# dnf install -y libcap # Ubuntu 24.04 LTS でインストール確認 user@ubuntu:~$ dpkg -l libcap2-bin ii libcap2-bin 1:2.66-5ubuntu2 amd64 POSIX 1003.1e capabilities (utilities) # Ubuntu でインストールする場合 sudo apt install libcap2-bin

2. getcap コマンドでファイルのケーパビリティを確認する

getcap ファイルパスで、対象ファイルに設定されているケーパビリティを表示します。

# ping のケーパビリティを確認する(Rocky Linux 9) [user@server01 ~]$ getcap /usr/bin/ping /usr/bin/ping cap_net_admin,cap_net_raw=p # Python 3 にケーパビリティが設定されていない状態 [user@server01 ~]$ getcap /usr/bin/python3 (出力なし = ケーパビリティ未設定) # システム全体でケーパビリティが設定されているファイルを一括検索 [user@server01 ~]$ sudo getcap -r / 2>/dev/null /usr/bin/ping cap_net_admin,cap_net_raw=p /usr/bin/python3.12 cap_net_bind_service=ep

出力末尾の文字列(=p=ep=eip)はケーパビリティセットを表します。

=p(permitted):バイナリ実行時にそのcapabilityを保持できるが、コード側で明示的に有効化する必要がある
=ep(effective + permitted):実行開始時から即座に有効。ほとんどの実用ケースではこれを使う
=eip(effective + inheritable + permitted):さらに子プロセスへの引き継ぎも有効になる

setcapコマンドでケーパビリティを付与する実践手順

1. CAP_NET_BIND_SERVICE の付与(80番ポートを非rootで使う)

Pythonの組み込みHTTPサーバーをポート80で非rootユーザーとして起動する例です。setcapはroot権限で実行する必要があります。

# Python 3 インタープリターにCAP_NET_BIND_SERVICEを付与する [root@server01 ~]# setcap cap_net_bind_service=ep /usr/bin/python3.12 # 設定を確認する [root@server01 ~]# getcap /usr/bin/python3.12 /usr/bin/python3.12 cap_net_bind_service=ep # 一般ユーザーで80番ポートに起動できるか確認する [user@server01 ~]$ python3 -m http.server 80 Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ... # 別ターミナルでポートの確認 [user@server01 ~]$ ss -tlnp | grep ':80' LISTEN 0 5 0.0.0.0:80 0.0.0.0:* users:(("python3",pid=12345,fd=3))

ss -tlnpの出力でプロセスが一般ユーザー権限で80番ポートをListenしていることが確認できます。Linux ポート確認の全コマンドも参照してください。

2. CAP_NET_RAW の付与(ping を非rootで実行できるようにする)

セキュリティポリシーでpingのsetuidビットを落とした環境では、capabilityで代替できます。

# 現在のpingのケーパビリティを確認する [user@server01 ~]$ getcap /usr/bin/ping /usr/bin/ping cap_net_admin,cap_net_raw=p # ケーパビリティが外れていて非rootでは実行できない場合に付与する [root@server01 ~]# setcap cap_net_raw+ep /usr/bin/ping [root@server01 ~]# getcap /usr/bin/ping /usr/bin/ping cap_net_raw=ep # 一般ユーザーでpingが打てることを確認する [user@server01 ~]$ ping -c 3 192.168.1.1 PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data. 64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.412 ms 64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.398 ms 64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.411 ms --- 192.168.1.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2051ms

3. ケーパビリティを削除する方法

設定したケーパビリティを取り除くにはsetcap -rを使います。

# ケーパビリティを削除する(-r オプション) [root@server01 ~]# setcap -r /usr/bin/python3.12 # 削除後の確認(出力がなければ削除済み) [root@server01 ~]# getcap /usr/bin/python3.12 (出力なし)

systemdサービスのCapabilities設定(AmbientCapabilities・CapabilityBoundingSet)

ファイルへのsetcapは手軽ですが、パッケージアップデートでバイナリが更新されるたびに再設定が必要になります。systemdのunit fileでCapabilitiesを管理すれば、バイナリを更新しても設定が維持されます。

1. AmbientCapabilitiesとは

Linux 4.3 で追加されたAmbient Capabilitiesは、プロセスがexecした子プロセスに自動的にcapabilityを引き継がせる仕組みです。systemdのunit fileでAmbientCapabilities=に指定すると、そのサービスのプロセスと子プロセス全体にcapabilityが付与されます。ファイル側にsetcapが設定されていなくても機能します。

2. systemd unit fileにAmbientCapabilitiesを設定する

/usr/bin/python3でWebサーバーを80番ポートで起動するサービスの例です。

# /etc/systemd/system/mywebserver.service [Unit] Description=My Web Server on Port 80 After=network.target [Service] Type=simple User=webuser Group=webuser # 80番ポートバインドに必要なcapabilityだけを付与する AmbientCapabilities=CAP_NET_BIND_SERVICE # プロセスがexecで新たに特権を取得できないようにする NoNewPrivileges=true # AmbientCapabilitiesが有効になるよう上限セットも明示する CapabilityBoundingSet=CAP_NET_BIND_SERVICE ExecStart=/usr/bin/python3 -m http.server 80 [Install] WantedBy=multi-user.target

# unit fileを読み込んで起動する [root@server01 ~]# systemctl daemon-reload [root@server01 ~]# systemctl enable --now mywebserver # プロセスのcapabilityを /proc で確認する [root@server01 ~]# PID=$(systemctl show mywebserver --property=MainPID --value) [root@server01 ~]# grep -i cap /proc/${PID}/status CapInh: 0000000000000400 CapPrm: 0000000000000400 CapEff: 0000000000000400 CapBnd: 0000000000000400 CapAmb: 0000000000000400

0000000000000400は16進数で、CAP_NET_BIND_SERVICE(ビット10=0x400)のみが有効な状態を表します。他のcapabilityがすべて0になっており、最小権限で稼働していることが読み取れます。

3. CapabilityBoundingSetとNoNewPrivilegesの役割

CapabilityBoundingSet:プロセスが持てるcapabilityの上限(境界)を制限します。ここに含まれないcapabilityはexec後に一切取得できません
NoNewPrivileges:trueにするとsetuidビットやexecによるcapability昇格が無効になります。コンテナセキュリティでも必須とされる設定です

AmbientCapabilitiesCapabilityBoundingSetNoNewPrivilegesの3点セットで設定することで、サービスが必要最小限のcapabilityだけを持ち、かつそれ以上に昇格できない設計が完成します。

ケーパビリティ付与後のよくあるエラーと対処法

1. 「Operation not permitted」がまだ出る場合

setcapは正常に通ったのに起動するとPermission deniedになる場合、以下を確認します。

シンボリックリンクへのsetcap:setcapはシンボリックリンクに付与しても無効です。ls -laで実体ファイルのパスを確認し、そちらに付与してください
NFSやnoexecマウント:NFS経由のファイルシステムやnoexecオプション付きでマウントされた領域ではケーパビリティが無効になります
SELinuxの拒否:SELinuxが有効な環境では、ausearch -m AVC -ts recentでSELinuxの拒否ログを確認します

# シンボリックリンクか実体かを確認する [root@server01 ~]# ls -la /usr/bin/python3 lrwxrwxrwx 1 root root 9 1月 9 10:23 /usr/bin/python3 -> python3.12 # シンボリックリンク先の実体ファイルに対してsetcapを実行する [root@server01 ~]# setcap cap_net_bind_service=ep /usr/bin/python3.12 [root@server01 ~]# getcap /usr/bin/python3.12 /usr/bin/python3.12 cap_net_bind_service=ep

2. パッケージ更新後にケーパビリティが消える

dnf updateapt upgradeでバイナリが新しいバージョンに置き換わると、setcapで設定したxattr情報も消えます。

短期対策:更新後にsetcapを再実行する
長期対策:前節のsystemd AmbientCapabilities方式へ移行する(バイナリ側でなくunit file側で管理するため更新の影響を受けない)

3. シェルスクリプトに setcap できない

シェルスクリプト(#!/bin/bash)に直接setcapを設定しようとすると以下のエラーが出ます。

[root@server01 ~]# setcap cap_net_bind_service=ep /usr/local/bin/myscript.sh Failed to set capabilities on file '/usr/local/bin/myscript.sh' (Invalid argument)

ケーパビリティはELFバイナリ(コンパイル済みのプログラム)にのみ設定できます。シェルスクリプトの場合はスクリプトではなく実行するインタープリター(/bin/bash/usr/bin/python3等)に付与するか、systemdのAmbientCapabilities方式を使います。

本記事のまとめ

やりたいこと コマンド・設定
ファイルのケーパビリティを確認する getcap /usr/bin/python3.12
システム全体でケーパビリティ設定済みを検索 sudo getcap -r / 2>/dev/null
80番ポートバインドを非rootで許可する setcap cap_net_bind_service=ep /usr/bin/python3.12
pingを非rootで使えるようにする setcap cap_net_raw+ep /usr/bin/ping
ケーパビリティを削除する setcap -r /usr/bin/python3.12
systemdサービスに最小権限を持たせる unit fileにAmbientCapabilities=CAP_NET_BIND_SERVICE
capabilityの昇格を禁止する unit fileにNoNewPrivileges=true
setcapによる最小権限設計は、「rootかそれ以外か」という二択から脱却する実践的なアプローチです。特にシステムサービスではsystemdのAmbientCapabilitiesCapabilityBoundingSetを組み合わせることで、パッケージ更新後も設定が維持される堅牢な権限管理が実現できます。

CAP_SYS_ADMINのような広大なcapabilityに頼らず、本当に必要な権限だけを最小限で付与するという設計思想は、Linuxサーバーの長期運用においてセキュリティリスクを抑える上で非常に重要です。

capabilitiesで最小権限設計を身につけたら、次はLinuxサーバー全体のセキュリティ設計をプロのレベルで固めませんか?

ケーパビリティはLinuxセキュリティ設計の重要な一要素です。setuid・sudoers・SELinux・ファイアウォールと組み合わせて体系的に理解することで、本番環境で安全なサーバーを設計・運用できる力が身につきます。
ネットの切れ端の情報をコピペするだけでなく、現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。

「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。