#状況
apt list --upgradable に、新しいカーネルと openssh-server、sudo が並んでいます。手元からは SSH でしか入れません。更新の途中で接続が切れたら、RoamSwitch が何か知らせてきたら、どう判断しますか。
OS の更新は、重要なファイルをまとめて書き換えます。改ざんを見張る仕組みから見ると、攻撃とよく似た動きです。運用者が知りたいのは、次の3つです。更新のあいだ、保護は何を知らせ、何を知らせないか。接続が切れても更新を続けるにはどうするか。再起動のあと、保護が本当に戻ったかをどう確かめるか。
この講座は、使い捨ての VM の中で、カーネルを含む apt full-upgrade を SSH 越しに流して確かめる手順書です。
| 順番 | すること | 使うもの |
|---|---|---|
| 1. 用意する | 更新が届く状態と、外の作業場所を作る | 古いカーネル、ネットワーク名前空間、Falco |
| 2. 確かめる | 基準がきれいか、締め出されないかを見る | 重要システムファイルの改ざん監視、SSH 総当たりの検知と遮断、SSH の接続元の限定 |
| 3. 更新する | 接続が切れても続く形で流す | tmux、nc |
| 4. 読む | 通知と、通知に出ない変更を見る | 通知の履歴、dpkg -S、dpkg --verify |
| 5. 戻す | 再起動して、保護が働くことを確かめ、片付ける | カーネル層の侵入検知と自律隔離、SUID・SGID の変更の監視 |
RoamSwitch 自身を更新する手順と、アンインストールは、更新・脅威データ・アンインストール で扱いました。この講座は、OS の側を更新するときの運用です。
この講座は、カーネルを入れ替え、OS を再起動します。VM は tart exec でも操作できるので、SSH が使えない間も作業を続けられます。実機では、クラウドのコンソールのような、SSH 以外の入り口を先に確かめておきます。
#練習の場を用意する
この VM には、作ったあとに出た更新もいくつか届いています。練習のため、さらに1つ前のカーネル(7.0.0-38)で起動し、新しいカーネルと、openssh-server・sudo を古い版に戻します。どれもパッケージの操作だけで、RoamSwitch の設定は変えません。
カーネルと起動の設定を変える操作です(変更を伴う操作です)。起動の設定は、この演習の中で元に戻します。カーネルとパッケージは、このあとの更新で新しい版に戻ります。
1つ前のカーネルを入れ、次の起動で選ばれるようにして、再起動します。
sudo apt-get install -y linux-image-7.0.0-38-generic linux-modules-7.0.0-38-generic
sudo cp /etc/default/grub /etc/default/grub.lab-orig
sudo sed -i 's/^GRUB_DEFAULT=.*/GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 7.0.0-38-generic"/' /etc/default/grub
sudo update-grub
sudo systemctl reboot起動したら、カーネルの入口のパッケージを古い版に戻し、新しいカーネルを外します。起動の設定も元に戻します。
uname -r
sudo apt-get install -y --allow-downgrades linux-generic-hwe-24.04=6.8.0-31.31 linux-image-generic-hwe-24.04=6.8.0-31.31 linux-headers-generic-hwe-24.04=6.8.0-31.31
sudo apt-get purge -y linux-image-7.0.0-42-generic linux-modules-7.0.0-42-generic linux-headers-7.0.0-42-generic linux-hwe-7.0-headers-7.0.0-42 linux-hwe-7.0-tools-7.0.0-42 linux-tools-7.0.0-42-generic linux-main-modules-zfs-7.0.0-42-generic
sudo cp /etc/default/grub.lab-orig /etc/default/grub
sudo update-grub
sudo apt-get install -y --allow-downgrades openssh-server=1:9.6p1-3ubuntu13 openssh-client=1:9.6p1-3ubuntu13 openssh-sftp-server=1:9.6p1-3ubuntu13 sudo=1.9.15p5-3ubuntu5
apt list --upgradable 2>/dev/null | grep -c upgradable7.0.0-38-generic
5050 個のパッケージに、更新が届いている状態になりました。
カーネル層の侵入検知と自律隔離 が働くように、Falco を入れます。手順は 不審な実行とマルウェア と同じです。
curl -fsSL https://falco.org/repo/falcosecurity-packages.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/falco-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/falco-archive-keyring.gpg] https://download.falco.org/packages/deb stable main" \
| sudo tee /etc/apt/sources.list.d/falcosecurity.list
sudo apt-get update
sudo FALCO_FRONTEND=noninteractive FALCO_DRIVER_CHOICE=modern_ebpf apt-get install -y falco
sudo roamswitch status --server | grep -A1 "eBPF ランタイム" [合格] eBPF ランタイムセキュリティエージェント - 稼働中 (Falco/Tetragon連携)
準拠: CIS - / NIST CSF DE.CM-09最後に、外の作業場所を作ります。VM の中にネットワーク名前空間を作り、10.99.0.2 を手元の PC に見立てて、鍵で SSH します。鍵は、この場で作る練習用のものです。
sudo ip netns add outside
sudo ip link add veth-host type veth peer name veth-out
sudo ip link set veth-out netns outside
sudo ip addr add 10.99.0.1/24 dev veth-host
sudo ip link set veth-host up
sudo ip netns exec outside ip addr add 10.99.0.2/24 dev veth-out
sudo ip netns exec outside ip link set veth-out up
ssh-keygen -q -t ed25519 -N "" -C lab-dummy-key -f /var/tmp/lab_key
cat /var/tmp/lab_key.pub >> ~/.ssh/authorized_keys
K="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o ConnectTimeout=5 -o BatchMode=yes -o IdentitiesOnly=yes -i /var/tmp/lab_key"
R="sudo ip netns exec outside ssh $K admin@10.99.0.1"
$R 'echo ok from $SSH_CLIENT'ok from 10.99.0.2 45148 22ここから先の $R '…' は、手元の PC から SSH で打つコマンドに当たります。
#更新の前に確かめる
更新の前に見るものは、2種類です。改ざんの監視の基準がきれいか。更新のあいだ、自分が締め出されないか。
読むだけの操作です。最後の fim update だけが、基準を書き換えます(変更を伴う操作です)。
まず、改ざんの監視の基準と、いまのファイルを比べます。
$R 'sudo roamswitch fim verify' 🔍 最重要システムファイルの整合性を検証中... (91 件)
🚨 ファイルの変更・改ざんが検知されました!
[内容の変更] /home/admin/.ssh/authorized_keys
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)
正規のOS更新等による変更の場合は 'sudo roamswitch fim update' でベースラインを更新してください。authorized_keys は、前の演習で自分が鍵を足したファイルです。鍵を足したときに、改ざんの通知がその場で届き、書いたプロセスが残っています。自分の変更だと確かめたので、基準に取り込みます。
$R 'sudo roamswitch fim update; sudo roamswitch fim verify' 📝 現在のシステムファイルからベースラインDBを再作成中...
✓ ベースラインDBを正常に更新・署名保存しました。 (91 件記録)
✓ SUID / SGID ファイルの基準を更新しました。 (20 件記録)
🔍 最重要システムファイルの整合性を検証中... (91 件)
✓ 改ざんは検知されませんでした。すべて正常です。 (91 ファイルを監視中)
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)次に、SSH の入り口です。総当たりガード、接続元の許可リスト、待ち受けのポートを見ます。
$R 'sudo roamswitch bans | sed -n 5,10p'
$R 'sudo roamswitch ssh-allow status | sed -n 5,8p'
$R 'sudo roamswitch server config get ssh_ports; sudo ss -ltnpH | grep sshd' 状態 : 検知のみ(遮断しない)
理由 : fail2ban が SSH を防御しているため、遮断はそちらに任せています(ssh_guard_yield_to_fail2ban=true)。
ログ : journal
ポート : 22
遮断は fail2ban に任せています。SSH ガードが遮断しない接続元(開いている SSH のセッション、最近の公開鍵のログイン、ssh_guard_allow)は、fail2ban には伝わりません。自分の接続元は、fail2ban の ignoreip(/etc/fail2ban/jail.local)にも加えてください。fail2ban が遮断している接続元: sudo fail2ban-client status sshd
ssh_allow_only_enabled : false
ssh_allow_only_sources : -
デーモンの状態 : 無効
いま SSH でつながっている接続元: 10.99.0.2
22
LISTEN 0 4096 *:22 *:* users:(("sshd",pid=11610,fd=3),("systemd",pid=1,fd=67))遮断は fail2ban に任せていて、自分の接続元は、SSH ガードが遮断しない側に入っています。fail2ban の側でも締め出されないように、ignoreip に足すよう案内が出ます。許可リストは使っていません。ssh_ports と、sshd が待ち受けるポートは、どちらも 22 です。
最後に、自動の更新が重ならないかと、何が更新されるかを見ます。
$R 'systemctl list-timers --no-pager apt-daily-upgrade.timer apt-daily.timer roamswitch-update.timer'
$R 'sudo fuser -v /var/lib/dpkg/lock-frontend; echo fuser=$?'
$R 'apt-get -s full-upgrade | grep -E "^Inst (openssh-server|sudo) "; apt-get -s full-upgrade | grep -E "^Inst linux-image-7"; apt-get -s full-upgrade | grep -E "^[0-9]+ upgraded"'NEXT LEFT LAST PASSED UNIT ACTIVATES
Thu 2026-11-12 02:23:22 UTC 11min Tue 2026-11-03 16:25:55 UTC - apt-daily-upgrade.timer apt-daily-upgrade.service
Thu 2026-11-12 02:42:57 UTC 30min - - roamswitch-update.timer roamswitch-update.service
Thu 2026-11-12 11:03:04 UTC 8h Sat 2026-10-31 11:01:41 UTC - apt-daily.timer apt-daily.service
3 timers listed.
Pass --all to see loaded but inactive timers, too.
fuser=1
Inst openssh-server [1:9.6p1-3ubuntu13] (1:9.6p1-3ubuntu13.20 Ubuntu:24.04/noble-updates, Ubuntu:24.04/noble-security [arm64]) []
Inst sudo [1.9.15p5-3ubuntu5] (1.9.15p5-3ubuntu5.24.04.4 Ubuntu:24.04/noble-updates, Ubuntu:24.04/noble-security [arm64])
Inst linux-image-7.0.0-43-generic (7.0.0-43.43~24.04.1 Ubuntu:24.04/noble-updates [arm64])
47 upgraded, 13 newly installed, 0 to remove and 3 not upgraded.- apt-daily-upgrade.timer: 自動のセキュリティ更新(unattended-upgrades)の時刻です。次は 02:23 UTC(日本時間 11:23)、11 分後です。この VM では、更新は約 2 分で終わり、重なりませんでした。時間が足りないときは、その時刻のあとに始めます
- roamswitch-update.timer: RoamSwitch の署名つきデータの更新です。OS のパッケージは入れません
- fuser=1: いま dpkg の鍵を握っているプロセスはありません。0 なら、別の更新が動いています
- Inst の行: カーネル、sshd、sudo が入れ替わります
更新を始める前に決めます。更新は、パッケージのファイルを入れ替えます。改ざんされたファイルが同じ更新で入れ替わると、中身がパッケージの記録と一致して基準に入り、何が変わっていたかを確かめられなくなります。
- 自分の変更だと確かめられた:
sudo roamswitch fim updateで取り込んでから、更新します - 覚えのない変更がある: 更新を始めません。通知の履歴で、書いたプロセスと SSH のログインを確かめます。調べ終わるまで、基準も更新しません
- 何も出ない: そのまま更新します
締め出されたときの戻し方も、先に試しておきます。隔離が働いて SSH が止まったときは、コンソールから emergency-restore を使います。
ファイアウォールの規則を外す操作です(変更を伴う操作です)。最後の再起動で、規則を戻します。
SSH ではなく、コンソール(この VM では tart exec)で実行します。いまは何も隔離していないので、まずそのまま実行し、次に --force を付けて、規則を外す動きを確かめます。
sudo roamswitch emergency-restore
sudo roamswitch emergency-restore --force
$R 'echo ok from $SSH_CLIENT'
sudo nft list tables
sudo systemctl restart roamswitch-server
sleep 3
sudo nft list tables 隔離はされていません。隔離の規則も残っていないので、何も外していません。ポートスキャンの遮断や Web ガードの遮断も含めて、通信を止めうる規則をそれでも外すときは: sudo roamswitch emergency-restore --force
現在の状態:
隔離の記録はありません(残った規則は、ここで取り除きます)
🔄 緊急遮断・隔離ルールを全解除し、ベースラインへ復旧中...
✓ 隔離の記録
✓ 通信を止めうるファイアウォールのテーブル
✓ DNSの設定
✓ 接続の追跡
次のファイアウォールのテーブルは、隔離ではないので残しました:
- roamswitch_server: サーバーの受信の規則(ssh_ports・allowed_ports だけを通す、ふだんの防御)
✓ ネットワークを復旧しました。
ポートスキャンの検知など、ここで外した規則は、再起動まで戻りません。戻すには: sudo systemctl restart roamswitch-server
ok from 10.99.0.2 50448 22
table inet roamswitch_server
table inet roamswitch_metadata_watch
table inet roamswitch_egress_block
table inet roamswitch_dev_guard
table inet roamswitch_dnstunnel
table inet roamswitch_server
table inet roamswitch_metadata_watch
table inet roamswitch_egress_block
table inet roamswitch_dev_guard
table inet roamswitch_portscan
table inet roamswitch_dnstunnel隔離の記録も規則もないときは、何も外さずに終わります(終了コード 0)。--force を付けると、確認なしで、通信を止めうる規則を外します。ポートスキャンの規則 roamswitch_portscan が消え、サーバーの受信の規則 roamswitch_server は、隔離ではないので残りました。開いていた SSH は切れませんでした。解除のあとは、表示どおりに roamswitch-server を再起動して、保護の規則を戻します。隔離が働いているときは、--force を付けずに実行すると、隔離の範囲を表示して、y の確認のあとに外します。総当たりガードの遮断は、emergency-restore では解けません。その解き方は、SSH への総当たりと、自分が締め出されたとき にあります。
#接続が切れても続く形で更新する
SSH のセッションで直接 apt を動かすと、接続が切れたときに、そのセッションのコマンドも止まります。tmux の中で動かせば、切れても続きます。
パッケージを更新する操作です(変更を伴う操作です)。カーネルとパッケージは、元の版には戻しません。
更新を始める時刻を、ファイルに残します。あとで「更新のあいだに変わったもの」を探すときの目印です。手元の PC から、新しい接続を5秒おきに試す見張りも、別に動かします。
sudo touch /var/tmp/upgrade-start; date -u +%FT%T | sudo tee /var/tmp/T0
sudo ip netns exec outside setsid sh -c 'while :; do if nc -z -w2 10.99.0.1 22; then r=open; else r=refused; fi; echo "$(date -u +%T) $r"; sleep 5; done' >/var/tmp/probe.log 2>&1 < /dev/null &2026-11-12T02:14:31SSH で入り、tmux の中で更新を始めます。設定ファイルの質問で止まらないように、--force-confold で、いまの設定を残します。15 秒後に、手元の SSH を強制終了して、切断を起こします。
sudo ip netns exec outside ssh -tt $K admin@10.99.0.1 'TERM=xterm tmux new -s up "sudo DEBIAN_FRONTEND=noninteractive apt-get full-upgrade -y -o Dpkg::Options::=--force-confold 2>&1 | tee /var/tmp/upgrade.log"' </dev/null >/var/tmp/ssh-client.out 2>&1 &
C=$!
sleep 15
sudo kill $C; sleep 2; kill -0 $C 2>/dev/null && echo "client alive" || echo "client gone"client gone切れたので、入り直します。
$R 'tmux ls; tail -n 2 /var/tmp/upgrade.log'up: 1 windows (created Thu Nov 12 02:14:32 2026)
Get:34 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 linux-main-modules-zfs-7.0.0-43-generic arm64 7.0.0-43.43~24.04.1 [2073 kB]
Get:35 http://ports.ubuntu.com/ubuntu-ports noble-updates/main arm64 linux-modules-7.0.0-43-generic arm64 7.0.0-43.43~24.04.1 [285 MB]入れました。tmux のセッションが残っていて、更新はパッケージを取ってくる途中です。手元の SSH が切れても、止まっていません。コンソールからも見ます。
systemctl is-active ssh ssh.socket
ps -eo pid,etime,args | grep -E "dpkg|apt-get|tmux" | grep -v grepactive
active
13844 00:16 tmux new -s up sudo DEBIAN_FRONTEND=noninteractive apt-get full-upgrade -y -o Dpkg::Options::=--force-confold 2>&1 | tee /var/tmp/upgrade.log
13851 00:16 apt-get full-upgrade -y -o Dpkg::Options::=--force-confoldこの時点では、sshd も動いています。sshd が止まるのは、このあと openssh-server を入れ替えるときです。更新が終わってから、見張りの記録と、sshd のログを見ます。
grep -v '^Connection' /var/tmp/probe.log | uniq -c -f1
sudo journalctl -u ssh -u ssh.socket --since "$(cat /var/tmp/T0 | tr T ' ')" --no-pager -o short-iso | grep -E "Stopped|Listening|Closed" 10 02:14:31 open
7 02:15:22 refused
7 02:15:57 open
2026-11-12T02:15:21+00:00 ubuntu systemd[1]: Stopped ssh.service - OpenBSD Secure Shell server.
2026-11-12T02:15:21+00:00 ubuntu systemd[1]: Closed ssh.socket - OpenBSD Secure Shell server socket.
2026-11-12T02:15:55+00:00 ubuntu systemd[1]: Listening on ssh.socket - OpenBSD Secure Shell server socket.openssh-server を入れ替えるあいだ、sshd は 02:15:21 から 02:15:55 まで止まりました(日本時間 11:15)。そのあいだ、新しい接続は 7 回続けて断られました。このときに入り直していたら、Connection refused になります。すでに開いているセッションとは別の話で、新しく入れないだけです。
更新のログの最後には、再起動したサービスと、カーネルの案内と、RoamSwitch の知らせが出ます。
grep -A2 "^Restarting services" /var/tmp/upgrade.log
grep "running kernel" /var/tmp/upgrade.log
cat /var/run/reboot-required /var/run/reboot-required.pkgs
grep -A2 "^RoamSwitch" /var/tmp/upgrade.logRestarting services...
/etc/needrestart/restart.d/systemd-manager
systemctl restart cron.service fail2ban.service multipathd.service packagekit.service polkit.service roamswitch-server.service systemd-journald.service systemd-networkd.service systemd-resolved.service systemd-timesyncd.service systemd-udevd.service udisks2.service
The currently running kernel version is not the expected kernel version 7.0.0-43-generic.
*** System restart required ***
linux-image-6.8.0-31-generic
linux-base
linux-image-6.8.0-149-generic
linux-base
linux-image-7.0.0-43-generic
linux-base
RoamSwitch: 1 change is not explained by the package update and was not taken into the FIM baseline.
/etc/cron.d/lab-during-upgrade (new file): it is not a file of any package (it was written while the update command ran, before the packages were unpacked)
Check: sudo roamswitch fim verify. Once you know the changes are legitimate: sudo roamswitch fim update更新の終わりに、needrestart が fail2ban や roamswitch-server などのサービスを再起動しました。新しいカーネルは、OS を再起動するまで使われません。最後の3行は、パッケージの更新で説明できない変更が1件あり、改ざんの基準に入れなかった、という知らせです。tmux の中の更新は LANG を付けずに動かしたので、英語で出ています。中身は、次の章で読みます。
更新の途中で入れないとき、慌てて VM や OS を強制的に再起動すると、パッケージが入れ替えの途中で残ります。tmux の中の更新は、続いています。待つか、コンソールから ps で apt-get が残っているかを見ます。この VM では、sshd は 35 秒ほどで戻りました。
#通知を読む
更新のあいだと、そのあとに、何が通知されたかを読みます。
読むだけの操作です。途中で /etc/hosts にコメントを1行足し、すぐ消します(変更を伴う操作です)。
まず、更新を始めた時刻より後の通知を、一覧にします。
$R "sudo roamswitch notifications --json | jq -r --arg t \"\$(cat /var/tmp/T0)\" '.[] | select(.timestamp > \$t) | .timestamp[0:19] + \" \" + .title'"; echo "(end)"2026-11-12T02:16:27 クリティカルパス改ざん検知 (FIM) (1 件の改ざん)
(end)カーネル、sshd、sudo の入れ替えそのものは、改ざんの監視も eBPF ガードも知らせませんでした。apt が動いているあいだ、監視は通知を後回しにし、終わったときに、パッケージで説明できる変更だけを基準に取り込みます。
それでも、改ざんの通知が1件あります。前の演習で、更新が dpkg の鍵を握った直後に、コンソールから次の1行を書いていました。
until sudo fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do sleep 1; done
echo '# lab dummy, written during the upgrade' | sudo tee /etc/cron.d/lab-during-upgradeこの書き込みの通知です。コンソールから、このファイルの通知の本文を見ます。
sudo roamswitch notifications --json | jq -r '.[] | select(.body | contains("lab-during-upgrade")) | "== " + .timestamp[11:19] + " " + .title, .body, ""'== 02:16:27 クリティカルパス改ざん検知 (FIM) (1 件の改ざん)
/etc/cron.d/lab-during-upgrade: 新しいファイル
プロセス: root / /usr/bin/tee / コマンド: tee /etc/cron.d/lab-during-upgrade (pid 13861)
SSH のログインは見つかりませんでした(systemd サービス tart-guest-agent.service のプロセスです)
2026-11-12 02:16 のパッケージの更新では、この変更を基準に取り込みませんでした。理由: どのパッケージのファイルでもありません (更新のコマンドの実行中、パッケージを展開する前に書かれました)- 02:16:27: 更新が終わった時点で、後回しにしていた通知が出ました。書いたのはコンソールの
teeで、どのパッケージのファイルでもないので、基準に入れなかった、とあります - 理由の括弧は、書いた時刻(02:14:33)が、apt-get がパッケージを取ってくる途中で、展開の前だったことを示します
- このあと 02:21 まで待っても、同じファイルの通知は増えませんでした。更新の終わりに知らせた変更を、定期の検査が知らせ直すことはありません
fim verify にも、このファイルが残ります。
$R 'sudo roamswitch fim verify' 🔍 最重要システムファイルの整合性を検証中... (91 件)
🚨 ファイルの変更・改ざんが検知されました!
[新しいファイル] /etc/cron.d/lab-during-upgrade
このうち 1 件は、2026-11-12 02:16 のパッケージの更新で説明できなかったため、基準に取り込んでいない変更です。
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)
(3 件は、パッケージの更新による変化と判断しました。デーモンが基準に取り込みます)
正規のOS更新等による変更の場合は 'sudo roamswitch fim update' でベースラインを更新してください。SUID の付いた sudo などの入れ替えは、デーモンがパッケージの更新と判断して、基準に取り込みます。監視の対象の外の場所も含めて、更新のあいだに置かれたファイルは、目印のファイルより新しく、どのパッケージにも属さないファイルとして探せます。
$R 'sudo find /etc/cron.d /etc/cron.daily /etc/cron.hourly /etc/sudoers.d /etc/pam.d /etc/ssh /etc/systemd/system /etc/profile.d /etc/ld.so.conf.d /root/.ssh /home/*/.ssh -xdev -type f -newer /var/tmp/upgrade-start 2>/dev/null | while read -r f; do dpkg -S "$f" >/dev/null 2>&1 || echo "not from a package: $f"; done'
$R 'sudo dpkg --verify'not from a package: /etc/cron.d/lab-during-upgrade
??5?????? c /etc/falcoctl/falcoctl.yaml- not from a package: 更新のあいだに置かれ、パッケージに属さないファイルです。練習で置いた1つだけが見つかりました
- dpkg --verify: パッケージのファイルのうち、中身が配布時と違うものです。
5は中身の違い、cは設定ファイルです。falcoctl.yamlは、Falco を入れたときに Falco 自身が書き換えたものです
更新が終わったあとは、監視がふだんに戻ります。手元の PC から、/etc/hosts にコメントを1行足します。
$R 'echo "# lab dummy, written after the upgrade" | sudo tee -a /etc/hosts >/dev/null'
sleep 5
sudo roamswitch notifications | sed -n 5,14p
ssh-keygen -lf /var/tmp/lab_key.pub 2026-11-12T02:17:09.393614715+00:00
クリティカルパス改ざん検知 (FIM) (1 件の改ざん)
ホスト: ubuntu (IP: 192.168.64.32)
ハッシュが一致しない重要システムファイル:
/etc/hosts: 内容の変更
プロセス: root(ログインしたアカウント: admin) / /usr/bin/tee / コマンド: tee -a /etc/hosts (pid 40057)
SSH ログイン: 10.99.0.2:37824 から admin が 2026-11-12 02:17:09 にログインしたセッションです(認証: publickey, 鍵 SHA256:IkcF1OvHdbfC0ydp0366nEBzz03rFyYcTxStBFwdjU8)
推奨対応: `sudo roamswitch fim verify` で改ざん箇所を特定し復旧してください。
時刻: 2026-11-12 02:17:09
256 SHA256:IkcF1OvHdbfC0ydp0366nEBzz03rFyYcTxStBFwdjU8 lab-dummy-key (ED25519)5 秒以内に通知が出ました。SSH ログインの行の鍵の指紋が、手元の鍵と同じです。自分の作業だと分かります。足した行を消すと、/etc/hosts は基準と同じに戻ります。
$R 'sudo sed -i "/lab dummy, written after the upgrade/d" /etc/hosts'この VM で見たことから、次のように分けます。
- パッケージの入れ替えそのものの通知がない: 想定内です。パッケージで説明できる変更は、通知せずに基準に取り込まれます
- 更新の終わりに出た、改ざんの通知: 想定外として読みます。更新のあいだに、パッケージ以外が書いた変更です。書いたプロセスと SSH ログインの行で、自分の作業か確かめます。合わなければ、調べます
- パッケージに属さないファイルが見つかった: 自分が置いたものでなければ、中身を確かめます。cron、sudoers、systemd のユニットは、居座りの仕掛けに使われます
#再起動して、戻ったことを確かめる
新しいカーネルは、再起動しないと動きません。再起動のあと、サービスが動いていることに加えて、検知が実際に働くことを確かめます。
OS を再起動する操作です(変更を伴う操作です)。この演習の最後に、練習の場を片付けます。
手元の PC から、再起動します。
$R 'sudo systemctl reboot'ネットワーク名前空間は、再起動で消えます。コンソールから、前の演習と同じ手順で outside を作り直してから、入り直します。1 分ほど待ってから確かめます。
$R 'uname -r; systemctl is-active roamswitch-server falco-modern-bpf ssh.socket fail2ban; ls /var/run/reboot-required 2>&1'
$R 'sudo roamswitch status --server | grep -A1 "eBPF ランタイム"'
$R 'sudo roamswitch fim verify'
$R 'sudo nft list tables'7.0.0-43-generic
active
active
active
active
ls: cannot access '/var/run/reboot-required': No such file or directory
[合格] eBPF ランタイムセキュリティエージェント - 稼働中 (Falco/Tetragon連携)
準拠: CIS - / NIST CSF DE.CM-09
🔍 最重要システムファイルの整合性を検証中... (91 件)
🚨 ファイルの変更・改ざんが検知されました!
[新しいファイル] /etc/cron.d/lab-during-upgrade
このうち 1 件は、2026-11-12 02:16 のパッケージの更新で説明できなかったため、基準に取り込んでいない変更です。
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)
正規のOS更新等による変更の場合は 'sudo roamswitch fim update' でベースラインを更新してください。
table inet roamswitch_server
table inet roamswitch_metadata_watch
table inet roamswitch_egress_block
table inet roamswitch_portscan
table inet roamswitch_dnstunnel
table inet roamswitch_dev_guard新しいカーネルで起動し、RoamSwitch と Falco と sshd が動いています。ファイアウォールの規則も戻りました。SUID の3件は、デーモンが基準に取り込み、もう出ません。更新のあいだに置いた cron のファイルは、再起動のあとも一覧に残ります。
「動いている」だけでは、新しいカーネルで eBPF のセンサーが働いているかは分かりません。害のない検知を1件起こします。root の python3 で /etc/shadow を読むだけで、書き換えはしません。
$R 'sudo python3 -c "open(\"/etc/shadow\").read(); import time; time.sleep(3)"'
sleep 8
sudo roamswitch notifications | sed -n 5,12p 2026-11-12T02:23:06.838248008+00:00
eBPF ランタイム脅威検知: Read sensitive file untrusted (Warning)
ホスト: ubuntu (IP: 192.168.64.32)
検知ルール: Read sensitive file untrusted
深刻度: Warning
対象プロセス: python3 (PID: 2133)
自律防御アクション: 記録のみ(ガードの設定により、遮断しない)
時刻: 2026-11-12 02:23:06新しいカーネルでも、Falco の検知が RoamSwitch に届きました。深刻度は Warning なので、記録して知らせるだけです。
最後に、練習の場を片付けます。古いカーネルは、/boot に残っています。練習のファイルと鍵を消し、fim verify で確かめてから、基準に取り込みます。
ls /boot/vmlinuz-*
sudo rm /etc/cron.d/lab-during-upgrade
sed -i '/lab-dummy-key/d' ~/.ssh/authorized_keys
sudo roamswitch fim verify
sudo roamswitch fim update
sudo ip netns del outside
sudo rm -f /var/tmp/lab_key /var/tmp/lab_key.pub /var/tmp/upgrade-start /var/tmp/T0 /var/tmp/upgrade.log /var/tmp/probe.log /var/tmp/ssh-client.out/boot/vmlinuz-6.8.0-147-generic
/boot/vmlinuz-6.8.0-149-generic
/boot/vmlinuz-6.8.0-31-generic
/boot/vmlinuz-7.0.0-38-generic
/boot/vmlinuz-7.0.0-43-generic
🚨 ファイルの変更・改ざんが検知されました!
[内容の変更] /home/admin/.ssh/authorized_keys
正規のOS更新等による変更の場合は 'sudo roamswitch fim update' でベースラインを更新してください。
✓ ベースラインDBを正常に更新・署名保存しました。 (91 件記録)cron のファイルは基準に入っていなかったので、消すと一覧から消えました。残ったのは、練習の鍵を消した authorized_keys です。6.8.0-31 は、練習の場を作るときに入ったカーネルです。6.8.0-149 は、今回の更新で入りました。Falco を外すときは、sudo apt-get remove falco を使います。
更新の前に見た fim verify、bans、ssh-allow status、nft list tables を、再起動のあとにもう一度見ます。違いが出たものだけを調べれば足ります。
#見えない部分
使い捨ての Ubuntu 24.04 (arm64) の VM で、カーネルを含む 60 個のパッケージ(更新 47、新規 13)を更新して確かめた範囲は、次のとおりです。
- OS のメジャーアップグレード(
do-release-upgrade)は、行っていません。この講座の結果は、同じリリースの中の更新のものです - 更新のあいだの変更のうち、監視するファイルのものは、更新の終わりに通知され、基準に入りません。監視の外の場所は、目印のファイルを使った
findとdpkg --verifyで探します。目印より前の変更や、findで探していない場所は、この手順では見つかりません - sshd が止まる時間は、更新の中身で変わります。この VM では 34 秒でした
- 設定ファイルは、
--force-confoldで、いまのものを残しました。新しい既定の設定との差分の扱いは、この講座では扱っていません - 古いカーネルで起動し直す手順は、試していません。この VM の GRUB は、メニューを出さない設定(
GRUB_TIMEOUT=0)です。実機で古いカーネルを選ぶには、コンソールが要ります - Falco のパッケージ自体の更新は、この更新に入っていませんでした
更新の途中で SSH が切れ、入り直すと Connection refused です。更新は tmux の中で動かしていました。何をしますか
解説を見る
更新の途中は、
openssh-serverの入れ替えで sshd が止まることがあります。ファイアウォールのせいではありません。tmuxの中の更新は続いているので、終われば sshd も戻ります。
更新の前の fim verify に、覚えのない /etc/pam.d/common-auth の変更が出ました。どうしますか
解説を見る
更新は、パッケージのファイルを入れ替えます。改ざんされたファイルが同じ更新で入れ替わると、中身がパッケージの記録と一致して基準に入り、変更の跡が消えます。調べるなら、更新の前です。
#次に学ぶこと
- 改ざんの監視が見るファイルと、通知の読み方は、居座りと改ざん で扱います
- 総当たりガードや許可リストに締め出されたときの解き方は、SSH への総当たりと、自分が締め出されたとき にあります
- RoamSwitch 自身の更新と、doctor の読み方は、更新・脅威データ・アンインストール にあります
2026-11-12に確認しました。対象は Linux 1.17.39 です。使い捨ての Ubuntu 24.04 の VM(公開版 1.17.39)で、1つ前のカーネルに戻してから、tmux の中の apt full-upgrade、切断、再起動、片付けまでを実行しました。英語の出力は、同じ VM で LANG(SSH の先は /etc/default/locale)を切り替えて取りました。
コマンドの出力は、製品の版や環境によって変わります。違いが出たら、まず製品の版を確かめてください。