
EC2 の OS(Ubuntu 24.04 ) パッチ運用を Patch Manager 前提で考えてみた
製造ビジネステクノロジー部の小林です。
EC2 での OS パッチ更新の運用方法を考える機会がありました。対象は Ubuntu 24.04(Graviton)の EC2 で、AMI は Canonical 公式の ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-arm64-server です。
現状の調べ方と、最終的に決めた運用ルールをまとめました。
まず今どうなっているかを調べる
Ubuntu には unattended-upgrades という自動更新のしくみが最初から入っています。ルールがなくても何も当たっていないとは限らないので、まずその動きを確認しました。
確認はマネジメントコンソールからセッションマネージャーで接続して行います。
- EC2 のコンソールで対象のインスタンスを選び、[接続] を選ぶ
- [セッションマネージャー] タブで [接続] を選ぶ
- ブラウザに開いたシェルで、以下のコマンドを順に実行する

ログインユーザーは ssm-user です。どのコマンドも表示するだけで、設定は変えません。出力は検証環境の 1 台で実行した結果です。
自動更新が有効か
まず、unattended-upgrades による自動更新が有効になっているかを、設定ファイル 20auto-upgrades で確認しました。
cat /etc/apt/apt.conf.d/20auto-upgrades

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
Update-Package-Lists はパッケージ一覧の更新、Unattended-Upgrade は更新の自動適用の設定です。値は日数で、"1" なら毎日実行、"0" なら無効です。今回はどちらも "1" なので、毎日自動で更新されていました。
対象のリポジトリ
自動更新でどのリポジトリのパッケージが適用されるかを確かめるため、unattended-upgrades の対象(Allowed-Origins)を確認しました。
apt-config dump Unattended-Upgrade::Allowed-Origins

Unattended-Upgrade::Allowed-Origins "";
Unattended-Upgrade::Allowed-Origins:: "${distro_id}:${distro_codename}";
Unattended-Upgrade::Allowed-Origins:: "${distro_id}:${distro_codename}-security";
Unattended-Upgrade::Allowed-Origins:: "${distro_id}ESMApps:${distro_codename}-apps-security";
Unattended-Upgrade::Allowed-Origins:: "${distro_id}ESM:${distro_codename}-infra-security";
apt-config dump は、設定ファイルをすべて読み込んだあとの有効な値だけを出すので、コメント行や途中で切れる心配がありません。有効なのはリリース本体(noble)、-security、ESM のセキュリティで、-updates の行がないので noble-updates は対象外です。
自動更新で noble-updates が当たらないため、その分が月次の Patch Manager 適用まで溜まることになります。
自動再起動の設定
grep -E "^[^/]*Automatic-Reboot" /etc/apt/apt.conf.d/50unattended-upgrades

何も表示されなければ未設定で、既定値の false(自動では再起動しない)が効いています。今回は何も表示されませんでした。
タイマー
自動更新がいつ動いているかを確かめるため、apt の 2 つのタイマーについて、次回と前回の実行時刻を確認しました。
systemctl list-timers apt-daily.timer apt-daily-upgrade.timer --no-pager

NEXT LEFT LAST PASSED UNIT ACTIVATES
Tue 2026-11-03 06:40:59 UTC 35min Mon 2026-11-02 06:36:49 UTC - apt-daily-upgrade.timer apt-daily-upgrade.service
Tue 2026-11-03 18:34:09 UTC 12h Tue 2026-11-03 06:03:13 UTC 2min 9s ago apt-daily.timer apt-daily.service
2 timers listed.
Pass --all to see loaded but inactive timers, too.
apt-daily-upgrade.timer が自動適用、apt-daily.timer がパッケージ一覧の更新です。時刻は UTC なので、前回の自動適用は日本時間で 11 月 2 日 15:36 でした。
直近の自動更新
ログのディレクトリは root と adm グループしか読めないので sudo を付けます。
sudo tail -n 3 /var/log/unattended-upgrades/unattended-upgrades.log

2026-11-03 06:03:16,864 INFO Allowed origins are: o=Ubuntu,a=noble, o=Ubuntu,a=noble-security, o=UbuntuESMApps,a=noble-apps-security, o=UbuntuESM,a=noble-infra-security
2026-11-03 06:03:16,864 INFO Initial blacklist:
2026-11-03 06:03:16,864 INFO Initial whitelist (not strict):
ログの冒頭からは、自動更新が対象にしているリポジトリ(noble、noble-security、ESM のセキュリティ)を確認できます。更新が成功したかどうかは、その回の処理の終わりに出る行(「All upgrades installed」や「No packages found that can be upgraded unattended」)で確かめます。
未適用の更新の件数
apt list --upgradeable 2>/dev/null | grep -c noble-updates
apt list --upgradeable 2>/dev/null | grep -c noble-security

71
0
noble-updates が 71 件、noble-security が 0 件でした。apt list は取得済みのパッケージ情報(apt-daily.timer が更新したもの)を見るので、ここでの件数はその時点の情報に基づくものです。
未適用の判定は Patch Manager の Scan でもできますが、現状調査では使いませんでした。Scan はベースラインの対象の更新は入れませんが、Patch Manager 自身が使う python3-apt とその関連パッケージは更新するためです。
実際、検証用に立てた EC2 に Scan を流すと、python3-apt と python-apt-common が 2.7.7ubuntu5.1 から 2.7.7ubuntu5.3 に更新されました。見るだけなら、サーバー上の apt で確かめる方が安全です。

再起動待ち
自動更新のあとに再起動が必要な状態で残っていないかを確かめるため、再起動待ちの目印のファイルと、最後に起動した日時を確認しました。
ls /var/run/reboot-required*
uptime -s

ls: cannot access '/var/run/reboot-required*': No such file or directory
2026-11-02 23:06:56
/var/run/reboot-required は再起動が必要な更新があるときに置かれる目印のファイルで、無ければ再起動待ちはありません。uptime -s は最後に起動した日時です。
今回は目印のファイルがなく、最後の起動は日本時間で 11 月 3 日 8:06 でした。前回の自動適用(11 月 2 日 15:36)のあとに起動し直しているので、再起動待ちの更新は残っていません。
結果のまとめ
自動更新は Ubuntu の初期設定のまま毎日動いていて、セキュリティ更新は当たっていました。一方、noble-updates は自動更新の対象外なので、適用されずに溜まっていました。

Persistent=true なので、その時刻にサーバーが止まっていた場合は、次に起動したときに実行されます。
分かった困りごと
セキュリティ更新は全台当たっていました。困っていたのは次の 4 つです。
- 業務時間中の 15 時台に自動更新が走る。ライブラリの更新があった日は、needrestart が nginx や ssh などのサービスを再起動していた(停止から起動までは 1 秒未満)
- 開発、検証、本番の順番がなく、全環境に同じ日に同じ更新が入る
- 何を、いつ、どの順番で当てるかが決まっておらず、監査で答えられない
- どの台に何が当たったかを、サーバーに入らないと確かめられない
Ubuntu の更新は 2 種類ある
現状調査で、自動更新は noble-updates を当てていないことが分かりました。運用ルールを決める前に、この 2 種類の更新の違いを整理します。
| 名前 | 中身 | unattended-upgrades の初期設定 | Patch Manager の既定 | 段階配信 |
|---|---|---|---|---|
| noble-security | 脆弱性の修正 | 対象 | 対象 | なし |
| noble-updates | バグ修正や機能改善 | 対象外 | 対象外 | あり |
Ubuntu セキュリティチームの FAQ によると、-security の更新は -updates に依存しないように作られています。つまり、セキュリティ更新だけを当てても依存関係は壊れません。
段階配信(Phased updates)は、更新をすべてのマシンに一斉に配らず、マシンごとに配る時期をずらすしくみです。noble-updates だけが対象で、セキュリティ更新は公開されるとすぐ全台に配られます。
Patch Manager も、Ubuntu では候補のバージョンが noble-security にあるパッケージだけを既定で対象にします。noble-updates まで含めるには、ベースラインで「セキュリティ以外の更新を含める」を選びます。
やり方の選択肢
OS パッチを当てる方法として、OS の自動更新(unattended-upgrades)、Patch Manager、AMI の入れ替え(EC2 Image Builder)の 3 つを比べました。

unattended-upgrades でも適用の時刻は変えられるので、15 時台に走る問題は解決できます。ただ、開発・検証・本番の順番を付けることと、全台の適用状況をサーバーに入らずに見ることはできません。
AMI の入れ替えは、ALB の後ろに複数台並ぶ構成に向いたやり方です。社内の経験者からも、そうした構成では EC2 Image Builder で月次に AMI を入れ替え、単体のサーバーには Patch Manager を使っていたと聞きました。
今回の構成は、各環境に役割ごとの EC2 が 1 台ずつで、VPN サーバーのように状態を持つものもあります。インスタンスを入れ替える方法は合わないので、Patch Manager に一本化します。2 つのしくみを残すと、どちらが当てたのか追えなくなるので、unattended-upgrades は止めます。
決めた運用ルール

| 毎日 | 月次 | |
|---|---|---|
| 当てるもの | セキュリティ更新(noble-security) | noble-updates |
| 開発・検証 | 公開された日の夜 | 第 1 火曜の夜 |
| 本番 | 翌営業日の夜 | 翌週の第 2 火曜の夜 |
| 項目 | ルール |
|---|---|
| 本番に入れる条件 | 開発・検証で翌朝の確認(起動、ALB、代表 API、VPN、前夜の全台成功)に合格したバージョンだけ |
| 時刻と再起動 | 平日 21:00 に適用し、再起動は 22:00 の停止と翌朝の起動で代用 |
| 通知 | 失敗や未実行をチャットに通知 |
| 緊急時 | そのパッケージだけ Run Command で全環境に当てる |
| OS のバージョンアップ | パッチとは別枠 |
セキュリティ更新は 1 回の変更が小さいので本番は翌営業日、noble-updates は 50〜70 件まとめて入るので 1 週間空けます。夜間は止まっているので、翌朝の確認では一晩動かした結果ではなく、起動後の状態を見ます。
環境ごとの順番をどう作るか
ルールどおりに動かすには、本番には開発・検証で確認済みの更新だけを当てるしくみが必要です。
ベースラインの ApproveAfterDays(公開から N 日で自動承認)を環境ごとにずらす方法も考えましたが、Ubuntu ではサポート対象外です。リポジトリから公開日を確実に取れないためで、既定の AWS-UbuntuDefaultPatchBaseline も即時承認になっています。
そこで、AWS-RunPatchBaseline の InstallOverrideList を使います。S3 に置いた YAML の一覧どおりに当てるパラメーターです。Linux では、すでに入っているパッケージの更新にだけ使われ、新しいパッケージは入りません。
一覧には、id にパッケージ名とアーキテクチャ、title に当てるバージョンを書きます。
patches:
-
id: 'nginx.arm64'
title: '*1.24.0-2ubuntu7.19'
-
id: 'libssl3t64.arm64'
title: '*3.0.13-0ubuntu3.16'

一覧は Lambda で作ります。
- 毎日の分:開発・検証の両方に入ったバージョンから作り、翌朝の確認に合格したら、翌営業日の夜に本番へ当てる
- 月次の分:第 1 火曜の開発・検証の適用結果から別の一覧を作り、翌週の第 2 火曜に当てる
InstallOverrideList は、指定した URL の一覧をそのまま当てるだけです。どの日の一覧を使うかを選ぶ機能はないので、その日の承認済み一覧を本番に渡す処理も Lambda で用意します。承認済みの一覧がない日は、本番の適用を見送ってチャットに通知します。
拒否リストは Lambda で効かせる
InstallOverrideList は、ベースラインのルールに関係なく一覧を当てます。そのため、ベースラインの拒否リストでは止まりません。拒否リストは Parameter Store に持ち、一覧を作る Lambda で除外します。
再起動をどうするか
この EC2 は 22:00 に自動停止し、翌朝 7:30 に自動起動しています。そこで RebootOption を NoReboot にして 21:00 に適用し、再起動は夜の停止と朝の起動に任せます。

メンテナンスウィンドウを作る
平日 21:00(日本時間)に開始し、1 時間で閉じるメンテナンスウィンドウを作ります。
aws ssm create-maintenance-window \
--name "patch-install-weekday" \
--schedule "cron(0 21 ? * MON-FRI *)" \
--schedule-timezone "Asia/Tokyo" \
--duration 1 \
--cutoff 0 \
--allow-unassociated-targets
このコマンドで作るのはウィンドウだけです。対象のインスタンスは register-target-with-maintenance-window、実行するタスク(AWS-RunPatchBaseline の Install)は register-task-with-maintenance-window で別に登録します。
1 時間で足りるか
Ubuntu Pro 22.04 での検証記事では、セキュリティ更新 60 件ほどの Install が約 10 分でした。今回の環境でも、自動更新にかかった時間は 1 日あたり最長 2 分半ほどです。月次の noble-updates も 1 台あたり 50〜70 件(40〜64 MB)と、検証記事と同じくらいの規模です。
ただし、ウィンドウの長さは「1 時間以内に終わる」ことを保証するものではありません。cutoff 0 は終了時刻以降に新しいタスクを始めない設定で、実行中のタスクは既定(CONTINUE_TASK)のまま続きます。適用が長引いて 22:00 をまたぐと、パッケージの入れ替え中に停止される恐れがあります。
そこで、自動停止の Lambda は、Patch Manager のコマンドが実行中なら停止を延期します。22:00 を過ぎても終わっていなければ、チャットに通知します。
翌朝に Scan で確かめる
NoReboot で当てたパッチは、再起動して Scan するまで InstalledPendingReboot(Non-Compliant)のままです。そこで、別のウィンドウで 7:45 に Scan を流し、8:00 の朝の確認で結果を見ます。7:45 にしたのは、7:30 の起動からサービスが立ち上がるまでの時間を 15 分ほど空けるためです。
注意点
NoReboot で止まるのは OS の再起動だけです。Ubuntu 24.04 のデフォルト設定では、needrestart がライブラリ更新の影響を受けるサービスを自動で再起動する場合があります。21:00 は「サービスが一瞬再起動されうる時間帯」として、認識しておきましょう。
実際、これまでも 15 時台の自動更新で、ライブラリ更新があった日は nginx が再起動していました(停止から起動まで 0.1〜0.3 秒)。
戻し方を決めておく
AWS Backup は毎日 1:00 に取っています。パッチは 21:00 に当たるので、適用前の最新の世代は、当てた日の 1:00 のものです。

戻し方は次の順に考えます。
- 更新前のバージョンがまだリポジトリに残っていて、ほかのパッケージを一緒に戻さずに済むなら、
apt install パッケージ=バージョンで原因のパッケージだけ戻す - 難しければ、当てた日の 1:00 の Backup から戻し、アプリを配備し直す。1:00 以降のデータや設定の変更も消えるので、VPN サーバーのように状態を持つサーバーでは、失われる変更を確かめてから戻す
月次の適用前にバックアップを取る
月次の noble-updates の問題は、気づくのが遅れがちです。気づいたころには、毎日の世代に適用前の状態が残っていないことがあります。
そこで月次の適用日は、AWS Backup の月次ルールで適用前に 1 世代取り、30 日残します。開始は 19:00、開始ウィンドウは 1 時間です。AWS Backup は指定時刻ちょうどに取る保証がないので、完了を確かめてから適用を始めます。終わっていなければ、その月の本番の回は延期します。
戻したら拒否リストに入れる
原因のパッケージは、環境に合わせて 2 か所の拒否リストに入れます。
| 環境 | 入れる場所 |
|---|---|
| 本番 | 一覧を作る Lambda が見る Parameter Store |
| 開発・検証 | ベースラインの「拒否するパッチ」 |
ベースラインの拒否は、既定(ALLOW_AS_DEPENDENCY)のままだと、別の更新の依存関係として入ることがあります。確実に止めるため、RejectedPatchesAction を BLOCK にします。BLOCK にすると、そのパッケージを依存として必要とする更新も入らなくなります。
その日の本番向けの一覧がすでに S3 にある場合は、21:00 までに一覧を消すか、拒否リストを反映して作り直します。消した場合は承認済みの一覧がない日になるので、本番の適用は見送られます。
拒否したパッケージには、そのあとのセキュリティ修正も入りません。月に 1 回、新しいバージョンが出ていないかを確かめ、開発で問題が直ったことを確認できたら拒否を外します。
unattended-upgrades を止める
公式ドキュメントのとおり、20auto-upgrades の 2 つの値を 0 にします。
sudo tee /etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
APT::Periodic::Update-Package-Lists "0";
APT::Periodic::Unattended-Upgrade "0";
EOF
反映は apt-config で確かめます。
apt-config dump APT::Periodic
止めるのは最後です。Patch Manager のメンテナンスウィンドウ、対象、タスクを登録し、Scan と適用が動いて、失敗時にチャットへ通知が届くことを確かめてから止めます。
先に止めると、Patch Manager が動き始めるまでの間、セキュリティ更新が当たらない期間ができてしまいます。
まとめ
Ubuntu 24.04 の EC2 で、OS パッチの運用ルールを Patch Manager 前提で考えてみました。
noble-security と noble-updates の役割の違いが分かり、毎日はセキュリティ更新だけを当てればよいと整理できたのは収穫でした。
一方で、Ubuntu では「公開から N 日待つ」設定がサポート対象外のため、今回は Lambda と S3 で一覧を用意して環境ごとの順番を作る形にしました。
Amazon Linux なら承認までの待機日数をベースラインで設定できるので、OS によって運用の組み立て方が変わることを実感しました。次回は実際に、PatchManager、Lambda、S3 を使い今回の構成を実装してみます!
この記事がどなたかの参考になれば幸いです。






