AWS Systems Managerのパッチマネージャーを使ってパッチ適用を自動化する

# はじめに
本記事は[AWS Well-Architected Labs - Operational Excellence - 100 - INVENTORY AND PATCH MANAGEMENT](https://wellarchitectedlabs.com/operational-excellence/100_labs/100_inventory_patch_management/)のポイントやハンズオン手順をまとめたものになります。AWS Well-Architected Labsについて知りたい方は[こちら](https://qiita.com/chanhama/items/b40fd218865d9bce7723)をご覧ください。

# パッチ適用
パッチ適用運用はやらないといけないけど、手動で行う場合は面倒臭い作業です。数台のサーバーならまだしも数が多いとさらに大変です。パッチ適用は**トイル**の代表格と言っても過言ではないでしょう。そんなパッチ適用を**パッチマネージャー**を使えば**自動化**することができます。

# パッチ適用自動化を行う上でのAWSサービスやSystems Manager機能間の関係
パッチマネージャーを使ったパッチ適用を行う場合はいくつかのAWSサービスやSystems Manager機能を連携させる必要があります。最初利用した時は関係性が若干分かりにくかったため、まとめておきます。

## マネージドインスタンス
まずはパッチ適用の自動化対象のサーバをSystems Managerの管理下にする必要があります。ちなみにSystems Manager管理下にあるサーバはマネージドインスタンスと呼ばれます。EC2だけでなく、オンプレミスのマシンもマネージドインスタンスにすることができます。マネージドインスタンスにする条件は公式ドキュメントを参照してください。
[Systems Manager の前提条件](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-prereqs.html)

## パッチマネージャー
どのパッチをどのインスタンスに適用させるかをパッチマネージャーで設定することができます。

### パッチベースライン
パッチ適用のルールを定義することができます。OS毎にデフォルトのベースラインが用意されており、それらは変更することはできませんが、ユーザの用途に合ったパッチベースラインをカスタムバッチベースラインとして作成することができます。具体的には以下のような設定を行います。

- Product (製品)
    - 承認ルールが適用されるオペレーティングシステムのバージョン
- Classification (分類)
    - 承認ルールが適用されるパッチのタイプ 
- Severity (重要度)
    - ルールが適用されるパッチの重要度の値 
- Auto-approval (自動承認)
    - 自動承認のためにパッチを選択する方法
- Compliance reporting (コンプライアンスレポート)
    - ベースラインで承認されたパッチに割り当てる重要度
- Include non-security updates (セキュリティに関連しない更新を含める)
    - セキュリティに関連するパッチに加えて、ソースリポジトリで使用可能なセキュリティに関連しない Linux オペレーティングシステムのパッチをインストールするには、このチェックボックスをオンにします

[カスタムパッチベースラインの作成](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-patch-baseline-console.html)

### パッチグループ
パッチベースラインを適用するインスタンスをパッチグループとしてグループ化できます。パッチグループに所属させたいインスタンスには`key=Patch Group`のタグを付与する必要があります。パッチグループ作成時はkeyに対するvalueを指定して作成します。パッチグループはパッチベースラインに対して関連付けられます。

## SSMドキュメント AWS-RunPatchBaseline
パッチベースラインに設定されているパッチ適用を行うためにはRun Command経由でSSMドキュメントである**AWS-RunPatchBaseline**を実行する必要があります。Run Commnandの実行はメンテナンスウィンドウ、AWS CLI,SDK等から行います。実行時の必須パラメータとして以下を指定します。

- Operation
    - Scan
        - 適用予定のパッチ一覧だけを確認し、インストールは行わない
    - Install
        - 適用対象のパッチをインストールします。
- RebootOption
    - RebootIfNeeded
        - 再起動が必要なパッチが合った場合はインスタンスを再起動する
    - NoReboot
        - インスタンスの再起動は行わない

[SSM ドキュメント AWS-RunPatchBaseline について](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/patch-manager-about-aws-runpatchbaseline.html)

また、どのインスタンスに対してRun Commandを実行するかターゲットを指定します。注意として、**パッチ適用を行うインスタンスはパッチグループにも所属させ、Run Commandのターゲットしても指定してあげる必要がある**ということです。


# ハンズオン手順
パッチマネージャーを使ったパッチ適用を試せる[AWS Well-Architected Labs - Operational Excellence - 100 - INVENTORY AND PATCH MANAGEMENT](https://wellarchitectedlabs.com/operational-excellence/100_labs/100_inventory_patch_management/)のハンズオン手順を記載します。

## セットアップ
### IAMユーザ作成
まずはAdministratorAccess相当のポリシーがアタッチされたIAMユーザを用意しましょう。以降はこのIAMユーザでAWSマネジメントコンソールにログインし、操作してください。
![全画面_2020_08_01_16_53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/3241b90c-d742-b57c-42eb-40aaf76eafc1.png)

### EC2キーペア作成
EC2のキーペアを適当な名前で作成します。今回は`yhamano-wal`という名前で作成します。ファイル形式はpemを選んでください。
![全画面_2020_08_01_17_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/60a6f800-b2fe-e326-31fd-e5b7b9f13583.png)

## CloudFormationでのデプロイ
### テンプレートファイルのダウンロード
今回のハンズオン環境をCloudFormationを用いてデプロイします。
まず、[こちら](https://wellarchitectedlabs.com/Operations/100_Inventory_and_Patch_Mgmt/Code/OE_Inventory_and_Patch_Mgmt.json)からCloudFormationテンプレートをローカルにダウンロードしてください。

### IAMロール作成
CloudFormationで作成するEC2にアタッチするIAMロールを事前に作成します。
AWSマネジメントコンソールからIAM画面に遷移し、ロールの作成を選択します。
![全画面_2020_08_02_9_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/dea332b9-8dd8-5cfc-ddd2-cc19a39ea551.png)

ユースケースの選択でEC2を選択します。
![全画面_2020_08_02_9_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/53a910fc-a740-507c-237d-7d45dc16136a.png)


Attchアクセス権限ポリシーで**AmazonSSMManagedInstanceCore**を選択します。元々の手順ではAmazonEC2RoleforSSMを選択するようになっていますが、権限が大きすぎることからこちらは**非推奨**となっています。詳しくは[クラメソさんのブログ](https://dev.classmethod.jp/articles/not-recommended-amazonec2roleforssm/)を参照ください。
![全画面_2020_08_02_9_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/c79a0dc2-ce18-6dc8-888c-16703c772aab.png)

タグは何も指定せずに、ロール名を入力してロールの作成を行います。ロール名は適当でOKです。
![全画面_2020_08_02_9_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/2c10a98e-bc6c-736f-3652-31c28baf231a.png)

### スタック作成
スタックの作成を行なっていきます。CloudFormationの画面に遷移し、新しいリソースを使用(標準)を選択します。
![全画面_2020_08_02_10_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/318e9f68-3454-51db-5fbd-ef81abbd613a.png)

テンプレートファイルのアップロードから先ほどダウンロードしたCloudFormationテンプレートを選択します。
![全画面_2020_08_02_9_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/3de59564-f1bf-3dee-2406-57ddbbbb1413.png)

次に各種パラメータを入力します。

- スタックの名前
    - OELabStack1
- InstanceProfile
    - 先ほど作成したIAMロール名を入力します。
- InstanceTypeApp,InstanceTypeWeb
    - デフォルトで入力されているt2.microでOK
- KeyName
    - 先ほど作成したEC2キーペアを選択
- SourceLocation
    - アクセス元のグローバルIPを指定。[こちら](https://checkip.amazonaws.com/)アクセスすると確認できる。入力時は**/32**を末尾に追記すること
- WorkloadName
    - Test

![CloudFormation_-_スタック.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/86215c38-ba18-1923-0037-0bd156c3cc95.png)

オプション設定は何も入力せずに、レビュー画面を確認し、問題無ければスタックの作成を行う。作成開始後はステータスがCREATE_COMPLETEになるまで待ちます。
![CloudFormation_-_スタック_OELabStack1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/dfdfcf8d-335a-23be-76ee-d9f8462da3e4.png)

再度同じCloudFormationの実行手順で別環境を作成します。
各種パラメータは以下です。

- スタックの名前
    - OELabStack2
- InstanceProfile
    - 先ほど作成したIAMロール名を入力します。
- InstanceTypeApp,InstanceTypeWeb
    - デフォルトで入力されているt2.microでOK
- KeyName
    - 先ほど作成したEC2キーペアを選択
- SourceLocation
    - アクセス元のグローバルIPを指定。[こちら](https://checkip.amazonaws.com/)アクセスすると確認できる。入力時は**/32**を末尾に追記すること
- WorkloadName
    - Prod

## Systems Managerを用いた状態管理
### マネージドインスタンスへの登録確認
Systems Managerのマネージドインスタンス一覧に作成した8つのEC2インスタンスが表示されることを確認する。IAMロールをアタッチしてから一覧に表示されるまで数分かかる場合もあります。
![AWS_Systems_Manager_-_Managed_Instances.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/247f7ffa-6527-06a2-4b64-b3105c69256c.png)

### インベントリ設定
マネージドインスタンスをインベントリに設定します。なお、**パッチマネージャーでのパッチ適用をする場合にインベントリ設定を行う必要はありません。**インベントリ画面からセットアップインベントリを選択します。
![AWS_Systems_Manager_-_Inventory.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/3960bd87-2b81-1722-ed48-dd823134d9bc.png)

ターゲットでタグの指定を選択し、`key=Environment,value=OELabIPM`を入力し、その他の設定はそのままでインベントリを作成する。
![AWS_Systems_Manager_-_Inventory.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/1f4ca588-e1bd-7e64-742c-d29dc5bc9e84.png)

## パッチ管理
### パッチベースライン作成
まずパッチベースラインの作成を行います。
![AWS_Systems_Manager_-_Patch_Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/8e0bd6ea-2103-1e5b-a1f3-8e8f58ab8471.png)

各種パラメータは以下です。記載されていないパラメータはデフォルト設定でOK

- パッチベースラインの詳細
    - 名前
        - AmazonLinuxSecAndNonSecBaseline
    - 説明
        - Amazon Linux patch baseline including security and non-security patches
    - OS
        - Amazon Linux

![AWS_Systems_Manager_-_Patch_Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/8b48360d-69a8-51c8-0773-6c826aeae009.png)

- オペレーティングシステムの承認ルール
    - ルール1
        - 製品
            - ALL
        - 分類
            - ALL
        - 重要度
            - ALL
        - コンプライアンスレポート オプション
            - 非常事態
    - ルール2
        - 製品
            - ALL
        - 分類
            - ALL
        - 重要度
            - ALL
        - コンプライアンスレポート オプション
            - ミディアム
        - セキュリティ以外の更新を含める
            - チェック

![AWS_Systems_Manager_-_Patch_Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/3c50501e-e0c4-7c04-f42d-0342c70cdb15.png)

- パッチの例外
    - 拒否済みパッチ オプション
        - system-release.*

![AWS_Systems_Manager_-_Patch_Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/10bc32ae-f8cb-343d-7d65-071401678a60.png)

### パッチグループの割り当て
EC2のタグに`key=Patch Group`が設定されていればパッチグループとして定義されますが、今回はタグ`key=Patch Group,value=Critical`が最初から付与された状態で作成されているため、パッチグループの割り当てのみ行います。
作成したパッチベースライン詳細画面からパッチグループの変更を選択し、パッチグループには`Critical`を入力し、追加します。

![AWS_Systems_Manager_-_Patch_Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/db60d7db-a744-c8d7-f158-fde7ce753b17.png)

![AWS_Systems_Manager_-_Patch_Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/c6bbb28d-198a-60ad-0e41-928f4113ac94.png)

### Run Commandを介してAWS-RunPatchBaselineでインスタンスにパッチを適用する
Run Command画面からRun Commandを選択します。
![AWS_Systems_Manager_-_Run_Command.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/1201488a-632f-1542-62be-d48aa06ee680.png)

各種パラメータは以下を設定します。記載されていないパラメータはデフォルトの設定でOK

- コマンドドキュメント
    - AWS-RunPatchBaseline
- コマンドのパラメータ
    - Operation
        - Install
- ターゲット
    - インスタンスタグの指定
        - key
            - Workload
        - value
            - Test

![AWS_Systems_Manager_-_Run_Command.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/73bf3df0-a5fb-bb46-8123-97ff2a4774e1.png)

対象インスタンス(タグが`key=Workload,value=Test`の4つ)のRun Command処理が成功することを確認する。
![AWS_Systems_Manager_-_Run_Command.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/fe501af3-a7f5-6a23-ba63-a86e12b3f138.png)

## メンテナンスウィンドウの作成と自動運用アクティビティのスケジュール
### メンテナンスウィンドウ実行用のIAMリソース作成
Systems Managerがユーザーに代わってメンテナンスウィンドウでタスクを実行できるようにIAMリソースを作成します。
以下の設定のIAMロールを作成します。

- ロール名
    - SSMMaintenanceWindowRole
- ロールの説明
    - Role for Amazon SSMMaintenanceWindow
- アタッチポリシー
    - AmazonSSMMaintenanceWindowRole 

作成後に信頼関係を以下に変更する。

```
{
   "Version":"2012-10-17",
   "Statement":[
      {
         "Sid":"",
         "Effect":"Allow",
         "Principal":{
            "Service":[
               "ec2.amazonaws.com",
               "ssm.amazonaws.com",
               "sns.amazonaws.com"
            ]
         },
         "Action":"sts:AssumeRole"
      }
   ]
}

```

### メンテナンスウィンドウの作成
メンテナンスウィンドウ画面からメンテナンスウィンドウの作成を行う。
![AWS_Systems_Manager_-_Maintenance_Windows.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/3b926948-a735-689b-09a5-97597ca187ca.png)

各種パラメータは以下を設定します。記載されていないパラメータはデフォルト設定でOK

- メンテナンスウィンドウの詳細の入力
    - 名前
        - PatchTestWorkloadWebServers
    - スケジュールを指定
        - 期間
            - 1時間
        - タスクの開始を停止
            - 0

### パッチメンテナンスウィンドウへのターゲットの割り当て
作成したメンテナンスウィンドウに対してターゲットの割り当てを行います。ウィンドウIDの詳細画面からターゲットの登録を選択します。
![AWS_Systems_Manager_-_Maintenance_Windows.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/e00a9fd4-569e-0415-f577-958ed6f66cb7.png)

各種パラメータは以下を設定します。記載されていないパラメータはデフォルト設定でOK

- メンテナンスウィンドウのターゲットの詳細
    - 名前
        - TestWebServers
- ターゲット
    - Target selection
        - `key=Workload,value=Test`
        - `key=InstanceRole,value=WebServer`

### パッチメンテナンスウィンドウへのタスクの割り当て
作成したメンテナンスウィンドウに対してタスクの割り当てを行います。ウィンドウIDの詳細画面からrun commandタスクの登録を選択します。
![AWS_Systems_Manager_-_Maintenance_Windows.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/656d5dc7-fc51-3e8e-1089-0fc072e9fcb9.png)

各種パラメータは以下を設定します。記載されていないパラメータはデフォルト設定でOK

- メンテナンスウィンドウのタスクの詳細
    - 名前
        - PatchTestWorkloadWebServers
- コマンドのドキュメント
    - AWS-RunPatchBaseline
- ターゲット
    - 登録済みターゲットグループの選択
        - 先ほど登録したターゲットのID
- レート制御
    - 並行性
        - 1
    - 誤差閾値
        - 1
- IAMサービスロール
    - カスタムサービスロールを使用する
        - SSMMaintenanceWindowRole
- パラメーター
    - Operation
        - Install

### メンテナンスウィンドウの実行の確認
メンテナンスウィンドウの実行時間になったら、履歴から実行結果を確認し、ステータスが成功となっていることを確認する。
![AWS_Systems_Manager_-_Maintenance_Windows.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/9cdd03cd-4bfd-8617-033f-c9cf47dc320c.png)

### リソース削除
最後に作成したリソースを削除します。

- CloudFormationスタック
    - OELabStack1
    - OELabStack2
- インベントリ
    - Inventory-Association
- メンテナンスウィンドウ
    - PatchTestWorkloadWebServers
- パッチベースライン
    - AmazonLinuxSecAndNonSecBaseline

# おわりに
各サービスの関係性さえ理解すれば、比較的簡単にパッチマネージャーでパッチ適用を自動化することは可能ですが、**パッチ適用フローを十分に精査する必要がある**と思います。実際のシステムに取り入れるのであれば、開発環境でまずは適用し、問題がなければ本番環境に適用するようなフローになると思います。また、**どの分類のどの重要度までのパッチを適用すれば良いかも考慮する必要があります。**ここら辺については従来通りエンジニア側で考える必要がありますが、パッチ適用作業自体を自動化できることを大きなメリットとなるため、機会があれば使っていきたいと思います。

# 参考

- [【AWS Systems Manager】パッチマネージャーの パッチベースライン と パッチグループ の概念を勉強する](https://dev.classmethod.jp/articles/patchmanager-baseline-and-group/)
- [AWS Patch Managerの備忘録](https://goodbyegangster.hatenablog.com/entry/2019/07/25/203319)