LinuxのCapabilities機能を使用することで、root権限を小さく明確に定義された権限に分割し、リスクを大幅に低減しています。これにより、どのプロセスが特定のアクションを実行できるかを的確に制御し、各アプリケーションの攻撃対象領域を制限しています。.
中心点
- 微粒状 「全権限」ではなく、root権限を細かい権限に分割する。.
- ファイル機能 Set-UIDの代わりに、必要な権限をバイナリファイルに直接紐付ける。.
- 機能セット 制御:Permitted、Effective、Inheritable、Bounding を意図的に設定する。.
- 特権の分離: サービス、ツール、タスクを厳格に分離する。.
- 徹底したディフェンス: sudo、ロール、ログによる機能の拡張。.
なぜroot権限を分離するのですか?
ルートアカウントには以下の権限が与えられます フルアクセス ファイルやプロセスの世界において、しかしそれこそが重大なエラーを招く原因となります。たった一つの誤ったコマンドやエクスプロイトで、システム全体がダウンしてしまうのです。 そのため、私は広範囲にわたる操作を必要最小限に抑え、それによって被害の規模と復旧時間を最小限に抑えています。「最小権限の原則」に従うことで、サービスをコンパクトかつ管理しやすい状態に保ちます。また、rootによる直接ログインを無効にし、ロールベースの管理を採用し、完全なログを記録しています。.
Linuxのキャパビリティについて簡単に解説
Linuxのキャパビリティは、従来のroot権限を明確に定義された 特典. 各プロセスには、そのタスクに本当に必要な構成要素のみが割り当てられます。例えば、1024未満のポートへのバインドや、特定のシグナルの送信などです。これにより、以前の「すべてか、あるいは何もなし」という方式を回避しています。 カーネルはプロセスごとにこれらの構成要素を管理し、厳格に適用します。これにより、制御はきめ細かく、追跡可能になります。.
技術的には、スキルを以下のいずれかに結びつけています プロセス (その機能セットを通じて)または ファイル (拡張属性として security.capability (ELFバイナリ)。その際、 execve()-Start オプションを指定すると、カーネルはファイルのキャパビリティとプロセスのセットを統合します。簡単に言えば、ファイル属性から得られる許可されたキャパビリティと、呼び出し元プロセスの継承可能な権限が組み合わされて新しい Permitted-Set が形成され、指定されている場合は同時に Effective-Set でも有効化されます。 これにより、Set-UIDによる迂回が回避され、権限の可視性と検証可能性が確保されます。.
プロセスという文脈におけるケイパビリティ・セットの理解
どのプロセスにも複数の権限セットがあり、私はそれらを意図的に コントロール. パーミッテッド・セットは、プロセスが原則として保有できる権限を定義する。エフェクティブ・セットは、現在アクティブな権限を規定する。インヘリタブル・セットは、子プロセスに継承可能な権限を規定する。バウンディング・セットは厳格な上限を設定し、プロセスがそれを超えて拡大することを防ぐ。.
アンビエント・キャパビリティとセキュアビット
おなじみのセットのほかに、次のようなものがあります。 アンビエント・セット, 、その execve() 自動的に失効することはありません。私は、特権のないプロセスが、複数の エグゼック-(外部ユーティリティの呼び出し時など)階層をまたいで保持されるようにする。呼び出されたファイル自体がファイル・キャパビリティを設定していない場合のみ、アンビエント権限が実効権限に反映される――これにより、意図しない権限の昇格を防ぐ。.
以下の Securebits 遷移の詳細を制御します。例えば、UIDの変更後、プロセスが以前に設定された能力を維持できるかどうかなど(keepcaps) あるいは、そもそも新たな特権を取得してはならないのか(no_new_privs). 実際の運用では、エクスプロイトの連鎖を断ち切るために、Securebitsの設定を厳格にし、利便性を犠牲にしています。.
Set-UIDの代わりにファイル機能
Set-UIDバイナリをファイル機能に置き換えることで、リスクを 下げる. プログラムにroot権限を与える代わりに、必要な権限のみを設定します。典型的な変更例は以下の通りです: setcap 'cap_net_bind_service=+ep' /usr/bin/meinserver.と一緒に getcap -r / どのファイルにスキルが紐付けられているかを確認します。これにより、エスカレーションの経路が著しく短縮されます。.
重要なのは、ファイル機能は ELFバイナリ 作用します。インタプリタスクリプト(PythonやBashなど)は、これを確実に継承するとは限りません。そのような場合、私は特権操作を、静的検証済みの小さなユーティリティにカプセル化するか、ソケットアクティベーションを利用することで、サービス自体がバインドする必要を最初からなくしています。 また、ファイル権限にも注意を払っています。キャパビリティはカーネルに対して特別な権限を付与しますが、 なし 一般的なACLやPOSIXパーミッション。.
コピーや圧縮を行うと、機能はすぐに失われてしまいます: cp XATTR に対応していない、設定が間違っている umask または、拡張属性のないファイルシステムからビルドアーティファクトを削除する security.capability 暗黙のうちに。そのため、私は再現性のある方法で作業を行い、以下を活用しています: cp --preserve=xattr ..., tar --xattrs, rsync -X. パッケージビルドでは、インストールスクリプト内でファイル機能(File-Capabilities)を明示的に設定し、クリーンなVMでインストールをテストして、確認します。 getcap CI内。.
現実的なシナリオを用いた特権分離
Webサーバーにはポート80/443へのアクセスが必要ですが、カーネルモジュールやシステムの再起動へのアクセスは必要ないため、次のように設定しています。 CAP_NET_BIND_SERVICE それ以外は何もありません。バックアップエージェントはファイルの読み取りと書き込みはできますが、ネットワーク設定を変更することはできません。 モニタリングツールは指標に対する読み取りアクセス権限を持つが、変更権限は与えられない。このような権限の割り当てにより、攻撃の影響はシステム全体に及ぶことなく、ローカルに限定される。まさにこの分離によって、サービスの管理が容易になり、設定ミスを未然に防ぐことができる。.
sudoとロールの組み合わせ
機能は、きちんとした 役割構造, 、それらはそれらを補完するものです。私はsudo権限を厳格に付与し、完全なコマンドパスを指定し、「ALL=(ALL) ALL」のような一律的なルールは避けています。 権限の付与はすべてログに記録しています。グループは責任範囲をまとめ、カパビリティはプロセスにおける技術的な制限を設定します。これにより、過剰な権限を与えることなく、明確な責任範囲が確立されます。.
よくある落とし穴とベストプラクティス
- CAP_SYS_ADMIN を略称として使用しない: この権利は包括的なものです。私はこれを、より限定的な選択肢(例:.
CAP_SYS_CHROOT,CAP_SYS_TIME,CAP_SYS_NICE) あるいは、そもそもやめておく。. - ファイルへのアクセス権は厳格に維持されます: 機能は、DACを一般的に無効にするわけではありません。~なしでは
CAP_DAC_OVERRIDEカーネルは引き続き所有者とモードビットを尊重します。したがって、私は読み取り権限の付与を最小限に留めています。. - パス硬化: バイナリにファイル機能(File-Capabilities)を設定すれば、PATHスプーフィング(絶対パスを
sudoers, 検索パス内のディレクトリへの書き込み権限が制限されている)。. - 早めに、頻繁に投稿しよう: プロセスは、必要以上に高い権限で起動される場合があります。私は、重要な処理が完了した直後に、不要な権限を直ちに削除します(
prctl()/libcap)を設定し、no_new_privs, 、可能な場合は。. - 遺伝を制限する: 私は「Inheritable」セットと「Ambient」セットを小さく抑えています。子プロセスは新しいドアを開いてはなりません。.
- ビルドおよびデプロイパイプラインの確認: 私は、以下を確認します。
security.capabilityが保持され、ステージング手順(コンテナレイヤー、NFS、アーティファクトスキャナー)によってXATTRが削除されないようにします。.
主要な機能とリスクの概要
権限を付与する前に、必要な権限を明確に割り当て、そのリスクを確認します。以下の表は、典型的な例とその影響および分類を示しています。過度な権限の付与を避けるため、常に代替案を検討しています。特に CAP_SYS_ADMIN 私は極めて慎重に割り当てを行っています。可能な限り、広範な特権を、的を絞った限定的なものに置き換えています。.
| 能力 | 目的 | リスク | 例 |
|---|---|---|---|
| CAP_NET_BIND_SERVICE | 1024未満のポートにバインドする | 低~中 | Webサーバーを80/443に設定 |
| CAP_SYS_BOOT | システムを再起動する | 高い | 予定されている再起動 |
| CAP_SYS_MODULE | カーネルモジュールの読み込み/アンロード | 非常に高い | ドライバー管理 |
| CAP_SYS_ADMIN | 多彩な管理操作 | 非常に高い | 各種保守作業 |
| CAP_SETUID / CAP_SETGID | UID/GIDの変更 | 中~高 | 勤務中の権利の移転 |
表の内容以外にも、現在評価を行っているところだ CAP_SYS_PTRACE (プロセスのデバッグ)、, CAP_NET_ADMIN (ネットワークのパラメータ設定)および CAP_DAC_OVERRIDE (ファイルアクセス制限の回避)については極めて慎重であるべきだ。多くの場合、こうした権限を回避する手法が存在する。例えば、プロセス・スヌーピングの代わりに専用のメトリクス・エンドポイントを使用したり、バインド権限の代わりにソケット・アクティベーションやポート転送を利用したり、一律的なDAC回避の代わりに適切なファイル権限を設定したりといった方法である。.
コンテナおよびホスティングにおけるハードニング
マルチテナント環境においては、私は能力を根本的に見直すべきだと考えています 小さい そして、子プロセスへの継承を防ぐ。バウンディングセットが厳密に設定されると、コンテナのパフォーマンスは大幅に向上する。私はこれを、分離されたファイルシステム空間およびプロセス空間と組み合わせて利用している。分離の手法について概観するには、以下の入門記事が参考になる。 プロセス分離. これにより、たとえあるアプリケーションに不具合が生じても、各サービスは独立して動作し続けます。.
実際には、コンテナの設定をデフォルトで「すべてドロップ、指定して追加」にしています: --cap-drop=ALL --cap-add=NET_BIND_SERVICE Webサービス用、マウント権限なし、なし SYS_ADMIN. オーケストレーション環境では、プロファイルを中央で管理し、ポリシーで検証しています。重要な点として、イメージ内のファイル機能には依存せず、オーケストレーターで実行時の権限を付与しています。これにより、再現性と監査可能性が確保されます。.
SELinux および AppArmor との連携
「Capabilities」はプロセスが実行できる操作を制御し、「MACプロファイル」はプロセスがアクセスできる対象を定義するもので、この2つは互いに調和している 良い. 私はCapabilitiesを厳格に設定し、SELinuxやAppArmorにファイルやソケットへのアクセスを制限させています。これにより、エクスプロイトに対して複数の障壁を設ける多層防御が実現されます。簡単な比較はこちらにあります: SELinux 対 AppArmor. これにより、侵害されたサービスは封じ込められ、被害を最小限に抑えることができる。.
実践:段階を追って進める
まずは、すべてのサービスとその 必要条件. その後、不要なSet-UIDバイナリを削除するか、適切なファイル権限に置き換えます。sudoの設定は厳格に行い、各エントリを文書化します。役割とグループにタスクを割り当て、権限は最小限に抑えます。 その後、負荷テストを実施し、ログエントリに予期せぬ拒否がないか確認します。.
簡潔なチェックリストが、移行作業の助けになっています:
- 各業務ごとの要件を文書で明確に定める(本当に必要なものに限る)。.
- 既存の特権を整理する (
find / -perm -4000,getcap -r /). - 的を絞って置き換える:Set-UID を廃止し、ファイルの権限設定(File-Capabilities)を設定し、権限を早期に削除する。.
- 継承を閉じる:バウンディングセットを絞り込み、Inheritable/Ambientを最小化する。.
- systemd/コンテナプロファイルのセキュリティ対策 (
CapabilityBoundingSet=,NoNewPrivileges=yes). - 負荷テストの実施、ログおよび監査記録の確認、例外の記録。.
モニタリング、ネームスペース、および継続的な監査
ログファイル、アラート、システムコールを監視し、望ましくない動作を即座に 目立つ. キャパビリティ、sudoルール、およびロールの変更については、定期的に検証を行っています。必要に応じて、カーネルの分離メカニズムを用いてワークロードをさらに分離しています。以下の概要は、そのための良い出発点となります。 ネームスペースとCgroups. そうすることで、異常を早期に発見し、周囲を清潔に保つことができます。.
日常的には、簡単なチェックを行っています: capsh --print 現在のスキルセットを表示し、, getpcaps プロセス権限を一覧表示し、 /proc//status 私は読んでいる CapEff, CapPrm, CapBnd.と一緒に 監査役 キャパビリティステータスの変更(例:ルールが capset)、イベントとデプロイメントを関連付け、突然強力な権限が出現した際にアラームを設定します。厄介なケースでは、以下のツールが役立ちます strace -e capget,capset, 、権限の改ざんを可視化するために。.
systemdおよびコンテナの実践例
多くのサービスをsystemdユニットとして運用し、そこで権限をカプセル化しています:
CapabilityBoundingSet=CAP_NET_BIND_SERVICE利用可能な権利の範囲を必要最小限に絞り込みます。.AmbientCapabilities=CAP_NET_BIND_SERVICEこの設定により、サービスはファイル機能なしで80/443ポートにバインドできるようになります。.NoNewPrivileges=yesその後の権利の拡大を妨げる。.ユーザー=,Group=,プロテクトシステム=ストリクト,PrivateTmp=yes断熱を完成させます。.
Container内では、プロセスを可能な限り最小限に起動するようにしています: docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE --read-only. 短期間しか存続しないジョブについては、ビルドの再現性を確保し、権限を環境に紐づけるため、イメージ内のファイル機能ではなく実行時間機能を使用しています。.
実務における具体的な移行事例
- Set-UID なしの ping: 代わりに
setuid root私はsetcap 'cap_net_raw=+ep' /bin/ping. これにより、どのユーザーも完全なroot権限を持たずにICMPソケットを開くことができます。私は定期的にgetcap /bin/ping, その属性が保持されているかどうか。. - ポート80/443でのWebサービス: 私は一般ユーザーとしてサービスを稼働させ、以下の情報のみを提供します
cap_net_bind_service. もしそのサービスがもともとリバースプロキシの後ろにあるのであれば、代わりにそこで80番または443番ポートにバインドし、内部ではハイポートを使用するという方法もあります。これなら、特別なスキルは一切必要ありません。. - 訴訟における当事者の変更: 一時的に権限を上げる必要があるツール(例:Niceレベルの設定など)については、次のように設定しています
cap_sys_nice, 、アクションは早めに済ませて、その後そのスキルを解除する。永続的に権限が上昇した状態は避けるようにしている。.
限界と代替案
すべてのユースケースで機能が必要というわけではありません。多くの場合、リスクの低い安全な代替手段が存在します:
- ソケットの有効化: Init サービス(例:systemd)は、特権ソケットを開き、それをプロセスに渡します。これにより、私のサービスには Bind 権限が不要になります。.
- ポート転送: ファイアウォールルールを使用して、80/443をハイポートにリダイレクトしています。サービスの権限は変更されず、システムの動作にも変化はありません。.
- 非特権のローポート: 状況に応じて、特権のないポートのしきい値を引き上げることも可能です。ただし、そうするとすべてのプロセスに対する許容範囲が広がってしまうため、リスクと利便性を慎重に比較検討しています。.
- 万能選手ではなく、小さな助っ人: 幅広い権限を持つ巨大なモノリス型システムよりも、能力がたった一つだけの、監査済みの小さなバイナリの方がましだ。.
簡単にまとめると
と一緒に Linuxのカパビリティ 私はroot権限を、管理しやすい小さな権限に分割します。ファイルキャパビリティは、リスクの高いSet-UIDバイナリに取って代わり、攻撃による影響を軽減します。厳格なsudoルール、ロール、およびMACプロファイルと組み合わせることで、明確な境界を持つ多層防御が構築されます。 バウンディングセットと継承可能セットは、権限の継承を制限し、プロセスを適切な範囲内に維持します。このように対処することで、攻撃対象領域を著しく縮小し、管理負担を管理可能な範囲に抑えることができます。.


