課題:apt upgrade完了後もシステムが完全に安全ではない理由
CentOSからUbuntuに乗り換えたばかりの頃、苦い経験をしました。<a href="https://itfromzero.com/ja/linux/ubuntu-ja-linux/nala%e3%82%92ubuntu%e3%81%ab%e3%82%a4%e3%83%b3%e3%82%b9%e3%83%88%e3%83%bc%e3%83%ab%e3%81%97%e3%81%a6%e4%bd%bf%e3%81%86%e6%96%b9%e6%b3%95%ef%bc%9a%e7%9b%b4%e6%84%9f%e7%9a%84%e3%81%aaui%e3%80%81.html">sudo apt upgrade</a>を定期的に実行し、システムがOpenSSLやlibcなどの重要なセキュリティパッケージの更新に成功したと報告していても、lsofコマンドで詳しく調べると、NginxやPHP-FPMのプロセスが依然としてメモリ上の古いライブラリをロードしていることに気づき、愕然としたのです。
基本的に、ディスク上のファイルは更新されていますが、メモリ内で実行中のコードは脆弱性のある古いバージョンのままです。最も力技な解決策はサーバー全体を再起動(リブート)することですが、稼働率99.99%が求められる本番環境において、小さなパッチ適用のためにサーバーを再起動するのは非常に贅沢な悩みです。そこで登場するのがneedrestartです。このツールは、システム全体を停止させることなく、更新が必要なサービスを正確に特定してくれます。
30秒でできるインストールと使い方
最近のUbuntu Server(20.04以降)では、needrestartは通常プリインストールされています。もしサーバーに入っていない場合でも、インストールに必要なディスク容量はわずか10MB程度です。
1. クイックインストール
sudo apt update && sudo apt install needrestart -y
2. 手動チェック
メモリ内に「古い残骸」が残っていないかスキャンするには、以下のコマンドを使用します:
sudo needrestart
システムがクリーンな状態であれば、「Your power is great. I mean… everything is up to date.」という少しユーモアのあるメッセージが表示されます。逆に問題がある場合は、ncursesベースのインターフェースが表示され、古いライブラリを使用しているサービスの一覧から、すぐに再起動するものを選択できます。
動作原理:なぜneedrestartは賢いのか?
.so(共有オブジェクト)ファイルを更新すると、APTはディスク上のファイルを上書きします。しかし、実行中のプロセスは依然として古いファイルの内容が含まれるメモリ領域を指す「ハンドル」を保持しています。needrestartは/procディレクトリをスキャンし、「deleted(削除済み)」とマークされたファイルを参照しているメモリマッピングを探し出します。
このツールは主に以下の4つの役割を担います:
- Library check: 古いライブラリをロードしているプロセスをスキャンします。
- Kernel check: 実行中のKernelバージョン(
uname -r)と、インストールされた最新バージョンを比較します。 - Microcode check: SpectreやMeltdownなどの脆弱性対策として、CPUが新しいマイクロコードを読み込む必要があるか確認します。
- APT Hook:
apt upgradeコマンドの終了時に自動的に起動し、通知を行います。
本番環境向けの構成
デフォルトでは、needrestartはアップデートプロセスを中断し、青い画面(対話型インターフェース)でユーザーの入力を求めます。これは自動化スクリプトやAnsibleを使用している場合には非常に不便です。
以下の設定ファイルを編集して調整しましょう:
sudo nano /etc/needrestart/needrestart.conf
再起動モードのカスタマイズ
パラメータ $nrconf{restart} を探し、以下の3つの値から1つを選択します:
'i'(interactive): インターフェース経由で確認する(デフォルト)。'a'(automatic): 自動的に再起動する。警告: サービスが予期せず中断される可能性があります。'l'(list only): ログへの記録とリスト表示のみを行い、何もしない。重要なサーバーにとって最も安全な選択肢です。
重要なサービスをブラックリストに登録する
突然のシャットダウンによるデータ破損を防ぐために、データベース(MySQLやPostgreSQLなど)をneedrestartの対象外にしたい場合は、以下のように設定します:
$nrconf{override_rc} = {
qr(^mysql) => 0,
qr(^postgresql) => 0,
};
現場からの実践的なアドバイス
カーネルの警告を無視しない
アプリケーションライブラリとは異なり、Kernelは部分的に再起動することはできません。needrestartがKernelの再起動が必要だと報告した場合は、早めにメンテナンス計画を立ててください。Kernelパッチは通常、root権限の奪取やコンテナ脱出(container escape)に関連する重要なものだからです。
自動化のためのバッチモード活用
数十台のサーバーを管理している場合、一つ一つの画面を確認することは不可能です。-bフラグを使用して、機械読み取り可能な形式で出力を取得しましょう:
sudo needrestart -b
grepと組み合わせることで、対応が必要なサーバーがある場合にTelegramへ通知を飛ばすような簡単なスクリプトを作成できます。
Dockerとコンテナに関する注意点
小さな弱点として、ホスト上で直接実行すると、needrestartがDockerコンテナ内で実行されているプロセスまで誤ってスキャンしてしまうことがあります。Dockerの場合、黄金律は「新しいイメージをビルド -> プル -> コンテナを再起動」です。実行中のコンテナ内のサービスをneedrestartで再起動しようとはしないでください。
おわりに
needrestartは、Ubuntuの管理をよりプロフェッショナルにするための強力な助っ人です。推測に頼る必要がなくなり、いつアクションを起こすべきかを正確に把握できるようになります。私にとって、これはOSインストール直後に導入すべき「マストハブ(must-have)」なツールであり、すべてのセキュリティパッチが単にディスクに保存されるだけでなく、実際に効果を発揮することを保証してくれます。

