[JAWS-UG CLI] Amazon EC2 Systems Manager 入門 (2) コマンドの実行

# この記事について

[JAWS-UG CLI専門支部 #81 Amazon EC2 Systems Manager 入門](https://jawsug-cli.doorkeeper.jp/events/57576)で実施するハンズオン用の手順書です。


# 前提条件

## 必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

- EC2 Systems Manager(ssm)のフルコントロール権限
- EC2のフルコントロール権限
- CloudFormationの関するフルコントロール権限
- IAMの関するフルコントロール権限
- Configの関するフルコントロール権限
- S3の関するフルコントロール権限
- SNSの関するフルコントロール権限


# 0. 準備

## 0.1. リージョンを指定

ハンズオンでは東京リージョンを利用しますが、必要に応じて他のリージョンに変更してご利用ください。（東京リージョンを他の検証目的で利用している、など）

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

## 0.2. 資格情報を確認

```bash:コマンド
aws configure list
```

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

```text:結果
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************QSAA         iam-role
secret_key     ****************c1xY         iam-role
    region                us-west-2              env    AWS_DEFAULT_REGION
```

## 0.3. バージョン確認

```bash:コマンド
aws --version
```

```text:結果
（可能な限り最新版を利用しましょう）
```

## 0.4. バージョンアップ（必要に応じて）

```bash:コマンド
sudo pip install -U awscli
```

# 1. マネージドインスタンスの確認

作成したEC2インスタンスがマネージドインスタンスとして認識されていることを確認します。

SSM Agentの動作要件は以下の通りです。

http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/systems-manager-prereqs.html

```bash:コマンド
aws ssm describe-instance-information \
    --query "InstanceInformationList[?InstanceId==\`${INSTANCE_ID}\`]"
```

```json:結果
[
    {
        "IsLatestVersion": false,
        "ComputerName": "WIN-NU3L7UBOQD9.WORKGROUP",
        "PingStatus": "Online",
        "InstanceId": "i-*****************",
        "IPAddress": "10.0.0.111",
        "ResourceType": "EC2Instance",
        "AgentVersion": "2.0.562.0",
        "PlatformVersion": "6.3.9600",
        "PlatformName": "Microsoft Windows Server 2012 R2 Standard",
        "PlatformType": "Windows",
        "LastPingDateTime": 1490878364.139
    }
]
```

正常に認識されていない場合、EC2インスタンスを再起動してください。

それでも正常に認識されてない場合には、「インスタンスプロフィルがアタッチされていること」「IAMロール（インスタンスプロファイル）に適切なポリシーがアタッチされていること」を確認してください。


# 2. AWS管理コマンドを実行する

**手順書の検証時点でSSM Agentにバグがあるもようで、アップデートを実施すると後述するソフトウェアインベントリの収集が正常に機能しない可能性があります。この手順は、リソースの削除前に実施してみてください。**

EC2Configは、Windows ServerのAMIに含まれる管理ツールです。

詳細については、以下のドキュメントを参照してください。

[EC2Config サービスを使用した Windows インスタンスの設定](http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/UsingConfig_WinAMI.html)

## 2.1. EC2Configを更新する

### ドキュメント名の指定

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

### ドキュメントの確認

ドキュメントの実行時に指定できるパラメータを確認できます。

```bash:コマンド
aws ssm describe-document \
    --name ${DOCUMENT_NAME}
```

```json:結果
{
    "Document": {
        "Status": "Active",
        "Hash": "b45b8ffa5ac627fcc8c0e555678bb317c523f1ae847ef0de25d6115c8d729d6c",
        "Name": "AWS-UpdateEC2Config",
        "Parameters": [
            {
                "DefaultValue": "",
                "Type": "String",
                "Name": "version",
                "Description": "(Optional) A specific version of the EC2Config service to install. If not specified, the service will be updated to the latest version."
            },
            {
                "DefaultValue": "false",
                "Type": "String",
                "Name": "allowDowngrade",
                "Description": "(Optional) Allow the EC2Config service to be downgraded to an earlier version. If set to false, the service can be upgraded to newer versions only (default). If set to true, specify the earlier version."
            }
        ],
        "DocumentType": "Command",
        "PlatformTypes": [
            "Windows"
        ],
        "DocumentVersion": "1",
        "HashType": "Sha256",
        "CreatedDate": 1487117202.214,
        "Owner": "Amazon",
        "SchemaVersion": "1.2",
        "DefaultVersion": "1",
        "LatestVersion": "1",
        "Description": "Update the EC2Config service to the latest version or specify an older version."
    }
}
```

ドキュメントで実行される処理の内容を確認できます。

詳細は、以下のドキュメントを確認してください。

[Systems Manager Documents](http://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-ssm-docs.html)

```bash:コマンド
aws ssm get-document \
    --name ${DOCUMENT_NAME}
```

```json:結果
{
    "Content": "{\n    \"schemaVersion\": \"1.2\",\n    \"description\": \"Update the EC2Config service to the latest version or specify an older version.\",\n    \"parameters\": {\n        \"version\": {\n            \"default\": \"\",\n            \"description\": \"(Optional) A specific version of the EC2Config service to install. If not specified, the service will be updated to the latest version.\",\n            \"type\": \"String\"\n        },\n        \"allowDowngrade\": {\n            \"default\": \"false\",\n            \"description\": \"(Optional) Allow the EC2Config service to be downgraded to an earlier version. If set to false, the service can be upgraded to newer versions only (default). If set to true, specify the earlier version.\",\n            \"type\": \"String\",\n            \"allowedValues\": [\n                \"true\",\n                \"false\"\n            ]\n        }\n    },\n    \"runtimeConfig\": {\n        \"aws:updateAgent\": {\n            \"properties\": {\n                \"agentName\": \"Ec2Config\",\n                \"source\": \"https://s3.ap-northeast-1.amazonaws.com/aws-ssm-ap-northeast-1/manifest.json\",\n                \"allowDowngrade\": \"{{ allowDowngrade }}\",\n                \"targetVersion\": \"{{ version }}\"\n            }\n        }\n    }\n}\n",
    "Name": "AWS-UpdateEC2Config"
}
```

### パラメータを確認

```bash:コマンド
cat << ETX

    INSTANCE_ID: ${INSTANCE_ID}
    ROLE_ARN_FOR_NOTIFICATION: ${ROLE_ARN_FOR_NOTIFICATION}
    SNS_TOPIC_ARN_FOR_EC2: ${SNS_TOPIC_ARN_FOR_EC2}

ETX
```

```text:結果

    INSTANCE_ID: i-*****************
    ROLE_ARN_FOR_NOTIFICATION: arn:aws:iam::************:role/NotificationForEC2SystemsManager
    SNS_TOPIC_ARN_FOR_EC2: arn:aws:sns:ap-northeast-1:************:ec2-topic

```

### コマンドの実行

※マネジメントコンソールの実行画面でコマンドを生成することも可能です。

```bash:コマンド
aws ssm send-command \
    --document-name "${DOCUMENT_NAME}" \
    --instance-ids ${INSTANCE_ID} \
    --parameters '{"allowDowngrade":["false"]}' \
    --timeout-seconds 600 \
    --service-role-arn ${ROLE_ARN_FOR_NOTIFICATION} \
    --notification-config NotificationArn="${SNS_TOPIC_ARN_FOR_EC2}",NotificationEvents="Success",NotificationType="Command"
```

```json:結果
{
    "Command": {
        "Comment": "",
        "Status": "Pending",
        "MaxErrors": "0",
        "Parameters": {
            "allowDowngrade": [
                "false"
            ]
        },
        "ExpiresAfter": 1490879945.768,
        "ServiceRole": "arn:aws:iam::************:role/NotificationForEC2SystemsManager",
        "DocumentName": "AWS-UpdateEC2Config",
        "TargetCount": 1,
        "OutputS3BucketName": "",
        "NotificationConfig": {
            "NotificationArn": "arn:aws:sns:ap-northeast-1:************:ec2-topic",
            "NotificationEvents": [
                "Success"
            ],
            "NotificationType": "Command"
        },
        "CompletedCount": 0,
        "Targets": [],
        "StatusDetails": "Pending",
        "ErrorCount": 0,
        "OutputS3KeyPrefix": "",
        "RequestedDateTime": 1490879345.768,
        "CommandId": "********-****-****-****-************",
        "InstanceIds": [
            "i-*****************"
        ],
        "MaxConcurrency": "50"
    }
}
```

### 実行結果の確認

直近の1件の結果を表示します。

StatusがSuccessとなっています。

```bash:コマンド
aws ssm list-command-invocations \
    --query "sort_by(CommandInvocations,&RequestedDateTime)[-1]"
```

```json:結果
{
    "Comment": "",
    "Status": "Success",
    "CommandPlugins": [],
    "ServiceRole": "arn:aws:iam::************:role/NotificationForEC2SystemsManager",
    "InstanceId": "i-*****************",
    "DocumentName": "AWS-UpdateEC2Config",
    "NotificationConfig": {
        "NotificationArn": "arn:aws:sns:ap-northeast-1:************:ec2-topic",
        "NotificationEvents": [
            "All"
        ],
        "NotificationType": "Command"
    },
    "StatusDetails": "Success",
    "StandardOutputUrl": "",
    "StandardErrorUrl": "",
    "InstanceName": "",
    "CommandId": "********-****-****-****-************",
    "RequestedDateTime": 1490349229.375
}
```

### 実行結果の確認（SNS）

成功している場合、設定したメールアドレス宛にsuatusが"Success"となっているメールが送信されています。
受信されていることを確認してください。


## 2.2. 任意のPowerShellコマンドを実行する

### ドキュメント名の指定

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

### ドキュメントの確認

```bash:コマンド
aws ssm describe-document \
    --name ${DOCUMENT_NAME}
```

```json:結果
{
    "Document": {
        "Status": "Active",
        "Sha1": "6ed0a59dfeb7e40913899b2342aec27035a76167",
        "Hash": "6ed0a59dfeb7e40913899b2342aec27035a76167",
        "Name": "AWS-RunPowerShellScript",
        "Parameters": [
            {
                "Type": "StringList",
                "Name": "commands",
                "Description": "(Required) Specify the commands to run or the paths to existing scripts on the instance."
            },
            {
                "DefaultValue": "",
                "Type": "String",
                "Name": "workingDirectory",
                "Description": "(Optional) The path to the working directory on your instance."
            },
            {
                "DefaultValue": "3600",
                "Type": "String",
                "Name": "executionTimeout",
                "Description": "(Optional) The time in seconds for a command to be completed before it is considered to have failed. Default is 3600 (1 hour). Maximum is 28800 (8 hours)."
            }
        ],
        "DocumentType": "Command",
        "PlatformTypes": [
            "Windows",
            "Linux"
        ],
        "DocumentVersion": "1",
        "HashType": "Sha1",
        "CreatedDate": 1450125626.387,
        "Owner": "Amazon",
        "SchemaVersion": "1.2",
        "DefaultVersion": "1",
        "LatestVersion": "1",
        "Description": "Run a PowerShell script or specify the paths to scripts to run."
    }
}
```

```bash:コマンド
aws ssm get-document \
    --name ${DOCUMENT_NAME}
```

```json:結果
{
    "Content": "{\n    \"schemaVersion\":\"1.2\",\n    \"description\":\"Run a PowerShell script or specify the paths to scripts to run.\",\n    \"parameters\":{\n        \"commands\":{\n            \"type\":\"StringList\",\n            \"description\":\"(Required) Specify the commands to run or the paths to existing scripts on the instance.\",\n            \"minItems\":1,\n            \"displayType\":\"textarea\"\n        },\n        \"workingDirectory\":{\n            \"type\":\"String\",\n            \"default\":\"\",\n            \"description\":\"(Optional) The path to the working directory on your instance.\",\n            \"maxChars\":4096\n        },\n        \"executionTimeout\":{\n            \"type\":\"String\",\n            \"default\":\"3600\",\n            \"description\":\"(Optional) The time in seconds for a command to be completed before it is considered to have failed. Default is 3600 (1 hour). Maximum is 28800 (8 hours).\",\n            \"allowedPattern\":\"([1-9][0-9]{0,3})|(1[0-9]{1,4})|(2[0-7][0-9]{1,3})|(28[0-7][0-9]{1,2})|(28800)\"\n        }\n    },\n    \"runtimeConfig\":{\n        \"aws:runPowerShellScript\":{\n            \"properties\":[\n                {\n                    \"id\":\"0.aws:runPowerShellScript\",\n                    \"runCommand\":\"{{ commands }}\",\n                    \"workingDirectory\":\"{{ workingDirectory }}\",\n                    \"timeoutSeconds\":\"{{ executionTimeout }}\"\n                }\n            ]\n        }\n    }\n}\n",
    "Name": "AWS-RunPowerShellScript"
}
```

### コマンドの実行

```bash:コマンド
aws ssm send-command \
    --document-name ${DOCUMENT_NAME} \
    --instance-ids ${INSTANCE_ID} \
    --parameters '{"commands":["import-module servermanager","add-windowsfeature web-server -includeallsubfeature"],"executionTimeout":["3600"]}' \
    --timeout-seconds 600 \
    --output-s3-bucket-name ${BUCKET_NAME} \
    --service-role-arn ${ROLE_ARN_FOR_NOTIFICATION} \
    --notification-config NotificationArn="${SNS_TOPIC_ARN_FOR_EC2}",NotificationEvents="Success",NotificationType="Command"
```

### 実行結果の確認

直近の1件の結果を表示します。

```bash:コマンド
aws ssm list-command-invocations \
    --query "sort_by(CommandInvocations,&RequestedDateTime)[-1]"
```

```json:結果
{
    "Comment": "",
    "Status": "Success",
    "CommandPlugins": [],
    "ServiceRole": "arn:aws:iam::************:role/NotificationForEC2SystemsManager",
    "InstanceId": "i-*****************",
    "DocumentName": "AWS-RunPowerShellScript",
    "NotificationConfig": {
        "NotificationArn": "arn:aws:sns:ap-northeast-1:************:ec2-topic",
        "NotificationEvents": [
            "Success"
        ],
        "NotificationType": "Command"
    },
    "StatusDetails": "Success",
    "StandardOutputUrl": "https://s3-ap-northeast-1.amazonaws.com/ec2-systems-manager-************/********-****-****-****-************/i-*****************/awsrunPowerShellScript/0.aws%3ArunPowerShellScript/stdout",
    "StandardErrorUrl": "https://s3-ap-northeast-1.amazonaws.com/ec2-systems-manager-************/********-****-****-****-************/i-*****************/awsrunPowerShellScript/0.aws%3ArunPowerShellScript/errout",
    "InstanceName": "",
    "CommandId": "********-****-****-****-************",
    "RequestedDateTime": 1490879834.044
}
```

### 実行結果の確認（SNS）

成功している場合、設定したメールアドレス宛にsuatusが"InProgress"および"Success"となっている2通のメールが送信されています。


### 実行結果の確認（S3）

```bash:コマンド
COMMAND_ID=$(aws ssm list-command-invocations \
    --query "sort_by(CommandInvocations,&RequestedDateTime)[-1].CommandId" \
    --output text) \
    && echo ${COMMAND_ID}
```

```bash:コマンド
OBJECT_KEY=$(aws s3 ls ${BUCKET_NAME} \
    --recursive \
    | grep ${COMMAND_ID} \
    | grep "stdout" \
    | awk '{print $4}') \
    && echo ${OBJECT_KEY}
```

```text:結果
2017-03-24 10:54:12        330 ********-****-****-****-************/i-*************/awsrunPowerShellScript/0.awsrunPowerShellScript/stdout
```

環境によっては文字化けします。

必要に応じて、マネジメントコンソールからファイルをダウンロードして確認してください。

```bash:コマンド
aws s3 cp s3://${BUCKET_NAME}/${OBJECT_KEY} stdout && cat stdout
```

```text:結果
download: s3://ec2-systems-manager-************/********-****-****-****-************/i-*****************/awsrunPowerShellScript/0.awsrunPowerShellScript/stdout to ./stdout

Success Restart Needed Exit Code      Feature Result
------- -------------- ---------      --------------
True    No             Success        {ASP.NET 4.5, .NET Framework 3.5 (.NET...

（一部省略）

```

以上