ROAMSWITCH SERVER 1.10.6 ・ 最終更新: 2026-09-26

RoamSwitch Server Edition 運用マニュアル

クラウド VPS(AWS, GCP, Azure, さくらのVPS, ConoHa 等)、データセンター、コンテナホスト環境のための公式導入・設定・運用リファレンスです。

1. 概要 & システム要件

RoamSwitch Server Edition は、常時インターネットに晒される Linux サーバー向けに特化した完全ヘッドレス(GUI 依存ゼロ)の自律型セキュリティ&整合性防護スイートです。

Wi-Fi 接続先の切り替えに応じた動的プロファイル切替を行うクライアント版とは異なり、サーバー版は「インバウンド既定拒否 (Default Drop)」「クリティカルパス改ざん監視 (FIM)」「カーネル LPE (Frag Gap) の予防的封鎖」「eBPF ランタイム脅威監視」「SSH 締め出し防止フェイルセーフ」「Telegram / LINE / Webhook への自律緊急通報」を中核機能とします。

Zero Telemetry 原則(利用者の情報は送らない。既定の外部通信は署名付きデータの受信だけ)
RoamSwitch は、お客様のサーバーのIPアドレス、ポート情報、ファイルハッシュ、システムログ、診断結果を、ベンダーやクラウドへ送信しません。デーモンバイナリ自体には TLS / HTTP クライアントが組み込まれていません。既定で外へ出る通信は、パッケージマネージャーの更新を除くと、署名付きデータの匿名取得(cve_kernel_map_updates_enabled、既定オン)だけです。取得するのは、カーネルCVEデータ、Web ルール、Ubuntu サーバーでは OS パッケージ CVE 照合用の Ubuntu のパッケージCVEデータです。roamswitch-updater が lafine.net から Ed25519 署名つきのデータを HTTPS GET で受信するもので(署名付きマニフェストの確認は毎日、CVEデータ本体は約30日に1回、Web ルールはマニフェストの版が新しいときだけ)、クエリ文字列と Cookie がなく、ソフトウェアを名乗るヘッダは固定の User-Agent: RoamSwitch-Updater だけで、このホストの情報は一切送りません。roamswitch server config set cve_kernel_map_updates_enabled false(またはセットアップウィザード、サーバー TUI)で止められ、止めても監査は組み込みベースラインで動きますが、Ubuntu サーバーの OS パッケージ CVE 照合は「CVEデータ未取得」になります。それ以外に外へ出る通信は、運用者が明示的に有効にした次のものだけです。通知(Telegram / LINE / Webhook)、npm署名検証(npm_audit_signatures_enabled。コマンド実行時のみ)、そしてイベント転送(forward_enabled、既定オフ。§16)。イベント転送は運用者が指定した自組織の宛先(SIEM・syslog・Webhook)にだけ送られ、TLS の syslog はシステムの openssl、構造化 Webhook は curl のサブプロセスで送信します。 このほか、Sensor ペアリング(sensor_pairing_enabled、既定オフ)と、同梱の別ツール accessscope の LLM 連携(既定オフ。コマンドラインでは --llm を指定したときだけ)も、運用者が有効にしたときだけ外部に接続します。例外の一覧は Server Edition セキュリティ設計書の Zero Telemetry の項にあります。

動作要件

2. インストール手順

公式の署名付きパッケージリポジトリを利用することで、依存関係の自動解決とシステム更新コマンドでの安全な自動アップデートが可能になります。

2.1 APT(Ubuntu / Debian / Raspberry Pi OS)

# 1. リポジトリ署名鍵の登録
curl -fsSL https://lafine.net/apt/roamswitch-archive-keyring.asc \
  | sudo gpg --dearmor -o /usr/share/keyrings/roamswitch-archive-keyring.gpg

# 2. リポジトリの追加
echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/roamswitch-archive-keyring.gpg] https://lafine.net/apt stable main" \
  | sudo tee /etc/apt/sources.list.d/roamswitch.list

# 3. インストール
sudo apt update && sudo apt install roamswitch-server

2.2 DNF / RPM(Fedora / RHEL / AlmaLinux / Rocky Linux)

# 1. GPG 鍵のインポート
sudo rpm --import https://lafine.net/rpm/RPM-GPG-KEY-roamswitch

# 2. リポジトリ設定ファイルの追加
sudo curl -fsSL -o /etc/yum.repos.d/roamswitch.repo https://lafine.net/rpm/fedora/roamswitch.repo

# 3. インストール
sudo dnf install roamswitch-server

2.3 openSUSE(zypper)

sudo rpm --import https://lafine.net/rpm/RPM-GPG-KEY-roamswitch
sudo zypper addrepo https://lafine.net/rpm/opensuse/roamswitch.repo
sudo zypper refresh && sudo zypper install roamswitch-server
パッケージの競合(Conflicts)について
クライアント版(roamswitch)とサーバー版(roamswitch-server)は同一ホストへの重複導入を防ぐため、パッケージマネージャのメタデータで排他指定(Conflicts)されています。サーバー用途では必ず roamswitch-server を指定してください。

3. 初期設定 & サービス確認

3.1 サービス起動状態の確認

インストールが完了すると、roamswitch-server.service が即座に起動し、自動起動(enabled)に設定されます。

sudo systemctl status roamswitch-server.service

3.2 対話型セットアップウィザード

以下のコマンドで対話型セットアップウィザードを起動し、ポート・保守元 IP・通知先・封じ込め動作を対話形式で構成します(Enter で既定値を採用)。

sudo roamswitch server setup
  1. ポートの指定: SSH メンテナンスポート(既定 22)と公開サービスポート(既定 80,443)をそれぞれカンマ区切りで入力します。
  2. 保守元 IP の指定: SSH 踏み台や監視元の IP / CIDR(例: 203.0.113.50/32)を指定します。ウィザードでは必須で、空欄のまま進めません。全 IP からの SSH を許可する場合は、ANYWHERE と入力します(その場合、隔離中も管理用 SSH が全世界に開いたままになります)。
  3. 緊急通知先の設定: Telegram Bot、LINE Messaging API、汎用 Webhook(Slack / Discord / Teams)をそれぞれ有効化します。
  4. eBPF 重大イベント時の動作: isolate(ホスト隔離)/ freeze(当該プロセス凍結)/ alert_only(通知のみ)を選択。保存後、テスト通知の送信とサービス再起動を確認します。
  5. CVE データの自動更新(既定 y): コンテナ隔離監査が使うカーネルCVEデータベースと Web ルール、Ubuntu サーバーでは OS パッケージ CVE 照合が使う Ubuntu のパッケージCVEデータを、lafine.net から匿名取得(署名付きマニフェストの確認は毎日、CVEデータ本体は約30日に1回、Web ルールはマニフェストの版が新しいときだけ。HTTPS GET のみ、クエリ文字列・Cookie なし、ソフトウェアを名乗るヘッダは固定の User-Agent: RoamSwitch-Updater のみ、Ed25519 署名を検証)するかを選択します。このホストの情報は送りません。サーバー版で既定で有効な唯一の外部通信で、n にすると止まります(監査自体は組み込みベースラインで動作しますが、Ubuntu サーバーの OS パッケージ CVE 照合は「CVEデータ未取得」になります)。既存の server.conf で無効にしてある場合は、既定の答えも n のままです。
  6. File Scan Guard の設定: メール中継・共有フォルダ・アップロード先のウイルススキャン(§13)を有効化するかどうか、対象ディレクトリを設定します。任意機能で既定は無効です。
  7. Resource Guard の設定: ネットワーク公開サービスの継続的な RSS 増大(メモリリーク/DoS)やクラッシュループを検知するリソース枯渇ガードの有効化を設定します。
  8. 常時稼働の中核保護についての説明表示: インバウンド既定拒否・FIM・eBPF 連携など、ウィザードを介さず常時有効な中核防御機能の一覧が表示されます(設定入力はありません)。
  9. 調査エージェント連携(investigation)の設定: eBPF 重大イベントや、クリティカルパス FIM・依存関係ロックファイル改ざん検知(いずれも通知のみ判定時)について、外部 AI エージェント CLI(Claude Code / agy / Codex CLI / OpenCode、またはカスタムコマンド)に一次調査を自動的に委任するかどうかを設定します(§10.1)。既定は無効です。
Telegram Chat ID の注意
スーパーグループの Chat ID は -100 で始まる負の数値です(例 -1001234567890)。curl -s "https://api.telegram.org/bot<token>/getUpdates" のレスポンス中の "chat":{"id":...} で正しい値を確認できます。

3.3 34項目 サーバーセキュリティ診断の実行

sudo roamswitch status --server

現在のファイアウォール状態、Frag Gap 対策、Yama LSM メモリ保護、重要ファイルパーミッション、Docker 露出など 34 項目を一括監査し、0〜100 のセキュリティスコアと評価等級(S〜C)を表示します。

各チェック項目には、コンプライアンス報告に利用できるよう NIST CSF 2.0 のファンクション/カテゴリ(該当する場合は必ず付与)と、確信度の高いマッピングが存在する場合に限り CIS Controls v8 の管理策番号が付与されます。

4. ファイアウォール & ポート設定

設定ファイル /etc/roamswitch/server.conf は、機密情報保護のためパーミッション 0600(root のみ読み書き可能)が強制されます。

# --- ファイアウォール ---
ssh_ports=22                     # SSH 管理用ポート(緊急隔離時も維持)
allowed_ports=80,443             # 公開サービス用ポート
whitelist_ips=203.0.113.10/32    # 保守元 IP / CIDR(空 = 全許可、旧名 admin_source_ips 可)
protect_docker_ports=true        # DOCKER-USER 保護(コンテナの FW 迂回を阻止)
preserve_ssh_on_isolation=true   # 緊急隔離時も SSH 管理経路を温存(false で完全遮断)

# --- eBPF ランタイムガード ---
action_on_critical=isolate       # isolate | freeze(SIGSTOP+ネット遮断) | alert_only
ebpf_socket_path=/run/roamswitch/events.sock

# --- Egress / C2 遮断 & DNS シンクホール ---
egress_ip_blocklist_enabled=true # 既定 true。パッケージ同梱のシードには、JPCERT/CC が公表した攻撃用サーバー3件だけが入っています。ほかはフィードを入れるまで何もブロックしません
metadata_watch_enabled=true      # 既定 true。root 以外のプログラム/コンテナがクラウドのメタデータへ接続したら通知(記録のみ・遮断しない。SSRF の検知)
metadata_watch_allow_users=      # メタデータを正規に使うアカウント(名前または数値ID、カンマ区切り。root は常に対象外)
dns_sinkhole_enabled=false       # 既定 false(社内DNS/split-horizon環境を壊さないため)
dns_sinkhole_provider=quad9      # quad9 | cloudflare | adguard | cleanbrowsing

# --- コンテナ隔離CVEデータ(既定で有効) ---
cve_kernel_map_updates_enabled=true # 既定 true。既定で有効な唯一の外部通信(署名付きのカーネル CVE データ、Web ルール、Ubuntu サーバーでは Ubuntu のパッケージ CVE データを、マニフェストは毎日・CVE データ本体は約30日に1回、匿名・受信のみ・署名検証で取得)。false で止まる

# --- 通知 ---
telegram_enabled=false
telegram_bot_token=
telegram_chat_id=
line_enabled=false
webhook_enabled=false
webhook_url=
webhook_block_private_addresses=false   # opt-in SSRF guard
webhook_allow_addresses=

# --- システム ---
language=ja
fim_check_interval_secs=300      # 旧名 scan_interval 可
isolation_hard_cap_secs=3600     # 高信頼度の隔離が縮退モードに移るまでの秒数(0 = 解除まで維持)

設定を直接編集した場合は、サービスを再起動して反映します(roamswitch-server は reload 非対応):

sudo roamswitch server restart

4.1 重大度別ポリシー(guard.yaml、任意設定)

action_on_critical だけでは足りない、より細かい制御が必要な場合は /etc/roamswitch/guard.yaml(配布テンプレート /etc/roamswitch/guard.yaml.example)を作成します。存在しない場合は server.conf の action_on_critical から自動的に等価なポリシーが合成されるため、既存の運用に影響はありません。

policies:
  on_warning:
    action: log_and_notify
  on_critical:
    server_action: isolate_process
    kill_process: true
    fallback_to_host_isolation_after_retries: 3   # 同一プロセスが再発したらホスト隔離へ自動昇格
  on_emergency:
    action: isolate_host_all
    kill_process: true

server_safeguards:
  maintenance_ssh_ports: [22]
  safety_timer_secs: 300   # 低信頼度の隔離を自動復帰させるまでの秒数(0で無効化)。高信頼度の隔離には適用されない(下記)

隔離の自動解除(信頼度別): 固定タイマーだけで解除すると、待つだけの攻撃者に突破されてしまいます。そのため、隔離のトリガーを信頼度で分類します。(1) 低信頼度(eBPF の Error / Warning 以下、汎用のポート異常など): 短いタイマー(safety_timer_secs、既定300秒)の後に全復旧します。(2) 高信頼度(カナリア改ざん、ランサムウェア的な大量書き換え、eBPF の Critical / Emergency / Alert、同一ルールの繰り返しエスカレーション): 黙って復旧しません。短いタイマー以降は原因の再確認を続け、原因の消滅を確認できたときだけ通知付きで解除します。確認できないまま ack もなく上限(server.conf の isolation_hard_cap_secs、既定3600秒、0 = 上限なし)に達すると、縮退(DEGRADED)モードへ移ります。(3) 縮退モード: 保守 SSH ポートとホワイトリスト IP の管理経路以外の新規通信は遮断したままで、時間経過では絶対に自動で開きません。解除は、原因消滅の再確認、明示的な ack(縮退中の ack は解除を意味します)、または sudo roamswitch emergency-restore だけです。どの隔離でも、管理経路(maintenance_ssh_ports と whitelist_ips)以外の確立済み接続(攻撃者がすでに張っている C2 やリバースシェルなど)は遮断されます。各遷移はインシデントタイムラインに記録され、10言語で通知されます。

sudo roamswitch server ack

roamswitch server ack は、FULL 隔離中は隔離を厳格なまま維持して確認応答し(運用者が引き取ったものとして、縮退への移行や自動解除を止めます)、縮退中は解除します。

4.2 Egress / C2 遮断 と DNS シンクホール

egress_ip_blocklist_enabled=true(既定)で、既知の悪性IPへの発信を nftables でブロックします。フィードは /var/lib/roamswitch/threatfeed/malicious_ips.txt(更新機構が管理)があればそれを使い、無ければパッケージ同梱のシード(/usr/share/roamswitch/threatfeed/)を使います(2つを合わせるのではなく、どちらか一方です)。シードに入っているのは、JPCERT/CC が2026年10月15日の報告(Web・API を狙う攻撃)で公表した攻撃用サーバーの3つのアドレス(210.149.87.120・118.26.36.16・69.10.51.162)だけです。貸しサーバーのアドレスは別の人に割り当て直されることがあるため、正規の通信先が止まったときは、このファイルの該当行を確認してください。

dns_sinkhole_enabled=true にすると、フィルタリング DNS リゾルバ(Quad9 / Cloudflare / AdGuard / CleanBrowsing)へ強制的に振り向け、既知の悪性ドメイン解決をブロックします。社内 DNS や split-horizon 構成を壊す可能性があるため既定は false です。

metadata_watch_enabled が有効(既定)なら、nftables テーブル inet roamswitch_metadata_watch が、root 以外のプログラムまたはコンテナがクラウドのメタデータのアドレス(169.254.169.254、169.254.170.2、100.100.100.200、fd00:ec2::254)へ新しく接続したときだけカーネルログに記録し、サーバーデーモンがアカウント(コンテナは送信元アドレス)ごとに 1 日 1 回通知します。記録と通知だけで、通信は遮断しません。攻撃者が自分のサーバーの URL(302 で内部アドレスへ転送する)を渡す手口では、アクセスログには外部 URL しか残らないため、2 段目の接続を見られるのはこの外向き通信だけです。クラウドの権限(ロール)を正規に使うアプリでも通知されるため、metadata_watch_allow_users にアカウント名を入れて除外できます(コンテナは除外不可)。

4.3 着信ポートスキャン検知ガード

短時間に多数の異なるポートへ接続してきた送信元 IP を、nftables のログルールと journald の突き合わせで検知します(既定で有効)。確度が高いスキャン元は一定時間、自動的に遮断できます。RoamSwitch Sensor(§10.1 とは別機能。ペアリング済み Sensor による全ポート監査プローブは誤検知対策として除外されます)と併用する場合、Sensor 側の IP は自動的に対象外となります。

# --- 着信ポートスキャン検知(既定で有効) ---
port_scan_detect_enabled=true              # false で無効化
port_scan_detect_min_distinct_ports=15     # この数以上の異なるポートへの接続でスキャンと判定
port_scan_detect_window_secs=300           # 判定の集計ウィンドウ(秒)
port_scan_block_enabled=true               # 検知したスキャン元IPの自動遮断
port_scan_block_duration_secs=600          # 自動遮断の継続時間(秒)

検知履歴は roamswitch port-scan コマンドで確認できます。

4.4 DNS トンネリング検知ガード

自ホストが送信する DNS トラフィック(UDP/TCP の 53 番ポート)のみを対象に、専用の NFQUEUE 経由で検査します。ラベル長が 40 バイトを超える、シャノンエントロピーが 3.8 を超える、または TXT/NULL レコードの qtype のいずれかに該当する問い合わせを「疑わしい形状」とみなし、直近 60 秒間に 10 件を超えて検知した場合にのみ通知します(同一条件での再通知は 300 秒のクールダウンを設けます)。iodine・dnscat2 など DNS トンネリング/情報持ち出しツールに特徴的な問い合わせパターンの検知が目的です。裏側の nftables ルールには他の DNS 系ガードと同じ bypass フラグが付いており、本ガードが停止・無応答であっても DNS 名前解決が妨げられることは一切ありません。通知専用機能で、自動的な遮断は行いません。他の設定キーと同様、dns_tunnel_detect_enabled の変更はサービス再起動後に反映されます。

# --- DNSトンネリング検知(既定で有効) ---
dns_tunnel_detect_enabled=true              # false で無効化

4.5 SSH 総当たりガード

sshd のログイン失敗を、ログに書かれた瞬間に読み、接続元ごとに数えます(既定で有効)。設定した回数(既定は 600 秒に 6 回)に達した接続元は、nftables の inet roamswitch_sshguard テーブルで、SSH のポートへの新しい接続だけを落とします。最初の禁止は 1 時間で、同じ接続元が繰り返すたびに 4 倍に延び、上限は 7 日です。禁止と同時に、その接続元が SSH にすでに張っていた接続も切ります(接続の追跡エントリ(conntrack)を消し、応答方向のパケットを落とす規則を足して切ります)。禁止の対象は、認証済みのセッションも、公開鍵での成功の記録も、免除も持たない接続元だけで、切る直前にもう一度確かめます。したがって、認証済みのセッションと免除の接続元は切りません。外部への通信はしません(journalctl・nft・loginctl などをローカルで実行するだけです)。

ログは journalctl -f で流し読みします。journald は書き手のプロセスを記録するので、sshd 以外が書いた行は読みません。journald が無い環境では /var/log/auth.log か /var/log/secure を追尾しますが、これらのファイルは syslog を使えるローカルユーザーなら行を偽造でき、第三者を遮断させられるおそれがあります。journald がある環境では、ssh_guard_log_source を既定の auto のままにしてください。数える失敗は、パスワードの失敗、存在しないユーザー、ユーザー名を名乗ったあとの認証前の切断、試行回数の超過、PAM の認証失敗です。公開鍵の失敗(Failed publickey)は数えません。鍵を複数持つ正規のクライアントが、毎回出すためです。接続元のアドレスは、行の末尾にある from <IP> port <N> から読みます。ユーザー名には攻撃者が好きな文字列を入れられますが、そこに偽の接続元を書かれても、第三者は禁止されません。IPv6 は /64 にまとめて数え、禁止も /64 単位です(その /64 にゲートウェイなど守るべきアドレスが含まれるときは、接続元の 1 アドレスだけを禁止します)。

禁止しない相手は、ゲートウェイ、DNS リゾルバー、このサーバー自身、ループバック、whitelist_ips、ssh_guard_allow、認証に成功した SSH セッションがいま開いている接続元、過去 30 日(ssh_guard_trust_key_days)に公開鍵認証で成功した接続元(パスワードでの成功は数えません)、ペアリング済みの Sensor です。これらの接続元が失敗を重ねても、記録だけを残します。プライベートアドレスは免除しません。社内の侵害された端末も、総当たりの発信元になるためです。認証の前の接続が開いているだけの接続元も、免除しません。

fail2ban(sshd の jail が有効なとき)か CrowdSec(firewall bouncer が動いているとき)がすでに sshd を守っている場合は、二重に禁止しないよう、遮断を譲って検知と通知だけを行います(ssh_guard_yield_to_fail2ban、既定は true)。ssh_guard_block_enabled=false のときも、検知と通知だけです。通知するのは、禁止したとき(検知だけのときは、閾値に達したとき)と、失敗を重ねた接続元からログインに成功したとき(重大。ブルートフォースが成功した疑いがあります。セッションは切りません)に限ります。失敗 1 件ごとには通知せず、1 時間に 10 件を超える接続元は 1 通にまとめます。

禁止の一覧は roamswitch server bans(--json あり。一覧は root だけが読めるので sudo を付けます)、解除は sudo roamswitch server unban <IP | IPv6 の /64 | --all> です。解除すると、その接続元の失敗の回数も消えます。禁止は、サーバーを再起動したあとも、残り時間つきで復元されます。roamswitch emergency-restore は SSH の禁止を解除しません(ネットワークを戻すことは、パスワードを推測していた相手を戻す理由にならないためです)。回復メニュー(roamswitch recover)とアンインストールは、テーブルごと消します。MCP の get_ssh_guard_incidents は読み取り専用で、解除のツールはありません。Server TUI では、インシデント画面の「SSH 総当たり」で、禁止の一覧の確認と解除ができます(root で起動したとき。§17)。

roamswitch server bans
sudo roamswitch server unban 203.0.113.9
sudo roamswitch server unban --all

設定キーは 10 個で、すべて ssh_guard_ で始まります(§18.1)。たとえば sudo roamswitch server config set ssh_guard_max_failures 10 のように変更し、反映には sudo roamswitch server restart が必要です。ガード全体を止めるには ssh_guard_enabled=false、検知と通知だけにするには ssh_guard_block_enabled=false にします。診断(34 項目)の「SSH ブルートフォース防御」は、このガードが動いていて禁止する設定のときも合格になります。

限界: 公開鍵の失敗だけを重ねる試行は数えません。多数の接続元に分散した総当たりは、接続元ごとの回数で数えるため、1 つの接続元が閾値に達するまでは止まりません。根本的な対策は、パスワード認証を無効にして、公開鍵認証だけにすることです。

5. SSH 締め出し防止フェイルセーフ

リモートサーバーの運用で最も重大な事故は「ファイアウォール誤設定による SSH ロックアウト」です。RoamSwitch Server Edition は多重の防御策を備えています:

6. コンテナ保護 (Docker / Podman)

Docker は標準でコンテナのポート公開時(-p 8080:8080 等)に独自の iptables ルールを作成し、ホストの標準ファイアウォールをバイパス(貫通)して全世界へ直接ポートを露出させる既知の問題があります。

protect_docker_ports=true(既定)のとき、RoamSwitch は Docker のファイアウォール方式に合わせて、コンテナ宛てのトラフィックも ssh_ports と allowed_ports に含まれるポート宛て以外は外部から届かないようにします。iptables / iptables-nft 方式では DOCKER-USER チェーンの先頭に検査ルールを挿入します(IPv4 に加え、Docker の IPv6 が有効なら ip6tables でも)。Docker 29 以降のネイティブ nftables 方式(DOCKER-USER が存在しない)では、専用の inet roamswitch_docker_guard テーブルを Docker のチェーンより前の forward フックに作ります(1つの inet テーブルで IPv4 / IPv6 の両方を扱います)。判定は DNAT 前の元の宛先ポート(ctorigdstport)で行い、外部インターフェースからの通信だけを対象にするため、コンテナからの外向き通信やコンテナ間通信には影響しません。意図しない開発用データベースコンテナ等の外部露出を防ぎます。

このガードは冪等で、1分ごとに自己修復します。dockerd が RoamSwitch より後に起動した場合、Docker の再起動やリロードでルールが書き換えられた場合、手動の nft flush や nftables テーブルの消失があった場合にも、現在有効なガードには手を加えないまま再設定します。

あわせて、docker events を監視するリアルタイムガードが、--privileged で起動したコンテナや /var/run/docker.sock がマウントされたコンテナ(コンテナ脱出リスク)を起動直後に検知して通知します。さらにコンテナ exec ガード(container_exec_guard_enabled、既定オン)が、コンテナ内でのバイナリの実行を YARA で検査します(実行後にファイルを削除する回避も、開いたファイル記述子から内容を読むため検査できます)。このガードはすでに稼働中のコンテナにも起動時にマークを付け、新規コンテナにも自動で追随します。どちらも通知のみで、自動遮断は行いません。Docker 29 でも動きます(1.11.1 で対応)。イベントの購読が続けて失敗するときは、再接続の間隔を5秒から最大5分まで広げます。

7. クリティカルパス FIM (改ざん監視)

150 以上の重要ファイル(/bin/login, /usr/bin/sudo, /usr/sbin/sshd 等の重要バイナリ、/etc/shadow, /etc/sudoers 等の認証設定、systemd ユニット)を SHA-256 で監視します。

監視範囲は個別のファイルだけではありません。重要ディレクトリ(/etc/pam.d、/etc/sudoers.d、/etc/ssh/sshd_config.d、/etc/cron.*、/etc/systemd/system、/etc/ld.so.conf.d、/etc/profile.d、/root/.ssh(known_hosts を除く))では新しいファイルが現れたことも検知し、ログインできる全アカウントの authorized_keys、/etc/ld.so.preload(存在しないのが正常で、出現はローカルルートキットの兆候)、RoamSwitch 自身のバイナリも対象です。snapd が自動生成する一時ユニット(snap-*.mount 等)は対象外です。新規ファイル検知はこの範囲を含むベースラインでのみ有効になるため、アップグレード後は一度 sudo roamswitch fim update を実行してください。root 以外で fim verify を実行して読めないファイルは、改ざんではなく「読み取り不可としてスキップ」として扱います。

7.1 手動整合性検証

sudo roamswitch fim verify

7.2 イベント駆動検知(即時)

監視対象ファイルは fanotify(FAN_CLASS_NOTIF、書き込み完了イベント)で個別に監視されており、次回の周期スキャンを待たず、改ざんが発生した瞬間にハッシュを再照合します。周期スキャン(既定 fim_check_interval_secs=300 秒間隔)はイベントを取りこぼした場合のバックストップとして併存します。新しいファイルを同じ名前の下に置く編集(install・sed -i など)も検知します。通知には、変更したプロセスと SSH ログインを添えます(§7.5)。

7.3 OS パッケージ更新時の自動ベースライン同期

Debian / Ubuntu 環境では、パッケージインストール時に /etc/apt/apt.conf.d/99roamswitch-fim の DPkg::Post-Invoke フックが自動構成されます。Fedora / RHEL / Rocky / AlmaLinux / openSUSE では、/var/lib/rpm を監視する systemd.path ユニット(roamswitch-fim-update.path)が同等の役割を果たします。

これにより、管理者が sudo apt upgrade(または dnf upgrade / zypper update)を実行してバイナリが正規に更新された際は、RoamSwitch が自動で検知してハッシュベースラインを静かに再同期します(誤報アラートの発生を防止)。手動で更新を反映する場合は以下を実行します:

sudo roamswitch fim update

デーモンが初めて起動してベースラインを作るとき、パッケージ管理(apt・dpkg、dnf・rpm、zypper、pacman)が作業中であれば、終わるまで最大120秒待ってから作ります。Apache などと同じ apt install で導入しても、dpkg が作業中の一時ファイル(*.dpkg-new など)がベースラインに入り、直後の検証で改ざんに見えることはありません(1.11.18 以降)。120秒たっても終わらないときは、警告を記録して、そのまま作ります。

7.4 ハニートークン(認証情報デコイ)

デーモン起動時、root 権限で動作する特性を利用して /root 配下に .aws/credentials、.ssh/id_rsa、.docker/config.json の3種のおとり認証情報ファイル(ハニートークン)を冪等に配置します。該当パスに実ファイルが既に存在する場合は絶対に上書きしません。バックグラウンドの監視プロセスが inotify でこれらのファイルへの読み取りアクセスを検知すると、侵入後の認証情報探索(MITRE ATT&CK T1552: Unsecured Credentials)とみなし、重大度 Critical の通知とインシデントタイムライン記録を即座に行います。既定で有効で、設定キー honeytokens_enabled(false にすると配置と監視を止めます。すでに置いたおとりは残ります)と honeytokens_home(配置先。既定は /root)で変えられます。1.10.4 までの配布パッケージには、この機能の実行に必要な roamswitch-honeytokens が同梱されておらず、パッケージから入れた環境では動作していませんでした。1.10.5 から同梱され、サーバー版で systemd のサンドボックスが /root への書き込みを止めていた問題は 1.10.10 で直りました。1.11.1 から、RoamSwitch 自身が実行する docker のコマンドは、空の専用ディレクトリ(root では /run/roamswitch/docker-config)を DOCKER_CONFIG に指定して起動するため、おとりの .docker/config.json には反応しません(それまでは、デーモンの監視や roamswitch status --server が、おとりを読んで誤って検知することがありました)。ほかのプログラムが読めば、これまでどおり検知します。

いずれかのハニートークンに実アクセスがあった場合、攻撃者がさらに深く探索してくることを見越し、文脈的に関連する新規のおとり(例: .aws/credentials への到達後は .aws/config、.ssh/id_rsa への到達後は .ssh/config、.docker/config.json への到達後は .kube/config)を1トリガーあたり最大2件、全体で最大6件まで追加配置します。侵害調査中に /root 配下でこれらの見慣れないファイルが増えていても、これは想定内の挙動です。

7.5 侵入経路(誰が、どの SSH ログインから変更したか)

ファイルの変更を知らせる通知(クリティカルパス FIM とロックファイル FIM)に、変更したプロセス(アカウント・実行ファイル・コマンド)と、そのプロセスが属するSSH ログイン(接続元の IP とポート・ログイン時刻・認証方法・公開鍵の指紋)を添えます(既定で有効。fim_intrusion_context_enabled)。イベントを読んだその場で、書き込んだプロセスの /proc/<pid>(実行ファイル、ユーザー、loginuid、sessionid、cgroup、親の連鎖)を撮ります。tee や sed のように一瞬で終わるプロセスのためです。すでに終了していて撮れなかったプロセスは、実行レコーダー(有効なとき)の記録で補います。ログインへの結び付けは、SSH ガードのセッション表を先に使い、なければ logind と journald の Accepted の行から引きます。SSH ガードを無効にしていても動きます。外部には何も送りません。

信じるのは、カーネルが報告する値だけです。実行ファイルは /proc/<pid>/exe(argv[0] ではありません)、ログインは loginuid(ログイン時に一度だけ設定され、sudo や su を越えて引き継がれます)と cgroup の session-N.scope、それに親の連鎖です。comm・コマンドライン・環境変数のように、プロセス自身が変えられる値は、表示するだけで判定には使いません。sshd を名乗るだけのプロセスは、SSH のログインとは見なされません。通知は、次の三つを区別して書きます。見つかった(接続元・時刻・認証方法・鍵)、「SSH のログインは見つかりませんでした」(調べた結果、systemd のサービス、コンテナ、ローカルのログインセッション、ログインセッションに属さないプロセス、のどれかだったとき)、「ログインの経路は調べられませんでした」(プロセスがすでに無く実行レコーダーにも無い、logind が答えない、定期検査で見つけた変更でプロセスが分からない、など)。調べられなかったことを、ログインではないとは書きません。取得に失敗しても通知は必ず出ます。

/etc/ssh/sshd_config: modified
  プロセス: root(ログインしたアカウント: admin) / /usr/bin/tee / コマンド: tee /etc/ssh/sshd_config (pid 4121)
  SSH ログイン: 203.0.113.25:51544 から admin が 2026-10-17 03:12:08 にログインしたセッションです(認証: publickey, 鍵 SHA256:AbCdEf0123456789)

/etc/sudoers: modified
  ログインの経路は調べられませんでした(定期検査で見つけた変更のため、変更したプロセスは分かりません)

install・sed -i・同じディレクトリでの cp と mv のように、新しいファイルを同じ名前の下に置く編集も検知します。ファイル単位の印は inode に付くため、以前はこの種の編集でイベントが出ませんでした。いまは、監視対象のファイルがあるディレクトリにも印を付け、同じディレクトリで別の名前のファイルが閉じられると、数ミリ秒後に名前を引き直します。限界もあります。別のディレクトリで書いたファイルを mv で持ち込む場合は、周期スキャン(fim_check_interval_secs)が見つけるまで分かりません。そのときは書き込んだプロセスが分からず、通知にもそう書かれます。

記録は、通知のほかに、インシデントタイムライン(種別 fim)と /var/lib/roamswitch/fim_intrusions.json(root 専用、最新 100 件)に残ります。MCP の verify_fim には、追加のフィールド recentIntrusionContext として出ます(root で動かしたときだけ)。改ざんかどうかの判定は変わりません。限界もあります。実行レコーダーを無効にしていて、書き込んだプロセスが極端に短命なときは、実行ファイルが分からず、親プロセスの実行ファイルとコマンドラインを出します。持続化の監視(persistence_watch)の通知にはプロセスの情報がないので、侵入経路は付きません。侵入経路が示すのは、変更したプロセスとログインまでです。侵入の入口そのもの(突かれた脆弱性や、鍵が盗まれた経緯)は分かりません。止めるには fim_intrusion_context_enabled=false にします。

8. eBPF ランタイムガード & Falco / Tetragon 連携

カーネル空間で動作する eBPF プローブと連携し、カーネル特権昇格脆弱性(Frag Gap)やリバースシェル、コンテナ脱出を検知します。既定のセンサーは Falco(UNIX ドメインソケット経由の JSONL)です。guard.yaml の sensor.type: tetragon を選択すると、Cilium Tetragon をセンサーとして使うこともできます(Tetragon 側のネイティブ gRPC API を同じ UNIX ソケット越しに購読するのみで、新規リッスンポートは増えません)。

8.1 ログ肥大化・I/O 負荷の徹底排除

従来のセキュリティツールで問題となる「syslog の爆発的肥大化」「ディスク容量圧迫」を防ぐため、RoamSwitch は Falco と UNIX ドメインソケット /run/roamswitch/events.sock で直結します。このソケットは root 専用(0600)で作成され、書き込めるのは root で動く Falco だけです(追加の権限設定は不要です)。

8.2 自律リアクション(検知即プロセス凍結)

悪性コードの実行や不審通信を検知した瞬間、デーモンは該当プロセスの PID へ即座に SIGSTOP を発行して実行を凍結し、nftables ルールで通信を遮断(Air-Gap)します。

8.3 侵害証拠の自動保全(Forensic Evidence Capture)

eBPF ランタイムガードがプロセス単位の封じ込め(SIGSTOP による凍結 + ネットワーク遮断)を実行した際に、自動的に証拠保全バンドルを作成します(§4.1 の既定ポリシーでは Critical 相当のイベントがこの経路に該当します。ホスト全体を隔離する Emergency 相当のイベントでは、本バンドルは現時点では作成されません)。バンドルの内容は、既定のルーティングインターフェース上でのベストエフォートな約30秒間の境界付きパケットキャプチャ(tshark 未導入の環境ではこの項目のみ静かにスキップされ、その旨が記録されます)と、対象 PID が判明している場合の /proc/<pid> スナップショット(status、cmdline、maps、environ(KEY/TOKEN/SECRET/PASSWORD を含む名前の値は [REDACTED] に置換)、オープン中のファイルディスクリプタのリンク先一覧、PID 1 までの祖先プロセスチェーン)です。すべての取得済みファイルの SHA-256 ハッシュを記録した manifest.json が同梱され、後日の改ざん検証に利用できます。

保存先は /var/lib/roamswitch/incident-evidence/<タイムスタンプ>-<ID>/ です。バンドルは自動削除されません。ディスク圧迫を防ぐため、保持期間(既定 30 日)を超えた古いバンドルを明示的に削除するには次を実行します:

sudo roamswitch-incident-capture prune [--keep-days N]

また、封じ込めの発動を待たず、任意のタイミングで手動のスナップショットを取得することもできます:

sudo roamswitch-incident-capture snapshot [--pid PID] [--reason TEXT] [--json]

8.4 隔離の速さの計測と、警報経路のハートビート

eBPF による隔離の精度と速さは、センサー(Falco や Tetragon)のルールに左右されます。実際、Falco 0.45.0 の標準ルール(29 件)には、ホスト上のリバースシェルを検知するものがありません。リバースシェル向けのルールはコンテナ専用で、一部は RoamSwitch の priority: warning の条件で捨てられます。RoamSwitch は、ルールの出来を前提にせず、次の三つで補います。隔離にかかった時間を測ること、警報の経路が生きていることを定期的に確かめること、リバースシェルを自分でも検知することです。

隔離の遅延の計測として、eBPF のインシデントごとに、Falco が検知してからデーモンが警報を読むまで(detect_to_receive_ms)、読んでから対処が終わるまで(receive_to_action_ms。隔離の呼び出しが戻ったあとに測ります。ホスト Air-Gap は、ルールセットを読み込み終えるまで)、その合計(detect_to_action_ms)を記録します。値は ebpf_incidents.json と、MCP の get_ebpf_incidents に、追加のフィールドとして出ます。プロセスを隔離したときの通知には、「検知から対処まで N ミリ秒」の 1 行が付きます。実測(Ubuntu 24.04 の VM、Falco 0.45.0、modern eBPF)は、検知から受信まで 1〜2 ミリ秒、受信からプロセス隔離と SIGKILL まで 41〜62 ミリ秒(合計 42〜64 ミリ秒)、ホスト Air-Gap は合計 109 ミリ秒でした(目標の 150 ミリ秒の内側)。値はこの VM のものです。Tetragon は受信時に時刻を付けるので、detect_to_receive_ms はありません。

ハートビート(ebpf_heartbeat_interval_secs。既定は 600 秒、0 で無効、有効にするときは 60〜86400)は次のように働きます。パッケージには、RoamSwitch 自身の Falco ルール 96-roamswitch-heartbeat.yaml が入っています。デーモンは定期的に、root 専用の使い捨てのパス(/run/roamswitch/heartbeat/ の下の乱数)を開き、そのルールの警報が Falco の出力から戻ってくるまでを測ります。1 回の往復で、ルールが読み込まれていること、Falco が動いていること、出力の経路が生きていることを、まとめて確かめられます。戻らない確認が 2 回続いたとき(1 回目の 1 分後に再確認)だけ、「ルールが読み込まれていない、または出力が届いていない」という警告を、24 時間に 1 回まで通知します。ハートビートの行は、隔離・通知・許可リスト・インシデント記録のどれにも通さずに捨てます。外部には何も送りません。実測の往復は 2〜6 ミリ秒で、ルールを外すと約 164 秒後に警告が出て、戻すと約 75 秒で正常に戻りました。

状態は /var/lib/roamswitch/ebpf_heartbeat.json に残り、MCP の get_ebpf_incidents の heartbeat と、診断 K-04(eBPF ランタイムエージェント。診断の項目数は 34 のままです)が読みます。Falco が動いていても、ハートビートが戻らなければ K-04 は不合格です。限界もあります。確認するのは 1 つのルール(open 系のシステムコール)の往復で、ほかのルールが個別に壊れていることまでは分かりません。確認の間隔(既定は 10 分)のあいだに壊れたものは、次の確認まで分かりません。Tetragon では行いません。Falco が動いていない、またはルールのファイルが無いホストでは、何も確認せず、何も警告しません(停止は従来の通知が担当します)。Falco は確認のたびに警告を 1 行、syslog に書きます(既定なら 1 日 144 行)。

8.5 リバースシェル検知(RoamSwitch 自身)

Falco のルールに頼らず、RoamSwitch 自身が 2 秒ごとに /proc を読み、標準入力と標準出力が、このホストから外部のアドレスへ張った 1 本の TCP 接続につながっているシェル・インタプリタ(sh・bash・python・perl・ruby・php・node など)を探します。bash -i >& /dev/tcp/…、python、perl、nc -e、socat exec: が対象です。2 回続けて見えたものだけを、プロセスごとに 1 回報告します。既定は外部の公開アドレス宛だけで、プライベートアドレス宛(RFC 1918・CGNAT・リンクローカル)は reverse_shell_watch_include_private=true のときだけ数えます(ssh の ProxyCommand、コンテナ、ローカルの開発に正規のものが多いためです)。ループバックは見ません。外から受け付けた接続(inetd や socat TCP-LISTEN が accept したもの)も対象外です。実測(Ubuntu 24.04 の VM)では、bash の /dev/tcp、python、perl、nc -e、socat exec: を、接続から約 2.4 秒で検知しました。ssh、ProxyCommand 付きの ssh、git over ssh、nc のクライアントは検知しません。

検知は、RoamSwitch Reverse Shell という Critical の eBPF イベントとして、Falco の警報と同じ経路(許可リスト、通知のクールダウン、guard.yaml の重大度ごとの動作、インシデント記録)に入ります。既定では、プロセスの隔離と終了(kill)を行います。root が所有するリバースシェルは、プロセス単位の隔離に失敗するため、既存の Critical の方針どおり、ホスト全体の Air-Gap まで進みます。正規のプログラムが誤って検知されるのが心配なときの逃げ道は二つあります。reverse_shell_watch_notify_only=true(Warning として通知だけを行い、隔離も kill もしません。既定は false)と、許可リストへの登録 sudo roamswitch server allowlist add "RoamSwitch Reverse Shell" <プロセス名> です。設定キーは reverse_shell_watch_enabled(既定 true)、reverse_shell_watch_include_private(既定 false)、reverse_shell_watch_notify_only(既定 false)の 3 つです。

限界もあります。名前(プロセス名と実行ファイル名)で絞るので、シェルやインタプリタ以外の名前で、標準入出力をソケットにつないだ自作のバイナリは見つかりません。ループバック経由(ssh -R の折り返しなど)の接続と、2 秒より短い接続は見ません。ホストのプロセス空間から見えないプロセスも見られません。この検知は Server Edition だけの機能で、Mac と Linux クライアント版にはありません。

9. 緊急アラート通知 (Telegram / LINE / Webhook)

重大なインシデント(ポート不正露出、FIM 改ざん、eBPF 脅威検知、緊急隔離発動)が発生した際、外部の通知プラットフォームへ即座に状況を配信します。

[notifications]
language = ja
# Telegram: Bot Token と Chat ID
telegram_bot_token = "123456789:ABCdefGHIjklMNOpqrSTUvwxYZ"
telegram_chat_id = "-1001234567890"

# LINE: Messaging API チャネルアクセストークン と ユーザーID
line_channel_access_token = "YOUR_LINE_ACCESS_TOKEN"
line_user_id = "U1234567890abcdef1234567890abcdef"

# 汎用 Webhook (Slack, Discord, Teams, 自社監視基盤)
webhook_url = "https://hooks.slack.com/services/T00/B00/XXXXX"

これらの外部通知先を設定していない場合でも、送信された通知は直近1週間ぶんローカルに保持されます。roamswitch notificationsで確認できます。

Webhook 宛先の内部アドレス拒否(オプトイン): webhook_block_private_addresses=true(既定 false = 従来どおり)にすると、通知 Webhook の宛先が、ループバック・プライベート(10/8、172.16/12、192.168/16)・リンクローカル(169.254/16、クラウドのメタデータ 169.254.169.254 を含む)・ULA(fc00::/7)・CGNAT(100.64/10)のいずれか——ホスト名の場合は名前解決結果のうち 1 つでも該当——であれば送信を拒否し、理由をログと roamswitch notify-test のエラーに出します(2130706433 や 0x7f.1 のような別表記、IPv4-mapped IPv6 も判定)。検証した解決結果は curl に固定して接続するため DNS rebinding も防ぎます。社内 SIEM など正当な内部宛先は webhook_allow_addresses=10.20.0.0/16,fd00::/8(CIDR のカンマ区切り)で許可します。イベント転送の Webhook には同じ仕組みの forward_webhook_block_private_addresses / forward_webhook_allow_addresses があります。このオプションが false でも、宛先がクラウドのメタデータアドレスなら警告ログを出します(送信は止めません)。HTTP プロキシ環境変数が設定されている場合、名前解決と接続はプロキシ側で行われるため、この検査の対象外です。

10. AI エージェント / MCP 連携運用

RoamSwitch Server Edition は、Claude、Gemini、Cursor 等の AI エージェントからサーバーのセキュリティ診断を実行できる roamswitch-mcp(Model Context Protocol サーバー)を標準内蔵しています。

堅牢な読み取り専用設計(Read-Only 原則)
Web アプリケーション等のログに悪意あるプロンプトインジェクションが含まれていた場合でも、AI エージェントが悪用されて勝手にファイアウォールを開放したり隔離を解除したりできないよう、MCP 経由のツールは状態取得・監査ツール(Read-Only)のみに限定されています。ポリシー変更やプロセス凍結解除はローカル TTY(SSH 端末)での明示的コマンド実行を必須としています。

設定例(Claude Desktop / AI クライアント)

{
  "mcpServers": {
    "roamswitch": {
      "command": "/usr/bin/roamswitch-mcp",
      "args": []
    }
  }
}

10.1 調査エージェント連携(investigation、一次自動調査のAIエージェント委任)

§10 の roamswitch-mcp が「人間の AI クライアントからの問い合わせ」向けなのに対し、investigation 連携はデーモン自身が検知イベントをきっかけに外部 AI エージェント CLI を自律的に起動する、別の仕組みです。対象は、通知のみ判定(自動隔離・凍結に至らなかった)の eBPF 重大イベント、およびクリティカルパス FIM・依存関係ロックファイルの改ざん検知です。有効化すると、デーモンはローカルのヒューリスティックによる一次判定レポート(誤検知らしさ・根拠・次の調査ステップ)を生成した上で、そのレポートを添えて設定済みの AI エージェント CLI をサブプロセスとして起動し、追加調査と要約を委任します。既定は無効です。

# /etc/roamswitch/guard.yaml に追記(server.conf とは別ファイル)
investigation:
  enabled: true
  command: "claude"                 # "claude" | "agy" | "codex" | "opencode" | 任意のカスタムコマンド
  args: ["-p"]                      # プロンプトは自動的に末尾の引数として追加される
  timeout_secs: 180

sudo roamswitch server setup の対話式ウィザード(§3.2 最終ステップ)からも同じ内容を設定できます。ツールは Claude Code(claude -p)/ agy(agy -p --dangerously-skip-permissions)/ Codex CLI(codex exec)/ OpenCode(opencode run)のプリセット、または任意のカスタムコマンドから選択します。再実行時は保存済みの設定から該当するプリセットが自動選択されます。

プロンプトインジェクションへの注意
investigation 連携は、検知イベントの詳細(プロセス名・ファイルパス等、攻撃者が部分的に制御しうる文字列を含みうる)を、長さを切り詰めた JSON の文字列として、AIエージェントへのプロンプトに渡します。JSON の文字列にすることで、改行や引用符を使って、区切り線や偽の指示欄を作れないようにしています。ただし、文字列の中身が指示として読まれる可能性は、なくなりません。そのため、エージェントは root では実行できません。run_as に一般ユーザーを指定しない設定は、ウィザード(CLI と TUI)が保存せず、デーモンも起動しません。特に --dangerously-skip-permissions 等の権限確認を省略するモードでツールを起動する設定は、悪意ある入力によってエージェントが意図しない操作を行うリスクを高めます。ウィザードは agy 選択時にこの注意を表示します。信頼できないログ入力経路を持つ環境では、権限確認を省略しないツール設定を推奨します。

ネットワーク遮断中(Air-Gap 発動時など、isolate_host_all 相当の状態)は investigation 連携は呼び出されません。

11. CLI コマンド早見表

コマンド 必要権限 機能概要
sudo roamswitch status --server root 34項目のサーバーセキュリティ診断スコアとステータスを表示(--json で同じ内容を JSON で出力)
sudo roamswitch ports root 現在外部露出しているポートおよびバインドプロセスの一覧
sudo roamswitch fim verify root クリティカルパス重要ファイルの SHA-256 整合性検査
roamswitch notifications 一般 直近1週間の通知履歴(送信済みの全アラート)を表示(--json / --export ファイル にも対応)
sudo roamswitch server setup root 対話型の初期セットアップウィザードを実行
sudo roamswitch fim update root 現在のファイル状態を元に FIM ベースライン DB を再生成
sudo roamswitch server config set <key> <値> root 設定キーを 1 つ変更して保存(一覧は §18)
sudo roamswitch emergency-restore root eBPF・ファイアウォールの緊急隔離を全解除し、初期ベースラインへ復帰
roamswitch port-scan 一般 着信ポートスキャン検知ガード(§4.3)の検知履歴(送信元IP、自動遮断の有無・継続時間)を表示
roamswitch sensor [key|list|pair|repin|unpair|request-audit|results] 一般/root RoamSwitch Sensor とのペアリングコード方式による相互信頼。pair --addr <IP> --code <コード> --fingerprint <SHA-256>でペアリング(フィンガープリントはSensorの画面に表示される値)、repinでSensorの証明書再生成後にピンを更新、request-auditで能動的脆弱性監査をリクエスト(結果はresultsで取得)。sensor_pairing_enabled: true(既定 OFF)が必要。詳細は Sensor 運用マニュアル を参照
roamswitch server tui 一般/root 全機能を操作できる TUI を起動(一般ユーザーは読み取り専用、root で全操作。§17)
sudo roamswitch server ack root 現在の緊急隔離を確認応答(FULL 隔離中は厳格な隔離を維持し、縮退中は解除。§4.1)
roamswitch server ebpf 一般 eBPF ランタイムガードの現在の隔離状態と検知済みインシデント履歴を表示
roamswitch server bans [--json] 一般/root SSH 総当たりガード(§4.5)の状態と、いま禁止している接続元(残り時間つき)を表示。--json あり。禁止の一覧は root だけが読めます
sudo roamswitch server unban <IP | IPv6 /64 | --all> root SSH 総当たりガードの禁止を解除し、その接続元の失敗の回数も消します(IPv6 は /64 で指定、--all で全件)
sudo roamswitch server allowlist [list|add <rule> <process> [--exe <path>]|remove <rule> <process>] root 誤検知の恒久許可リストを管理。--exe を付けると実行ファイルのパスに紐づき、プロセス名の偽装では回避できません(名前だけの登録は偽装可能で、警告が表示されます)
roamswitch frozen [list|resume <PID>|resume all] 一般/root ガードが SIGSTOP で凍結中のプロセスの一覧と、誤検知だった場合の解除(SIGCONT)。resume all で全件解除
sudo roamswitch events search|tree|export|verify|status root 実行レコーダーの検索(--since 2h --pid --exe --user --parent --text --json)、プロセスツリー、エクスポート、ハッシュチェーンの検証、状態表示(§15)
sudo roamswitch forward status|test|queue root イベント転送の状態確認・テストイベントの送信・再送キューの表示(§16)
roamswitch timeline / notifications [--json] [--export FILE] 一般 統合インシデントタイムライン(実験的)/通知履歴の表示。--json で JSON 配列、--export ファイル で JSON Lines を出力
roamswitch audit-agent-setup [--json] 一般 AI エージェントに読ませる指示ファイル・スキルと OpenClaw の設定の危険な記述を、読み取り専用で点検(ホームフォルダーのみ。通信しない。--json で JSON)。Server TUI の「ツール」からも実行できる

12. トラブルシューティング & FAQ

Q1. SSH 接続が突然切断される可能性はありますか?

ありません。RoamSwitch は通常時、既知の ESTABLISHED/RELATED 接続ステートおよび ssh_ports(既定 22)を無条件に許可します。また、重大攻撃による Air-Gap 緊急隔離の発動時でも preserve_ssh_on_isolation=true(既定)により、保守 SSH ポートと管理元 IP の管理セッションは温存されます(それ以外の確立済み接続は遮断されます)。1.10.4 以前のサーバー版には、隔離用ルールが SSH の応答を落とし、隔離中は管理者の SSH が通らない不具合がありました。1.10.5 で修正しています。

Q2. 誤設定で自分自身がアクセス不能になった場合は?

クラウド事業者の Web 管理コンソール(VNC / シリアルコンソール)からログインし、sudo roamswitch emergency-restore で緊急隔離を解除するか、sudo systemctl stop roamswitch-server を実行してサービスを停止してください。

Q3. Nginx や Apache、Node.js などの Web サーバーを後から追加した場合は?

sudo roamswitch server config set allowed_ports 80,443,3000(または /etc/roamswitch/server.conf を直接編集)し、sudo roamswitch server restart を実行してください。

13. File Scan Guard (メール中継・共有フォルダ・アップロード先の保護)

メール中継、Samba/NFS 共有、ファイルアップロード先など、他者に渡すファイルを保管するディレクトリがある場合のみ関係する任意機能です。組み込み YARA エンジンは外部依存なしで clamav_scan_dirs を常時スキャンし、clamav_enabled=true にすると ClamAV によるセカンドオピニオンも追加されます。確認された脅威は自動的に /var/lib/roamswitch/quarantine へ隔離され、運用者に通知されます。

# --- File Scan Guard (ClamAV, オプトイン) ---
# 組み込みYARAは常時、clamav_scan_dirs を無条件でスキャンします。
clamav_enabled=false             # true で clamdscan による追加検査を有効化
clamav_scan_dirs=                # スキャン対象の絶対パス(カンマ区切り)
clamav_scan_interval_secs=86400  # スキャン間隔(秒、最小 3600)
clamav_freshclam_interval_secs=7200  # シグネチャDB自動更新間隔(秒、最小 1800)

対話式ウィザード sudo roamswitch server setup からも設定でき、get_file_scan_guard_status MCP ツールから設定・隔離状況を確認できます。

14. Log Audit (ログパターンの異常検知・通知)

journalctl の定期スキャンにより、ログメッセージをテンプレート化して新規パターン(過去に見られなかったログ形式)と頻度異常(統計的なスパイク、Z-score > 3.0)を検知します。追加のデーモンや外部依存を必要としない軽量な仕組みのため、既定で有効です。検出時は File Scan Guard や FIM と同じ通知チャネル(Telegram / LINE / Webhook)へ通知されます。ログに含まれる可能性のあるAPIキーやトークンは、通知本文へ渡す前に自動的にマスキングされます。

# --- Log Audit (既定で有効) ---
log_audit_enabled=true           # false で無効化
log_audit_interval_secs=1800     # スキャン間隔(秒、最小 300)

対話式ウィザード sudo roamswitch server setup からも設定でき、roamswitch audit-logs CLI コマンドまたは audit_security_logs MCP ツールから最新の検知結果を確認できます。

アクセスログの診断ツール AccessScope(別ツール): Server Edition の deb / rpm には、Web サーバと SSH のアクセスログを診断する別ツールのコマンド accessscope が同梱されます(画面アプリは入りません)。読み取り専用で、解析には LLM もネットワークも使いません。LLM による分析は任意で、既定はオフです(有効にしたときは、root でも実行できますが、LLM が root の権限で動くので、権限のないユーザーでの実行をお勧めします)。accessscope scan --auto でこのホストのログを診断し、accessscope discover でログの場所を一覧にします。詳細は AccessScope のページをご覧ください。

15. 実行レコーダー & 相関ルール(ローカル、通知専用)

プロセスの実行(exec)を、netlink の proc connector で記録します(実行ファイル・引数・親プロセスの系譜・UID・cwd・コンテナID・SHA-256)。既定でオンで、記録はこのホストの root 専用ディレクトリ /var/lib/roamswitch/exec_log に、ハッシュチェーン付きのセグメント化 JSON Lines(0600、既定 200 MB / 14 日)として保存され、外部へは送信されません。改ざんを検知できる(events verify)もので、改ざんを防止するものではありません。proc connector を開けない場合は、低頻度の /proc 走査に縮退します。記録処理は fanotify の許可イベントループとは別スレッドで動き、自身の CPU 使用率を予算(既定 3%)内に抑えます。

ローカルで検索・エクスポートします(root 専用ログのため通常 sudo が必要です)。

sudo roamswitch events status
sudo roamswitch events search --since 2h --exe curl
sudo roamswitch events tree 4242
sudo roamswitch events export --since 1d > exec-events.jsonl
sudo roamswitch events verify

相関ルール EXR-001〜007(通知専用・MITRE ATT&CK 技術ID付き): EXR-001 Web サービスから起動されたシェル / EXR-002 /tmp・削除済み・memfd からの実行 / EXR-003 ダウンロード直後の実行 / EXR-004 base64・eval を使うインタプリタのワンライナー / EXR-005 setuid 由来でない uid 0 の取得 / EXR-006 cron・systemd が直前に配置したバイナリの実行 / EXR-007 ld.so.preload 変更後の実行。各ルールは静かな既定値で、単独では隔離しません。exec_rules_disabled(例 EXR-003,EXR-004)で個別に無効化し、exec_rule_service_users で EXR-001 の対象ユーザーを調整できます。

exec_rules_isolation_optin(既定 false)を明示的に true にした場合に限り、重大度の高いルールが高信頼度の隔離トリガーとして扱われます(§4.1)。既定では、ルールは通知するだけです。読み取り専用の MCP ツール search_exec_events / get_process_tree からも参照できます。

16. イベント転送(SIEM / syslog / Webhook、オプトイン)

検知イベントを、運用者が指定した自組織の宛先へ転送できます。既定はオフで、forward_enabled=true にして宛先を1つ以上設定するまで何も送信されず、ベンダーの宛先は組み込まれていません。転送対象はインシデントタイムライン・通知履歴・eBPF ガード・隔離の状態遷移・FIM・カナリア・exec ルールのアラートで、exec の生ログ自体は転送しません。宛先は次の3種類です。

送れなかったイベント(TCP / TLS / Webhook)はディスクの再送キュー(0600、forward_queue_max_mb 既定20 と forward_queue_max_age_hours 既定72 で上限)に積まれ、再起動後も指数バックオフで再送されます。forward_min_severity(既定 low)で送る重大度の下限を設定できます。ホットパスを止めないよう、送信は専用スレッドで行い、キューが溢れた場合は最古のものから破棄します。

状態確認・疎通テスト・再送キューの確認は次のコマンドで行います(設定を変えたらサービスを再起動してください)。

# /etc/roamswitch/server.conf
forward_enabled=true
forward_syslog_url=tls://siem.example.org:6514
forward_syslog_format=rfc5424
forward_tls_ca_file=/etc/ssl/certs/corp-ca.pem
forward_min_severity=medium

sudo roamswitch server restart
sudo roamswitch forward status
sudo roamswitch forward test
sudo roamswitch forward queue

17. Server TUI(全機能を操作できるターミナルUI)

roamswitch-server-tui(roamswitch server tui でも起動)は、CLI の動詞と 2 つの設定ファイル(server.conf と guard.yaml)に散らばる Server Edition のすべての機能を、SSH 越しのキーボード操作だけで扱える TUI です(80x24 で動作、10言語)。CLI の動詞または設定キーが増えたのに TUI に対応物がない状態は、開発時のテストで失敗するようになっています。

起動:

sudo roamswitch-server-tui    # full control
roamswitch-server-tui         # read-only
roamswitch server tui         # same as roamswitch-server-tui

18. 設定キー一覧(server.conf / guard.yaml)

roamswitch-server は設定の再読み込み(reload)に対応していません。すべてのキーの反映にはサービスの再起動が必要です(sudo roamswitch server restart)。server.conf の各キーは roamswitch server config set <キー> <値> または §17 のエディタで変更できます。guard.yaml はエディタか手動編集で変更します。

18.1 server.conf(109 キー)

キー 型 / 取り得る値 既定 再起動
languagesystem | ja | en | zh-hans | zh-hant | ko | de | fr | es | it | ptja要
ssh_portsport list22要
allowed_portsport list80,443要
whitelist_ipslist—要
preserve_ssh_on_isolationbooltrue要
telegram_enabledboolfalse要
telegram_bot_tokenstring—要
telegram_chat_idstring—要
line_enabledboolfalse要
line_channel_access_tokenstring—要
line_user_idstring—要
webhook_enabledboolfalse要
webhook_urlURL—要
webhook_block_private_addressesboolfalse要
webhook_allow_addressesCIDR list—要
action_on_criticalisolate | freeze | alert_onlyisolate要
ebpf_socket_pathabs path/run/roamswitch/events.sock要
ebpf_heartbeat_interval_secs0 (off) | int 60–86400600要
isolation_hard_cap_secsint ≥ 03600要
fim_check_interval_secsint ≥ 10300要
fim_intrusion_context_enabledbooltrue要
protect_docker_portsbooltrue要
dns_sinkhole_enabledboolfalse要
dns_sinkhole_providerquad9 | cloudflare | adguard | cleanbrowsingquad9要
egress_ip_blocklist_enabledbooltrue要
metadata_watch_enabledbooltrue要
metadata_watch_allow_userslist—要
cve_kernel_map_updates_enabledbooltrue要
clamav_enabledboolfalse要
clamav_scan_dirsabs path list—要
clamav_scan_interval_secsint ≥ 360086400要
clamav_freshclam_interval_secsint ≥ 18007200要
lockfile_watch_dirsabs path list—要
npm_audit_signatures_enabledboolfalse要
log_audit_enabledbooltrue要
log_audit_interval_secsint ≥ 3001800要
resource_guard_enabledbooltrue要
resource_guard_rss_sample_interval_secsint ≥ 1060要
resource_guard_rss_window_secsint ≥ 3001800要
resource_guard_rss_min_samplesint ≥ 310要
resource_guard_rss_min_growth_pctint ≥ 1050要
resource_guard_rss_recovery_drop_pctint ≥ 110要
resource_guard_rss_min_kbint ≥ 020000要
resource_guard_crash_loop_window_secsint ≥ 60300要
resource_guard_crash_loop_min_restartsint ≥ 23要
resource_guard_correlation_window_secsint ≥ 60600要
resource_guard_zombie_min_countint ≥ 020要
resource_guard_load_min_normalizedfloat ≥ 0.00.5要
resource_guard_load_enabledbooltrue要
resource_guard_cpu_enabledbooltrue要
resource_guard_cpu_sample_interval_secsint ≥ 060要
resource_guard_cpu_window_secsint ≥ 0600要
resource_guard_cpu_min_samplesint ≥ 08要
resource_guard_cpu_pct_thresholdfloat 0.0–1000.080.0要
container_exec_guard_enabledbooltrue要
port_scan_detect_enabledbooltrue要
port_scan_detect_min_distinct_portsint ≥ 015要
port_scan_detect_window_secsint ≥ 0300要
port_scan_block_enabledbooltrue要
port_scan_block_duration_secsint ≥ 0600要
ssh_guard_enabledbooltrue要
ssh_guard_block_enabledbooltrue要
ssh_guard_max_failuresint 2–10006要
ssh_guard_window_secsint 10–86400600要
ssh_guard_ban_secsint 60–25920003600要
ssh_guard_ban_max_secsint 60–31536000604800要
ssh_guard_allowIP/CIDR list—要
ssh_guard_log_sourceauto | journal | abs pathauto要
ssh_guard_yield_to_fail2banbooltrue要
ssh_guard_trust_key_daysint 0–365030要
dns_tunnel_detect_enabledbooltrue要
reverse_shell_watch_enabledbooltrue要
reverse_shell_watch_include_privateboolfalse要
reverse_shell_watch_notify_onlyboolfalse要
sensor_pairing_enabledboolfalse要
sensor_colocatedboolfalse要
forward_enabledboolfalse要
forward_syslog_urlURL—要
forward_syslog_formatrfc5424 | cefrfc5424要
forward_syslog_framingoctet | lfoctet要
forward_tls_ca_fileabs path—要
forward_file_pathabs path—要
forward_file_max_mbint 1–1000050要
forward_file_keepint 1–1005要
forward_webhook_urlURL—要
forward_webhook_secretstring—要
forward_webhook_secret_fileabs path—要
forward_webhook_block_private_addressesboolfalse要
forward_webhook_allow_addressesCIDR list—要
forward_min_severityinfo | low | medium | high | criticallow要
forward_queue_max_mbint 1–1000020要
forward_queue_max_age_hoursint 1–876072要
exec_recorder_enabledbooltrue要
exec_recorder_retention_mbint 1–100000200要
exec_recorder_retention_daysint 1–365014要
exec_recorder_hash_chainbooltrue要
exec_recorder_hash_exebooltrue要
exec_recorder_cpu_budget_pctint 1–503要
exec_rules_enabledbooltrue要
exec_rules_disabledstring—要
exec_rule_service_usersstring—要
exec_rule_window_secsint 5–3600120要
exec_rules_isolation_optinboolfalse要
honeytokens_enabledbooltrue要
honeytokens_homeabs path/root要
harden_userns_enabledbooltrue要
dns_tunnel_entropy_allowlistlist—要
fleet_forwarding_allowed_hostslist—要
fleet_forwarding_allow_plaintextboolfalse要

18.2 guard.yaml(37 キー)

キー 型 / 取り得る値 既定 再起動
sensor.typefalco | tetragonfalco要
sensor.transportstringunix_socket要
sensor.socket_pathabs path/run/roamswitch/events.sock要
sensor.reconnect_interval_msint 100–36000001000要
policies.on_warning.actionlog_and_notify | isolate_process | isolate_host_alllog_and_notify要
policies.on_warning.server_actionlog_and_notify | isolate_process | isolate_host_all—要
policies.on_warning.kill_processboolfalse要
policies.on_warning.freeze_processboolfalse要
policies.on_warning.fallback_to_host_isolation_after_retriesint 0–1000—要
policies.on_error.actionlog_and_notify | isolate_process | isolate_host_allisolate_process要
policies.on_error.server_actionlog_and_notify | isolate_process | isolate_host_all—要
policies.on_error.kill_processboolfalse要
policies.on_error.freeze_processboolfalse要
policies.on_error.fallback_to_host_isolation_after_retriesint 0–1000—要
policies.on_critical.actionlog_and_notify | isolate_process | isolate_host_allisolate_process要
policies.on_critical.server_actionlog_and_notify | isolate_process | isolate_host_all—要
policies.on_critical.kill_processbooltrue要
policies.on_critical.freeze_processboolfalse要
policies.on_critical.fallback_to_host_isolation_after_retriesint 0–10003要
policies.on_emergency.actionlog_and_notify | isolate_process | isolate_host_allisolate_host_all要
policies.on_emergency.server_actionlog_and_notify | isolate_process | isolate_host_all—要
policies.on_emergency.kill_processbooltrue要
policies.on_emergency.freeze_processboolfalse要
policies.on_emergency.fallback_to_host_isolation_after_retriesint 0–1000—要
server_safeguards.allow_established_connectionsbooltrue要
server_safeguards.maintenance_ssh_portsport list22要
server_safeguards.whitelist_cidrslist—要
server_safeguards.whitelist_dns_serverslist—要
server_safeguards.safety_timer_secsint ≥ 0300要
adaptive_security.enabledbooltrue要
adaptive_security.untrusted_network_actions.elevate_falco_profilestring—要
adaptive_security.untrusted_network_actions.auto_enable_userns_restrictionboolfalse要
investigation.enabledboolfalse要
investigation.commandabs path—要
investigation.argslist—要
investigation.run_asstring—要
investigation.timeout_secsint 1–86400180要

19. Webシェル・注入コードの検知 (Web Rules)

Web サーバーで動く PHP・JavaScript・JSP・ASP の Web シェルや注入コード、画像に偽装した PHP、.htaccess の悪用を見つける機能です(Linux 1.11.23 以降)。設定は要りません。Apache・nginx・Caddy の設定からドキュメントルートを自動で見つけ、そこにファイルが書き込まれて閉じられた直後に検査します(通知専用の fanotify を使うため、ほかのプロセスを止めることはありません)。取りこぼしと、起動前からあるファイルのために、6 時間ごとの定期スキャンも行います。ClamAV は不要です。

動作は /etc/roamswitch/web_rules.conf(root 所有、権限 0644。他人が書き込めるファイルは無視されます)で決めます。変えたら sudo roamswitch server restart で反映します。雛形は roamswitch web-rules example conf で出せます。

キー意味(既定値)
quarantine自動で隔離する水準。off は隔離しない、critical は重大だけ、high は重大と高(既定: critical)。高を critical 水準で見つけたときは、通知とフックだけで、ファイルには触れません。
account_action検知したファイルの持ち主のログインシェルを無効にするか。off / revoke_shell(既定: off)。隔離できた重大・高だけが対象です。root、account_min_uid 未満、ログイン中のユーザー、デーモン自身には何もしません。元のシェルは記録され、sudo roamswitch web-rules unlock-account <ユーザー> で戻せます。
account_min_uidaccount_min_uid: アカウント対処の対象にする最小の UID(既定 1000、100 未満には下げられません)。
scan_dirs, auto_docroots, watch, scan_interval_secsscan_dirs(カンマ区切りの絶対パス)、auto_docroots(既定 true。false で、Web サーバー設定からの自動検出をやめる)、watch(既定 true。false で、書き込み監視をやめて定期スキャンだけにする)、scan_interval_secs(既定 21600、最小 3600)。
# /etc/roamswitch/web_rules.conf
quarantine=critical
account_action=off
account_min_uid=1000
#scan_dirs=/srv/sites/a,/srv/sites/b
auto_docroots=true
watch=true
scan_interval_secs=21600

検知すると、通知(Telegram・LINE・Webhook)が届きます。通知には、ルール名と、隔離したか、そのまま残したかが書かれます。確認だけで動かしたいときは、sudo roamswitch web-scan <フォルダー>(確認のみ。--quarantine で隔離)、または Server TUI の「ツール」画面を使います。独自ルールは /etc/roamswitch/rules.d/*.json、検知後に自分のスクリプトを呼ぶ場合は /etc/roamswitch/hooks/post-detection(検知の内容が JSON で標準入力に渡されます。root 所有で、他人が書き込めず、親ディレクトリも安全なものだけが実行されます。シェルは通らず、30 秒で打ち切られます)です。ルールの更新は、日次の受信専用アップデートに含まれます。cve_kernel_map_updates_enabled を無効にすると、通信は一切行われず、同梱のルールで動作します。

← サーバー版ホワイトペーパー Linux版導入ページへ →