サーバー上で動いているあるプロセスが突然CPUを100%使い続け、他のサービスが応答しなくなった経験はないでしょうか。あるいは、メモリリークが起きたプロセスがシステム全体をフリーズさせてしまった、そんな障害を経験した方もいるはずです。
攻撃者は意図的にこうしたリソース枯渇状態を引き起こすこともあります。しかし同様の被害は、設定ミスやバグのあるアプリケーションが原因でも起こります。いずれの場合も、被害を一つのプロセスに封じ込める仕組みがあれば、サーバー全体への影響を大幅に減らせます。
この記事では、Linuxのリソース管理機能「cgroups(Control Groups)」を使って、特定のプロセスがシステム全体に悪影響を与えるリスクを減らす方法を、現場で使えるレベルで解説します。コマンド手順からsystemdとの連携まで、情シス1人でも実践できる設定を紹介します。

cgroupsとは?(概要・なぜ重要か)
cgroups(Control Groups)は、Linuxカーネルに組み込まれたリソース管理機能です。プロセスやプロセスグループに対して、CPU・メモリ・I/O・ネットワーク帯域などのリソース使用量を制限・測定・優先度付けできます。
cgroupsはDockerやKubernetesのようなコンテナ技術の基盤にもなっており、「あるプロセスが使えるリソースの上限を設定する」というシンプルな考え方でシステムの安定性を高めます。
cgroupsのバージョンについて
cgroupsにはv1とv2の2つのバージョンがあります。
・cgroups v1: 各リソース(CPU・メモリなど)が独立したサブシステムで管理される。複雑で設定が煩雑になりがちです
・cgroups v2: 2016年にカーネル4.5で導入。単一の統一階層で全リソースを管理。RHEL 9・Ubuntu 22.04以降でデフォルト有効です
現在では新規構築のサーバーでcgroups v2が標準となっています。本記事では主にcgroups v2を前提に説明しますが、v1固有の操作についても触れます。
なぜセキュリティ観点で重要か
cgroupsは多層防御(ディフェンス・イン・デプス)の一つとして機能します。ゼロデイ脆弱性や設定ミスによってプロセスが暴走したとしても、cgroupsによるリソース上限が設定されていれば、他のサービスへの影響を局限できます。特に次のようなシナリオで効果を発揮します。
・ウェブアプリケーションがDoS状態に陥ってもSSHでの管理アクセスを確保できます
・マルウェアがCPUを大量消費するマイニング処理を行っても、他のサービスへの影響を抑えられます
・バグのあるスクリプトがメモリを無制限に消費してシステム全体がOOMキルされる事態を防げます
cgroupsで防げるリスクとは(敵を知る)
cgroupsが対策できる主な脅威とリスクを整理します。
リソース枯渇型DoS攻撃
攻撃者がWebアプリケーションの処理を大量リクエストで圧迫し、CPUやメモリを使い切らせる攻撃です。cgroupsでWebサーバープロセスのCPU使用量を制限しておけば、攻撃を受けてもSSHや監視ツールが動き続けるため、インシデント対応が可能です。
クリプトジャッキング(不正マイニング)
マルウェアが感染後にCPUを使って仮想通貨のマイニングを行うケースです。cgroupsでCPU使用量を制限していれば、マイニングの効率を大幅に低下させ、検知するまでの被害を抑えられます。
プロセス暴走・メモリリーク
アプリケーションのバグや設定ミスによってメモリが際限なく確保され続けるケースです。cgroupsのメモリ上限設定(memory.max)によって、プロセスが上限に達した時点でOOMキラーが働き、システム全体ではなく問題のプロセスのみが終了します。
フォーク爆弾
プロセスが自分自身を無限に複製してシステムリソースを食い尽くす攻撃です。cgroupsのpids(プロセス数制限)でフォーク爆弾の被害を局限できます。なお、Linuxのulimitによるリソース制限と組み合わせることで、より強固な防御が実現できます。
cgroupsの実践設定手順
1. cgroups v2が有効かどうか確認する
まず現在の環境でcgroups v2が有効かどうかを確認します。
# cgroups v2が有効かどうか確認(cgroup2fs と表示されれば v2 が有効) stat -fc %T /sys/fs/cgroup/ # systemdが認識しているcgroupsの情報を確認 systemd-cgls | head -20
RHEL 9・Ubuntu 22.04・Debian 11以降では、デフォルトでcgroups v2が有効です。cgroup2fs と表示された場合はv2が使えています。tmpfs と表示された場合はcgroups v1(またはハイブリッドモード)です。
2. systemdのユニットファイルでリソースを制限する
実用上もっとも簡単で安定した方法は、systemdのユニットファイルにリソース制限ディレクティブを追加することです。systemdは内部でcgroupsを使っており、設定が再起動後も永続します。
既存のsystemdサービスにCPU・メモリ制限を追加する例を示します。ここではnginxを例にします。
# 既存ユニットファイルを上書きせずにオーバーライドファイルを作成 sudo systemctl edit nginx.service # エディタが開いたら以下の内容を入力して保存する # [Service] # CPUQuota=80% # MemoryMax=512M # MemorySwapMax=0 # TasksMax=200 # 設定を反映 sudo systemctl daemon-reload sudo systemctl restart nginx # 設定が適用されているか確認 systemctl show nginx.service | grep -E 'CPUQuota|MemoryMax|TasksMax'
主要なsystemdリソース制限ディレクティブは以下の通りです。
| ディレクティブ | 内容 | 設定例 |
|---|---|---|
| CPUQuota= | CPU使用率の上限(%指定) | CPUQuota=50% |
| MemoryMax= | メモリ使用量の上限 | MemoryMax=256M |
| MemorySwapMax= | スワップ使用量の上限(0で無効化) | MemorySwapMax=0 |
| TasksMax= | 生成できるタスク(スレッド含む)の上限数 | TasksMax=100 |
| IOReadBandwidthMax= | ディスク読み込み帯域の上限 | IOReadBandwidthMax=/dev/sda 50M |
| IOWriteBandwidthMax= | ディスク書き込み帯域の上限 | IOWriteBandwidthMax=/dev/sda 20M |
systemdのサンドボックス化(PrivateTmp・NoNewPrivilegesなど)と組み合わせると、リソース制限だけでなくファイルシステムアクセスや権限昇格も防ぐ、より強固なサービス隔離が実現できます。
3. cgroups v2を直接操作する(応用設定)
systemd経由以外でも、/sys/fs/cgroup を直接操作してcgroupsを設定できます。特定のプロセスに対して即時に制限を適用したい場合や、systemdで管理されていないプロセスに使います。
# 新しいcgroupを作成(ディレクトリを作るだけで自動認識される) sudo mkdir /sys/fs/cgroup/myapp-limit # サブシステムコントローラーを有効化(子cgroupでメモリとCPUを制御可能にする) echo "+memory +cpu" | sudo tee /sys/fs/cgroup/cgroup.subtree_control # メモリ上限を256MBに設定 echo $((256 * 1024 * 1024)) | sudo tee /sys/fs/cgroup/myapp-limit/memory.max # CPU使用率の上限を50%に設定(100000マイクロ秒中50000マイクロ秒の割当) echo "50000 100000" | sudo tee /sys/fs/cgroup/myapp-limit/cpu.max # 特定のプロセス(PID=12345)をcgroupに追加 echo 12345 | sudo tee /sys/fs/cgroup/myapp-limit/cgroup.procs # cgroup内のプロセス一覧を確認 cat /sys/fs/cgroup/myapp-limit/cgroup.procs
/sys/fs/cgroup への変更は再起動で消えます。永続化にはsystemdのユニットファイルを使うか、起動時スクリプトをsystemdサービスとして登録してください。
4. cgroupsの状態確認とモニタリング
設定したリソース制限が機能しているかを確認する手順です。
# systemdスライス・サービスのリソース使用状況をリアルタイム確認 systemd-cgtop # 特定サービスのcgroup情報を表示 systemctl status nginx.service # メモリ使用量の詳細を確認(cgroups v2) cat /sys/fs/cgroup/system.slice/nginx.service/memory.current # cgroups階層全体をツリー表示 systemd-cgls
中小企業でも今日からできること
「cgroupsの設定は難しそう」と感じるかもしれませんが、systemdとの連携を使えば最小限の手間で始められます。
ステップ1: 重要なサービスのメモリ使用量を把握する
すべてのサービスにいきなり制限をかける必要はありません。まず通常運用時のメモリ使用量を確認し、その1.5倍程度を上限の目安にします。
# メモリ使用量の多いプロセスを確認する ps aux --sort=-%mem | head -10 # systemd管理下のサービスのメモリ使用量を確認する systemctl show nginx.service | grep MemoryCurrent
ステップ2: 外部公開サービスにCPUとメモリの上限を設定する
WebサーバーやAPIサービスなど、外部からアクセス可能なサービスから優先的にリソース制限を適用しましょう。特にnginx・Apache・MySQL・PostgreSQLはまず設定すべき対象です。
ステップ3: SSH・監視ツールには制限をかけない
sshd.serviceや監視エージェントには意図的にリソース制限を設けないでください。インシデント発生時にこれらのサービスへのアクセスが確保できることが最重要です。
なお、Linuxサーバーの初期セキュリティ設定チェックリストの一環として、cgroupsによるリソース制限を組み込むと、セキュリティの網羅性が高まります。
Linuxのプロセス管理やリソース制御の基礎については、姉妹サイトLinuxMaster.JPでも詳しく解説しています。
よくある誤解と注意点
【注意】cgroupsは攻撃を「防ぐ」ものではない
cgroupsはリソース使用量を制限するものであり、攻撃そのものを検知・ブロックするわけではありません。IDS/IPSやWAF、ファイアウォールと組み合わせた多層防御の一要素として位置づけましょう。
【注意】MemoryMax設定後にOOMキルで意図しないサービス停止が起こることがある
MemoryMaxを設定する際は、通常の負荷時のメモリ使用量を事前に測定してから、適切な余裕を持った値を設定してください。小さすぎる値を設定すると、通常運用でもOOMキルが発生します。設定後しばらくは systemd-cgtop で消費量を監視することを推奨します。
【注意】cgroups v1とv2の設定ファイルは異なる
cgroups v1とv2ではファイルシステム階層も制御ファイル名も異なります。インターネット上の古い情報(2018年以前のもの)はv1向けの設定例が多いため、参照する際はバージョンを確認してください。
【注意】DockerやKubernetesを使っていてもホストOSの設定は必要
コンテナを使っている場合でも、ホストOSのサービスにはcgroupsによる制限が必要です。コンテナランタイム自体が暴走した場合や、ホストOS上で動くその他のサービスを保護するためにも有効です。Dockerコンテナのセキュリティ強化と組み合わせて使いましょう。

本記事のまとめ
| 対策 | 効果 | 難易度 |
|---|---|---|
| systemdでCPUQuota・MemoryMax設定 | プロセス暴走・DoSの影響を局限 | 低(すぐできる) |
| TasksMax設定 | フォーク爆弾対策 | 低(すぐできる) |
| MemorySwapMax=0 | スワップ使用による性能劣化防止 | 低(すぐできる) |
| systemd-cgtopによる定期監視 | 異常なリソース消費の早期発見 | 低(すぐできる) |
| IOReadBandwidthMax設定 | ディスクI/O帯域の公平な分配 | 中(デバイス名の確認が必要) |
cgroupsによるリソース制限は、インシデント発生時の「封じ込め」能力を高める重要な対策です。特にsystemdのオーバーライドファイルを使った設定は、数行の変更で実現でき、再起動後も永続します。
まずは外部公開しているWebサービスやデータベースに MemoryMax と CPUQuota を設定することから始めてみてください。Linuxのcapabilitiesやseccompによるシステムコール制限と組み合わせることで、より深いプロセス分離が実現できます。
PR
SELinux・PAM・ファイアウォール・ログ監視まで、Linuxサーバーのセキュリティ強化を体系的に学べる一冊。cgroupsを含むリソース管理や各種セキュリティ機構の全体像を把握したい方に最適です。
