みなさまこんにちは、れおりんです。
今回はLinuxの「Capabilities(ケイパビリティ)」について紹介します。これ、Linuxでシステム開発や運用をしていると、ちょっと耳にしたことがあるかもしれないヤツです。記事ではすべての技術要素を細かく掘り下げるのは難しいので、まずは「こんな概念なんだな」っていう全体像と、重要そうな用語、そして僕なりの意見を交えながらお話していこうと思います。
root特権を分解する?:Capabilitiesの登場背景
従来、Linuxの「root」ってユーザーは全知全能の神みたいな存在でした。rootユーザーになれば、なんでも好き放題できてしまう。だけど、それって結構リスキーなんですよね。もしroot特権を持ったプロセスが侵害されたら、システム全体が危険にさらされる。
そこで考えられたのがLinux Capabilitiesです。
「root特権」をまるっと1個与えるんじゃなくて、「ファイルオーナーを変更する権限」「低番号ポートを開く権限」「システムクロックを変える権限」みたいに、小さな特権の塊に分けてしまおう、という発想です。これによって、必要最小限の権限だけをプロセスに与えることができるようになり、もしそのプロセスがヤバいことになっても、被害が限定されます。
Capabilitiesの基本的な考え方
プロセスは、permitted
(許可可能)、inheritable
(継承可能)、effective
(実行時有効)といった複数のケイパビリティセットを持ちます。これらは実行ファイルやユーザーID変更などのイベントを通じて変化します。また、ファイル自体にcapabilityを埋め込むことも可能で、特定のバイナリを実行した時に必要な特権だけを自動で有効化することができます。
ポイントは以下です:
- permitted set:プロセスが「持ちうる」能力の上限
- effective set:実際に「今有効な」能力
-
inheritable set:
execve()
などで新しいプログラムを実行した際に継承可能な能力 - ambient set:非特権バイナリ実行でも継続できる新しい仕組み(Linux 4.3以降)
イメージ:root権限を色んな小箱に分ける感じ
root特権が巨大な宝箱だとしたら、その中身を小さな箱に分けて、それぞれの箱は個別に渡せるイメージです。
例えばこういった小箱(capability)が用意されています:
-
CAP_CHOWN:任意のファイルの所有者を変更できる
通常のユーザーは自分所有のファイルにしかchownできませんが、これがあれば何でも変更可能。 -
CAP_DAC_OVERRIDE:
ファイルパーミッション(読み書き実行権)を無視してアクセスできる。
本来ならrootのみがパーミッションチェックをスキップ可能でしたが、この権限を分離。 -
CAP_NET_ADMIN:
ネットワークインターフェースの設定変更やファイアウォールルール変更、ルーティングテーブル更新など、ネットワーク管理に関わる機能がまとめられています。 -
CAP_NET_BIND_SERVICE:
1024未満の特権ポートにバインドできる(Webサーバとかで便利)。 -
CAP_SYS_ADMIN:
マウント操作など、超広範囲な管理権限(小箱のなかでもでかい箱)。
非常に強力かつ幅広い特権で、「new root」とも呼ばれるほど多機能です。 -
CAP_SYS_TIME:
システムクロックをいじれる。 -
CAP_SYS_BOOT:
システムの再起動(reboot)を行う能力。 -
CAP_SYS_PTRACE:
任意のプロセスをptraceできる(デバッガのようにプロセスを覗いたり、操作する)特権。 -
CAP_SETUID、CAP_SETGID:
任意のプロセスUID/GIDを変更する能力。 -
CAP_IPC_LOCK:
メモリをロックしてスワップアウトされないようにするなど、IPC(共有メモリ)やロック機能に関する特権。 -
CAP_BPF / CAP_PERFMON / CAP_CHECKPOINT_RESTORE:
新しいLinuxで追加された特定機能用capabilities。それぞれBPFの特権操作やパフォーマンスモニタリング機能、checkpoint/restoreなど。
なぜCapabilitiesが嬉しいのか
ソフトウェア開発って複雑さと戦う必要があるって、前の記事(オブジェクト指向やDDDのお話)でも言いましたよね。ここでも同じで、システムを安全に保つには特権の付与方法をシンプルに、かつ安全にしたいわけです。
セキュリティ向上が最大の理由です:
従来:
- setuid rootプログラムがあれば、それが侵害された瞬間にシステムがほぼ終わり
- 1つのバグで全部が危ない
Capabilities導入後:
- 必要な能力(特権)だけを付与する
- もし侵害されても、そのプログラムが持ってる特定の機能だけが悪用される
- システム全体への影響がだいぶ小さくなる
つまり、ソフトウェアのセキュリティを強化するための仕組みなんですね。
「だから何?」な活用例
-
特権が必要なネットワークサーバー
たとえばWebサーバを運用するとき、80番ポート(特権ポート)を開くのにrootが必要でした。だけどCapabilitiesがあれば、CAP_NET_BIND_SERVICE
という特権だけ付けてWebサーバープロセスを起動できます。rootとして全部は与えず、「特権ポートを開く能力」だけを与えるイメージ。これで仮にそのWebサーバがハックされても、相手は「root全能権限」じゃなくて「特定のネットワーク特権」しか使えないので、まだ被害がマシです。 -
ファイルシステム操作用ツール
マウント操作にはCAP_SYS_ADMINが必要です。これを持つ特定のコマンドだけに付与し、他の特権は与えないことで、万が一そのコマンドが侵害されても「マウント変更」程度の被害で抑えられます。 -
コンテナ内プロセス
コンテナ環境やユーザ名前空間の活用時にも便利。コンテナ内部で特定の権限だけを渡せば、コンテナ内で必要最低限の管理操作を可能にしつつ、ホスト全体を危険にさらさない設計ができます。
Kubernetesでの活用例
Kubernetesでは、コンテナのセキュリティを制御する重要な要素としてcapabilitiesが使われています。PodのSecurityContextで細かく制御できるんですよ。
基本的な使い方
Kubernetes上でコンテナを動かすとき、デフォルトでは以下のcapabilitiesが付与されます:
capabilities:
add:
- CHOWN
- DAC_OVERRIDE
- FOWNER
- FSETID
- KILL
- SETGID
- SETUID
- SETPCAP
- NET_BIND_SERVICE
- NET_RAW
- SYS_CHROOT
でも、これって結構多いんですよね。必要最小限にするには、Podの定義でこんな感じで明示的に指定します:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
containers:
- name: nginx
image: nginx
securityContext:
capabilities:
drop: ["ALL"] # デフォルトのcapabilitiesを全部外す
add: ["NET_BIND_SERVICE"] # 必要なものだけ追加
実践的なユースケース
-
Nginxコンテナの最小権限化
Nginxって80番ポートを使うだけならNET_BIND_SERVICE
だけあれば十分です:securityContext: capabilities: drop: ["ALL"] add: ["NET_BIND_SERVICE"]
-
デバッグ用コンテナ
トラブルシューティング用のコンテナには、ネットワーク診断とプロセス確認用の権限を付与:securityContext: capabilities: add: ["NET_ADMIN", "SYS_PTRACE"]
-
ストレージ管理Pod
永続ボリュームを扱うPodには、ファイルシステム関連の権限を付与:securityContext: capabilities: add: ["SYS_ADMIN", "DAC_OVERRIDE"]
セキュリティのベストプラクティス
-
最小権限の原則を徹底
- デフォルトの capabilities をすべて drop して、必要なものだけ add
- Pod Security Policy や Security Context Constraints で制限
-
危険なcapabilitiesの制限
-
SYS_ADMIN
のような強力な capabilities は極力避ける - 代わりに具体的な機能に対応する capabilities を使う
-
-
namespace単位での制御
- 開発環境と本番環境で異なるポリシーを適用
- 特権的な capabilities は専用の namespace に限定
トラブルシューティングのコツ
コンテナが起動しないときは、capabilitiesが足りない可能性があります。こんな感じで調べます:
# Podのログを確認
kubectl logs <pod-name>
# コンテナ内でcapabilitiesを確認
kubectl exec <pod-name> -- grep Cap /proc/1/status
あと、capabilities関連のエラーは結構わかりにくいんですよね。例えば「Permission denied」って出たときは、必要なcapabilityが足りない可能性を疑ってみるといいです。
まとめ
Linux Capabilitiesは、root特権をきれいに分解して必要な分だけプロセスに与える仕組みです。
- root特権=巨大な1つの力を分割
- 小さな特権を必要なだけ付与して、被害範囲を限定
- コンテナやサーバ運用などでセキュリティと柔軟性を向上
- ファイルにcapabilitiesを付与し、非rootユーザーでも必要最小限の特権を行使可能
「セキュリティ」という面で「最小権限の原則」を実現する一つの工夫です。こんな感じで世の中には、システムをより安全に、より保守しやすくするための仕組みがたくさんあるんですね。興味があればぜひ調べてみてください。
以上、れおりんでした!