EC2 Systems ManagerでLinuxのパッチを適用してみた

# 

Linuxの環境に対してPatchを適用できるようになったようです。

[Amazon EC2 Systems Manager Now Supports Linux Patching](https://aws.amazon.com/jp/about-aws/whats-new/2017/07/amazon-ec2-systems-manager-now-supports-linux-patching/)

```
Previously, Patch Manager only supported Windows managed instances. 
If you wanted to patch Linux managed instances, you needed to use in-house or Linux distribution-specific tools. 
Now, you can manage Linux patches for AWS and on-premises managed instances using the same tool as you do for Windows. 
Just like with Windows patching, Patch Manager lets you automate your Linux patching process using defined auto-approval rules, which lets you only deploy vetted packages. 
This also gives you a single patch compliance view for both your Linux and Windows managed instances.
```

これまで、Windows Serverに対してはメンテナンスウィンドウやパッチベースラインを利用してパッチの適用ができていましたが、Linuxでも同じ要領でパッチの適用ができるようになったようです。

これは時間の節約ができそうです。早速試します。

# Management Consoleを確認

## ドキュメント

"AWS-RunPatchBaseline"なるドキュメントが提供されていました。

![EC2 Management Console_2.png](https://qiita-image-store.s3.amazonaws.com/0/36230/9bcda0a3-8cb9-59e6-5f78-5e0d49f44fb7.png)

## パッチベースライン

Amazon Linux、RHEL、Ubuntu用のパッチベースラインが提供されていました。

![EC2 Management Console.png](https://qiita-image-store.s3.amazonaws.com/0/36230/cabc2a99-db8d-34b7-7958-1d86e0e403a3.png)


# 使ってみる

東京リージョンで試します。

```bash:コマンド
export AWS_DEFAULT_REGION="ap-northeast-1"
```

## メンテナンスウィンドウの作成

まず、メンテナンスウィンドウを作成します。（これまでと同じです）

```bash:コマンド
aws ssm create-maintenance-window \
    --name "LinuxPatching" \
    --no-allow-unassociated-targets \
    --schedule "cron(0 10 10 ? * SAT *)" \
    --duration 2 \
    --cutoff 1
```

```json:結果
{
    "WindowId": "mw-xxxxxxxxxxxxxxxxx"
}
```

## ターゲットとなるLinuxインスタンスの作成

今回はAmazon Linuxを用意します。

ログインするのがめんどいので、UserDataでSSM Agentをインストールします。

また、インターネットにアクセス可能なSubnetに配置しましょう。また、適切なインスタンスプロファイルを設定します。

EC2 Systems Managerの動作要件は、以下のドキュメントを確認してください。



```bash:UserData
#!/bin/bash
cd /tmp
sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
```

## ターゲットの指定

ここもこれまでの手順と変わりません。

```bash:コマンド
MAINTENANCE_WINDOW_ID="mw-xxxxxxxxxxxxxxxxx"
INSTANCE_ID="i-xxxxxxxxxxxxxxxxx"
```

```bash:コマンド
aws ssm register-target-with-maintenance-window \
    --window-id ${MAINTENANCE_WINDOW_ID} \
    --resource-type "INSTANCE" \
    --targets "Key=InstanceIds,Values=${INSTANCE_ID}"
```

```json:結果
{
    "WindowTargetId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

## （割愛）パッチベースラインの作成

今回はデフォルトのパッチベースラインと使って動作を確認します。

パッチベースラインの一覧を確認します。

```bash:コマンド
aws ssm describe-patch-baselines
```

```json:結果
{
    "BaselineIdentities": [
        {
            "BaselineName": "AWS-AmazonLinuxDefaultPatchBaseline",
            "DefaultBaseline": true,
            "BaselineDescription": "Default Patch Baseline for Amazon Linux Prov                                                                                                                                                            ided by AWS.",
            "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline                                                                                                                                                            /pb-0221829c157d721d8",
            "OperatingSystem": "AMAZON_LINUX"
        },
        {
            "BaselineName": "AWS-DefaultPatchBaseline",
            "DefaultBaseline": true,
            "BaselineDescription": "Default Patch Baseline Provided by AWS.",
            "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline                                                                                                                                                            /pb-04ba050f612fba3a6",
            "OperatingSystem": "WINDOWS"
        },
        {
            "BaselineName": "AWS-RedHatDefaultPatchBaseline",
            "DefaultBaseline": true,
            "BaselineDescription": "Default Patch Baseline for Redhat Enterprise                                                                                                                                                             Linux Provided by AWS.",
            "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline                                                                                                                                                            /pb-0adf5cb7136a2984d",
            "OperatingSystem": "REDHAT_ENTERPRISE_LINUX"
        },
        {
            "BaselineName": "AWS-UbuntuDefaultPatchBaseline",
            "DefaultBaseline": true,
            "BaselineDescription": "Default Patch Baseline for Ubuntu Provided b                                                                                                                                                            y AWS.",
            "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline                                                                                                                                                            /pb-0ec96a11368349171",
            "OperatingSystem": "UBUNTU"
        }
    ]
}
```

Amazon Linux用のパッチベースラインを確認します。

```bash:コマンド
aws ssm get-patch-baseline \
    --baseline-id arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline/pb-0221829c157d721d8
```

```json:結果
{
    "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline/pb-0221829c157d721d8",
    "Name": "AWS-AmazonLinuxDefaultPatchBaseline",
    "PatchGroups": [],
    "RejectedPatches": [],
    "GlobalFilters": {
        "PatchFilters": [
            {
                "Values": [
                    "AmazonLinux2012.03",
                    "AmazonLinux2012.09",
                    "AmazonLinux2013.03",
                    "AmazonLinux2013.09",
                    "AmazonLinux2014.03",
                    "AmazonLinux2014.09",
                    "AmazonLinux2015.03",
                    "AmazonLinux2015.09",
                    "AmazonLinux2016.03",
                    "AmazonLinux2016.09",
                    "AmazonLinux2017.03",
                    "AmazonLinux2017.09"
                ],
                "Key": "PRODUCT"
            }
        ]
    },
    "ApprovalRules": {
        "PatchRules": [
            {
                "PatchFilterGroup": {
                    "PatchFilters": [
                        {
                            "Values": [
                                "Security"
                            ],
                            "Key": "CLASSIFICATION"
                        },
                        {
                            "Values": [
                                "Critical",
                                "Important"
                            ],
                            "Key": "SEVERITY"
                        }
                    ]
                },
                "ApproveAfterDays": 7,
                "ComplianceLevel": "UNSPECIFIED"
            },
            {
                "PatchFilterGroup": {
                    "PatchFilters": [
                        {
                            "Values": [
                                "Bugfix"
                            ],
                            "Key": "CLASSIFICATION"
                        }
                    ]
                },
                "ApproveAfterDays": 7,
                "ComplianceLevel": "UNSPECIFIED"
            }
        ]
    },
    "ModifiedDate": 1499203527.709,
    "CreatedDate": 1499203527.709,
    "ApprovedPatchesComplianceLevel": "UNSPECIFIED",
    "OperatingSystem": "AMAZON_LINUX",
    "ApprovedPatches": [],
    "Description": "Default Patch Baseline for Amazon Linux Provided by AWS."
}
```

## タスクを指定

使用するドキュメントを確認します。

```bash:コマンド
DOCUMENT_NAME="AWS-RunPatchBaseline"

aws ssm describe-document \
    --name ${DOCUMENT_NAME}
```

```json:結果
{
    "Document": {
        "Status": "Active",
        "Hash": "d5c29590f323c144ce0338b8424970e2284f780b404dc164b2bc96dae5415218",
        "Name": "AWS-RunPatchBaseline",
        "Parameters": [
            {
                "Type": "String",
                "Name": "Operation",
                "Description": "(Required) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline."
            },
            {
                "DefaultValue": "",
                "Type": "String",
                "Name": "SnapshotId",
                "Description": "(Optional) The snapshot ID to use to retrieve a patch baseline snapshot."
            }
        ],
        "DocumentType": "Command",
        "PlatformTypes": [
            "Linux"
        ],
        "DocumentVersion": "1",
        "HashType": "Sha256",
        "CreatedDate": 1499451553.857,
        "Owner": "Amazon",
        "SchemaVersion": "2.2",
        "DefaultVersion": "1",
        "LatestVersion": "1",
        "Description": "Scans for or installs patches from a patch baseline to a Linux or Windows operating system."
    }
}
```

タスクを設定する際には、IAMロールを指定する必要があります。

[Configuring Roles and Permissions for Maintenance Windows](http://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-maintenance-permissions.html)

```bash:コマンド
ROLE_ARN_FOR_MAINTENANCE_WINDOW="arn:aws:iam::XXXXXXXXXXXX:role/AmazonSSMMaintenanceWindowRole"
```

また、実行結果を格納するS3バケットも予め用意しておきます。

```bash:コマンド
BUCKET_NAME="XXXXXXXX"
PREFIX="logs"

PATCH_BASELINE_LOGGING_FILE_NAME="patch_baseline_logging.json"

cat << EOF > ${PATCH_BASELINE_LOGGING_FILE_NAME}
{
    "S3BucketName": "${BUCKET_NAME}",
    "S3KeyPrefix": "${PREFIX}",
    "S3Region": "${AWS_DEFAULT_REGION}"
}
EOF
```


その他のパラメーターを確認し、タスクを登録します。

```bash:コマンド
PATCH_BASELINE_PARAMETER_FILE_NAME="patch_baseline_parameter.json"

cat << EOF > ${PATCH_BASELINE_PARAMETER_FILE_NAME}
{
    "Operation": {
        "Values": [
            "Install"
        ]
    }
}
EOF
```

```bash:コマンド
TASK_TYPE="RUN_COMMAND"
PRIORITY="1"
MAX_COCCURRENCY="1"
MAX_ERRORS="1"
```

```bash:コマンド
aws ssm register-task-with-maintenance-window \
    --window-id ${MAINTENANCE_WINDOW_ID} \
    --targets "Key=InstanceIds,Values=${INSTANCE_ID}" \
    --task-arn ${DOCUMENT_NAME} \
    --service-role-arn ${ROLE_ARN_FOR_MAINTENANCE_WINDOW} \
    --task-type ${TASK_TYPE} \
    --task-parameters file://${PATCH_BASELINE_PARAMETER_FILE_NAME} \
    --priority ${PRIORITY} \
    --max-concurrency ${MAX_COCCURRENCY} \
    --max-errors ${MAX_ERRORS} \
    --logging-info file://${PATCH_BASELINE_LOGGING_FILE_NAME}
```

```json:結果
{
    "WindowTaskId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

## 実行結果の確認

メンテナンスウィンドウで指定した時刻になるまで待ちます。

細かいところをとばして、S3に出力された実行結果を確認します。

```text:結果
/usr/bin/python
Loaded plugins: priorities, update-motd, upgrade-helper
Resolving Dependencies
--> Running transaction check
---> Package python26-requests.noarch 0:1.2.3-5.10.amzn1 will be installed
--> Processing Dependency: python(abi) = 2.6 for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Processing Dependency: python26-urllib3 >= 1.7 for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Processing Dependency: python26(dist-packages) for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Processing Dependency: python26-chardet for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Processing Dependency: python26-ordereddict for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Running transaction check
---> Package python26.x86_64 0:2.6.9-2.88.amzn1 will be installed
--> Processing Dependency: libpython2.6.so.1.0()(64bit) for package: python26-2.6.9-2.88.amzn1.x86_64
---> Package python26-chardet.noarch 0:2.0.1-7.7.amzn1 will be installed
---> Package python26-urllib3.noarch 0:1.8.2-1.5.amzn1 will be installed
--> Processing Dependency: python26-backports-ssl_match_hostname for package: python26-urllib3-1.8.2-1.5.amzn1.noarch
--> Processing Dependency: python26-six for package: python26-urllib3-1.8.2-1.5.amzn1.noarch
--> Running transaction check
---> Package python26-backports-ssl_match_hostname.noarch 0:3.4.0.2-1.12.amzn1 will be installed
--> Processing Dependency: python26-backports for package: python26-backports-ssl_match_hostname-3.4.0.2-1.12.amzn1.noarch
---> Package python26-libs.x86_64 0:2.6.9-2.88.amzn1 will be installed
---> Package python26-six.noarch 0:1.8.0-1.23.amzn1 will be installed
--> Running transaction check
---> Package python26-backports.x86_64 0:1.0-3.14.amzn1 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package                              Arch   Version            Repository
                                                                           Size
================================================================================
Installing:
 python26-requests                    noarch 1.2.3-5.10.amzn1   amzn-main  94 k
Installing for dependencies:
 python26                             x86_64 2.6.9-2.88.amzn1   amzn-main 5.8 M
 python26-backports                   x86_64 1.0-3.14.amzn1     amzn-main 5.2 k
 python26-backports-ssl_match_hostname
                                      noarch 3.4.0.2-1.12.amzn1 amzn-main  12 k
 python26-chardet                     noarch 2.0.1-7.7.amzn1    amzn-main 377 k
 python26-libs                        x86_64 2.6.9-2.88.amzn1   amzn-main 697 k
 python26-six                         noarch 1.8.0-1.23.amzn1   amzn-main  31 k
 python26-urllib3                     noarch 1.8.2-1.5.amzn1    amzn-main  98 k

Transaction Summary
================================================================================
Install  1 Package (+7 Dependent packages)

Total download size: 7.0 M
Installed size: 22 M
Downloading packages:
--------------------------------------------------------------------------------
Total                                              1.9 MB/s | 7.0 MB  00:03     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : python26-2.6.9-2.88.amzn1.x86_64                             1/8 
  Installing : python26-libs-2.6.9-2.88.amzn1.x86_64                        2/8 
  Installing : python26-chardet-2.0.1-7.7.amzn1.noarch                      3/8 
  Installing : python26-six-1.8.0-1.23.amzn1.noarch                         4/8 
  Installing : python26-backports-1.0-3.14.amzn1.x86_64                     5/8 
  Installing : python26-backports-ssl_match_hostname-3.4.0.2-1.12.amzn1.n   6/8 
  Installing : python26-urllib3-1.8.2-1.5.amzn1.noarch                      7/8 
  Installing : python26-requests-1.2.3-5.10.amzn1.noarch                    8/8 
  Verifying  : python26-requests-1.2.3-5.10.amzn1.noarch                    1/8 
  Verifying  : python26-chardet-2.0.1-7.7.amzn1.noarch                      2/8 
  Verifying  : python26-urllib3-1.8.2-1.5.amzn1.noarch                      3/8 
  Verifying  : python26-libs-2.6.9-2.88.amzn1.x86_64                        4/8 
  Verifying  : python26-six-1.8.0-1.23.amzn1.noarch                         5/8 
  Verifying  : python26-2.6.9-2.88.amzn1.x86_64                             6/8 
  Verifying  : python26-backports-1.0-3.14.amzn1.x86_64                     7/8 
  Verifying  : python26-backports-ssl_match_hostname-3.4.0.2-1.12.amzn1.n   8/8 

Installed:
  python26-requests.noarch 0:1.2.3-5.10.amzn1                                   

Dependency Installed:
  python26.x86_64 0:2.6.9-2.88.amzn1                                            
  python26-backports.x86_64 0:1.0-3.14.amzn1                                    
  python26-backports-ssl_match_hostname.noarch 0:3.4.0.2-1.12.amzn1             
  python26-chardet.noarch 0:2.0.1-7.7.amzn1                                     
  python26-libs.x86_64 0:2.6.9-2.88.amzn1                                       
  python26-six.noarch 0:1.8.0-1.23.amzn1                                        
  python26-urllib3.noarch 0:1.8.2-1.5.amzn1                                     

Complete!
07/08/2017 10:30:55 root [INFO]: Attempting to acquire instance information from ssm-cli.
07/08/2017 10:30:55 root [INFO]: ssm-cli path is: /usr/bin/ssm-cli.
07/08/2017 10:30:55 root [INFO]: Instance metadata from ssm-cli is: {"instance-id":"i-xxxxxxxxxxxxxxxxx","region":"ap-northeast-1","release-version":"2.0.847.0"}.
07/08/2017 10:30:55 urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): s3.dualstack.ap-northeast-1.amazonaws.com
07/08/2017 10:30:56 urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): s3.dualstack.ap-northeast-1.amazonaws.com
07/08/2017 10:30:57 root [INFO]: Attempting to acquire instance information from ssm-cli.
07/08/2017 10:30:57 root [INFO]: ssm-cli path is: /usr/bin/ssm-cli.
07/08/2017 10:30:57 root [INFO]: Instance metadata from ssm-cli is: {"instance-id":"i-xxxxxxxxxxxxxxxxx","region":"ap-northeast-1","release-version":"2.0.847.0"}.
07/08/2017 10:30:57 root [INFO]: Operation type: Install.
07/08/2017 10:30:57 root [INFO]: Snapshot ID: e62016f7-257d-4aee-b520-b58b10ad3cdd.
07/08/2017 10:30:57 root [INFO]: Instance ID: i-xxxxxxxxxxxxxxxxx.
07/08/2017 10:30:57 root [INFO]: Region ID: ap-northeast-1.
07/08/2017 10:30:57 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTP connection (1): 169.254.169.254
07/08/2017 10:30:57 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTP connection (1): 169.254.169.254
07/08/2017 10:30:57 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): ssm.ap-northeast-1.amazonaws.com
07/08/2017 10:30:57 root [INFO]: Product: AmazonLinux2017.03.
07/08/2017 10:30:57 root [INFO]: Snapshot download URL: https://patch-baseline-snapshot-ap-northeast-1.s3-ap-northeast-1.amazonaws.com/325e6910d69bd8861bea653821b277cecf2df85952414e32ec904b9a32a4a88b-788063364413/AMAZON_LINUX-e62016f7-257d-4aee-b520-b58b10ad3cdd?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20170708T103057Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=AKIAILTSCHNHVBZOKOSA%2F20170708%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Signature=833c5f22664d48aa9b6fe5a4db9d04ee878293efb56d3bd581e1e8f0ce421de7.
07/08/2017 10:30:57 urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): patch-baseline-snapshot-ap-northeast-1.s3-ap-northeast-1.amazonaws.com
07/08/2017 10:30:57 root [INFO]: Patch baseline: {u'baselineId': u'pb-0221829c157d721d8', u'name': u'AWS-AmazonLinuxDefaultPatchBaseline', u'modifiedTime': 1499203527.709, u'description': u'Default Patch Baseline for Amazon Linux Provided by AWS.', u'rejectedPatches': [], u'globalFilters': {u'filters': [{u'values': [u'AmazonLinux2012.03', u'AmazonLinux2012.09', u'AmazonLinux2013.03', u'AmazonLinux2013.09', u'AmazonLinux2014.03', u'AmazonLinux2014.09', u'AmazonLinux2015.03', u'AmazonLinux2015.09', u'AmazonLinux2016.03', u'AmazonLinux2016.09', u'AmazonLinux2017.03', u'AmazonLinux2017.09'], u'key': u'PRODUCT'}]}, u'approvalRules': {u'rules': [{u'filterGroup': {u'filters': [{u'values': [u'Security'], u'key': u'CLASSIFICATION'}, {u'values': [u'Critical', u'Important'], u'key': u'SEVERITY'}]}, u'complianceLevel': u'UNSPECIFIED', u'approveAfterDays': 7}, {u'filterGroup': {u'filters': [{u'values': [u'Bugfix'], u'key': u'CLASSIFICATION'}]}, u'complianceLevel': u'UNSPECIFIED', u'approveAfterDays': 7}]}, u'createdTime': 1499203527.709, u'approvedPatchesComplianceLevel': u'UNSPECIFIED', u'operatingSystem': u'AMAZON_LINUX', u'approvedPatches': [], u'accountId': u'486716784251'}.
07/08/2017 10:30:57 root [INFO]: Patch group: .
07/08/2017 10:30:57 root [INFO]: Operating system: AMAZON_LINUX.
07/08/2017 10:30:57 root [WARNING]: Unable to gain necessary access for possible kernel updates, code: 1.
07/08/2017 10:30:58 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTP connection (1): 169.254.169.254
07/08/2017 10:30:58 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTP connection (1): 169.254.169.254
Loaded plugins: priorities, update-motd, upgrade-helper
07/08/2017 10:30:58 root [INFO]: No updates, skipping.
Loaded plugins: priorities, update-motd, upgrade-helper
07/08/2017 10:30:59 root [INFO]: 
Patch compliance initialized with instance ID:i-xxxxxxxxxxxxxxxxx, 
baseline ID: pb-0221829c157d721d8, snapshot ID: e62016f7-257d-4aee-b520-b58b10ad3cdd, patch group: ,
start time: 2017-07-08 10:30:58.177869, end time: 2017-07-08 10:30:59.590999, upload NA compliance: False
        
07/08/2017 10:30:59 root [INFO]: Start to upload patch compliance.
07/08/2017 10:30:59 root [INFO]: Summary: {'ContentHash': 'b71836e461121012e37c8f25eb2846ade95a267c9fc237d5e5af36deaf8048f8', 'TypeName': 'AWS:PatchSummary', 'SchemaVersion': '1.0', 'CaptureTime': '2017-07-08T10:30:59Z', 'Content': [{'OperationStartTime': '2017-07-08T10:30:58Z', 'FailedCount': '0', 'PatchGroup': u'', 'OperationType': u'Install', 'BaselineId': u'pb-0221829c157d721d8', 'MissingCount': '0', 'NotApplicableCount': '249', 'OperationEndTime': '2017-07-08T10:30:59Z', 'InstalledOtherCount': '377', 'SnapshotId': u'e62016f7-257d-4aee-b520-b58b10ad3cdd', 'InstalledCount': '20'}]}
07/08/2017 10:30:59 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): ssm.ap-northeast-1.amazonaws.com
07/08/2017 10:31:00 root [INFO]: Upload complete.
07/08/2017 10:31:00 root [INFO]: Report upload is successful.
```

# 感想

動作確認をどうするのかとか、適用を除外したい／別途ラインでは該当しないけど適用したいなどの例外処理（パッチベースラインで設定可能）をどうするのかなど、予め考えていくことはありますが、できるだけ仕事しなくていいようにがんばりましょう！