USBポートは閉めるまで開きっぱなしの扉だ
深夜にSSHブルートフォース攻撃を受けてから、ネットワーク側のサービスだけでなく、あらゆる攻撃経路を真剣に考えるようになった。SSHの堅牢化、Fail2Ban、ファイアウォールルール……それらは定番の対策だ。しかし、ほとんどのLinux管理者が完全に見落としている物理的な侵入経路がある。USBポートだ。
清掃員がサーバー室のマシンにUSBドライブを差して充電しているところを想像してほしい。あるいは、同僚が接続したキーボードが実はRubber Duckyだったとしたら——Hak5が販売する80ドルのHIDインジェクションデバイスで、見た目は普通のUSBドライブと全く変わらない。こうした攻撃は現実に存在し、実行コストも低く、ファイアウォールには完全に無力だ。
USBGuardはこの問題を直接解決する。ベンダー、シリアル番号、ポートを指定して許可するUSBデバイスを定義しておけば、カーネルが認証する前にそれ以外のデバイスをすべてブロックできる。
BadUSBがこれほど危険な理由
BadUSBは従来の意味でのウイルスではない。USBデバイスのファームウェアを書き換えて別のデバイス種別——通常はキーボードやネットワークアダプター——に成りすます攻撃だ。差し込んだ瞬間、OSは正規のHIDデバイスと認識してフルキーボードアクセスを許可してしまう。数秒以内にコマンドを実行し、ペイロードをダウンロードし、データを外部に送出できる。
特に厄介な特性が3つある:
- ウイルス対策ソフトでは検出不可能——ファイルではなくファームウェアに潜むため
- あらゆるOSで機能する——Linux、macOS、WindowsはいずれもHIDデバイスをデフォルトで信頼する
- 動作が速い——ペイロード全体を10秒以内に実行できる
悪意がない場合でも、USBアクセスを管理しないとコンプライアンス上の問題が生じる。HIPAA、PCI-DSS要件12.3.1、SOC 2 CC6.7はいずれも、機密データを扱うシステムにおけるリムーバブルメディアの制御を義務付けている。
基本概念:USBGuardの仕組み
USBGuardはシステムデーモンとして動作し、カーネルレベルでUSBデバイスの認証イベントを傍受する。デバイスが接続されると、USBGuardはルールセットと照合する。許可ルールに一致すればデバイスは認証される。ブロックルールに一致するか、デフォルトポリシーがブロックのときにどのルールにも一致しなければ、デバイスは未認証のままOSから使用できない。
設定に触れる前に知っておくべき3点:
デバイスの識別
USBGuardはベンダーID、プロダクトID、シリアル番号、デバイスクラス、USBポートでデバイスを識別する。ルールは「このベンダーのキーボードをすべて許可」という広いものから、「このシリアル番号のUSBドライブをこのポートだけで許可」という細かいものまで設定できる。
ポリシーターゲット
各ルールはallow、block、rejectのいずれかのターゲットで終わる。blockはデバイスを未認証のまま接続状態に保つ。rejectはバスから完全に切断する——lsusbからデバイスが消える。
暗黙のポリシー
暗黙のポリシーとは、どのルールにも一致しない場合の動作だ。blockに設定すると、未知のデバイスはサイレントにブロックされる。サーバーではこれをデフォルトにしておくべきだ。
インストール
USBGuardはほとんどのディストリビューションの標準リポジトリに含まれている:
# Debian / Ubuntu
sudo apt install usbguard
# RHEL / CentOS / Rocky Linux
sudo dnf install usbguard
# Arch Linux
sudo pacman -S usbguard
インストール後、デーモンはまだ起動していない——これは意図的だ。起動前にベースラインポリシーを生成しておかないと、自分のキーボードとマウスが使えなくなる。
実践:USBアクセスをロックダウンする
ステップ1 — 現在接続中のデバイスからポリシーを生成する
USBGuardを起動する前に、恒久的に許可すべきものをすべて接続しておく:キーボード、マウス、内蔵USBハブ、YubiKey、日常的に使うものすべてだ。次に、現在接続中のすべてのデバイスのルールを生成する:
sudo usbguard generate-policy > /etc/usbguard/rules.conf
これにより、現在バス上にあるすべてのデバイスの許可ルールが作成される。ファイルを開いて生成内容を確認しよう:
cat /etc/usbguard/rules.conf
次のようなエントリが表示される:
allow id 046d:c52b serial "" name "USB Receiver" hash "abc123..." parent-hash "def456..." via-port "1-1.2"
各行が1つのルールだ。hashはデバイスディスクリプターのフィンガープリントで——残念ながらファームウェアのハッシュではないが——同じVID/PIDを持つデバイスへの安易な差し替えは防げる。
ステップ2 — デーモンを有効化して起動する
sudo systemctl enable --now usbguard
起動を確認する:
sudo systemctl status usbguard
次に、元のポリシーに含まれていないUSBドライブを差し込んでみよう。dmesgには表示されるがマウントされないはずだ——カーネルは認識しているが、USBGuardが認証していない状態だ。
ステップ3 — 接続デバイスの一覧表示と管理
USBGuardにはデーモンと通信するための専用CLIが付属している:
# すべてのUSBデバイスと認証状態を一覧表示する
sudo usbguard list-devices
# 指定したIDのデバイスを許可する
sudo usbguard allow-device <id>
# デバイスをブロックする
sudo usbguard block-device <id>
# デバイスをリジェクトしてバスから削除する
sudo usbguard reject-device <id>
新しいデバイスを差し込んで一時的に許可したい場合は、list-devicesでIDを確認してallow-deviceを実行する。恒久的に許可するには、rules.confにルールを追加する。
ステップ4 — カスタムルールを記述する
ルールファイルはシンプルな構文を使用する。実用的なパターンをいくつか紹介する:
# シリアル番号でのみ特定のUSBドライブを許可する
allow id 0781:5583 serial "AA01234567890" name "SanDisk Ultra"
# 信頼済みベンダーのデバイスをすべて許可する(広範囲なので慎重に使うこと)
allow id 046d:*
# すべてのUSBストレージデバイスをブロックする(マスストレージクラス = 08)
block class 08:*:*
# USBハブは許可するが、クラス09のそれ以外は許可しない
allow class 09:00:00
# ネットワークアダプターとして認識されるデバイスをすべてリジェクトする
reject class 02:*:*
ルールは上から順に評価され、最初に一致したものが適用される。最も具体的なルールを先頭に配置すること。
rules.confを編集したら、デーモンを再起動せずにリロードする:
sudo usbguard reload
ステップ5 — 暗黙のポリシーを設定する
メイン設定ファイルを開く:
sudo nano /etc/usbguard/usbguard-daemon.conf
次の2行を見つけて設定する:
ImplicitPolicyTarget=block
PresentControllerPolicy=keep
ImplicitPolicyTarget=blockにより、明示的に許可されていないデバイスはすべてブロックされる。PresentControllerPolicy=keepは、デーモン起動時に既に接続済みのデバイスを現在の状態のまま維持するよう指示する——これにより、デーモン再起動時にキーボードが切断されるのを防ぐ。
ステップ6 — 監査ログを設定する
デバイスをブロックするのは仕事の半分だ。残りの半分は、いつどのポートで何が起きたかを記録することだ。設定ファイルで監査ログを有効にする:
AuditBackend=LinuxAudit
次にデーモンを再起動する:
sudo systemctl restart usbguard
USBGuardのイベントがシステム監査ログに記録されるようになる。次のコマンドで確認できる:
sudo ausearch -ts recent -m USER_DEVICE
SIEMやログシッパーを使っている場合、これらのイベントはauditdの既存のパイプラインにそのまま統合される——追加設定は不要だ。
ステップ7 — root以外のユーザーにデバイス管理権限を付与する
デフォルトでは、usbguard allow-deviceを実行できるのはrootだけだ。一般ユーザーが自分の周辺機器を接続する必要があるワークステーションでは、IPC ACLを通じて特定の権限を委任できる:
sudo nano /etc/usbguard/IPCAccessControl.d/90-user.conf
# 'wheel'グループにデバイスの一覧表示・許可・ブロックを許可する
[wheel]
Devices=list,allow,block
usbguardバイナリ全体にsudo権限を与えるよりも、この方法の方がすっきりしている。
設定のテスト
rules.confに登録されていないUSBドライブを用意して差し込む。次のコマンドを実行しよう:
sudo usbguard list-devices | grep -i block
blockターゲットでドライブが一覧に表示されるはずだ。マウントはされない。lsblkにも新しいデバイスは表示されない。これが期待される動作だ。
監査ログを確認するには:
sudo journalctl -u usbguard -f
デバイスを抜き差しすると、各イベントのログエントリがリアルタイムで表示される。
サーバーとワークステーションの考え方の違い
物理的な周辺機器が一切ないサーバーには、最も厳格なポリシーが適している:最小限のルールセット(おそらく内蔵USBハブだけ)を生成し、それ以外はすべてrejectに設定する。本番サーバーに何かを接続すべき人間はいないはずで、もし誰かが試みたなら即座に把握したい。
ワークステーションにはもう少し柔軟性が必要だ。暗黙のポリシーにはrejectではなくblockを使うことで、ユーザーはlist-devicesでブロックされたデバイスを確認して認証を要求できる。これをIPC ACLと組み合わせれば、既知の安全なデバイスに関しては管理者の承認なしで自分で対処できるようになる。
まとめ
初期ポリシーを設定してしまえば、USBGuardはバックグラウンドで静かに動作し続ける——継続的なメンテナンスは不要だ。ルールを書いてデーモンを起動すれば、USBセキュリティは自動化される。BadUSB、Rubber Ducky、O.MGケーブル——これらはすべて、コマンドが1つも実行される前にドライバー層で壁にぶつかる。
セットアップ全体で約15分あれば完了する。「誰も変なものを差し込まないだろう」という期待はセキュリティ戦略ではなく、楽観主義だ。共有スペース、データセンター、コンプライアンス規制のある環境で稼働するシステムにとって、USBホワイトリストはSSH鍵や自動アップデートと並んで、ベースラインの堅牢化チェックリストに加えるべき項目だ。

