LoginSignup
3
1

More than 5 years have passed since last update.

[JAWS-UG CLI] Amazon EC2 Systems Manager 入門 (1) 事前準備

Last updated at Posted at 2017-04-02

この記事について

JAWS-UG CLI専門支部 #81 Amazon EC2 Systems Manager 入門で実施するハンズオン用の手順書です。

前提条件

必要な権限

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

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

0. 準備

0.1. リージョンを指定

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

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

0.2. 資格情報を確認

コマンド
aws configure list

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

結果
      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. バージョン確認

コマンド
aws --version
結果
(可能な限り最新版を利用しましょう)

0.4. バージョンアップ(必要に応じて)

コマンド
sudo pip install -U awscli

1. 管理対象の構築

今回は、CloudFormationでVPCおよび管理対象となるEC2インスタンスを構築します。

1.1. KeyPairの作成

管理対象のEC2インスタンス用にKeyPairを作成します。

ただし、このハンズオンでは利用しない予定です。(ログインしない)

動作確認を目的としてログインする場合に利用してください。

※CloudFormationテンプレートの中でキーペアを指定しているので、必ず作成してください。

KeyPairの名前を指定

コマンド
AWS_ID=$(aws sts get-caller-identity \
    --query "Account" \
    --output text) \
    && echo ${AWS_ID}
コマンド
KEY_PAIR_NAME="${AWS_ID}_ec2systemsmanager"
KEY_MATERIAL_FILE_NAME=${KEY_PAIR_NAME}.pem

同名KeyPairの不存在を確認

コマンド
aws ec2 describe-key-pairs \
    --query "KeyPairs[?KeyName==\`${KEY_PAIR_NAME}\`]"
結果
[]

KeyPairの作成

コマンド
aws ec2 create-key-pair \
    --key-name ${KEY_PAIR_NAME} \
    --query "KeyMaterial" \
    --output text \
    > ~/.ssh/${KEY_MATERIAL_FILE_NAME} \
    && cat ~/.ssh/${KEY_MATERIAL_FILE_NAME}

KeyPairの存在を確認

コマンド
aws ec2 describe-key-pairs \
    --query "KeyPairs[?KeyName==\`${KEY_PAIR_NAME}\`]"
結果
[
    {
        "KeyName": "************_ec2systemsmanager",
        "KeyFingerprint": "**:**:**:**:**:**:**:**:**:**:f7:2e:00:16:92:68:df:05:98:d8"
    }
]

1.2. CloudFormation テンプレートの生成

テンプレートの作成

Public SubnetおよびそのSubnet上にWindows Serverをプロビジョニングするテンプレートを生成します。

コマンド
CF_TEMPLATE_FILE_NAME="ec2-systems-manager.yml"

利用するWindows ServerのAMIは、あえて最新でないものを指定しています。

コマンド
cat << EOF > ${CF_TEMPLATE_FILE_NAME}
AWSTemplateFormatVersion: "2010-09-09"
Description: JAWS-UG CLI EC2 Systems Manager Hands-on
Resources:
    VPC:
        Type: AWS::EC2::VPC
        Properties:
            CidrBlock: "10.0.0.0/16"
    IGW:
        Type: AWS::EC2::InternetGateway
    AttachIGW:
        Type: AWS::EC2::VPCGatewayAttachment
        Properties:
            VpcId:
                Ref: VPC
            InternetGatewayId:
                Ref: IGW
    PublicSubnetA:
        Type: AWS::EC2::Subnet
        Properties: 
            AvailabilityZone: 
                Fn::Select: 
                    - 0
                    - Fn::GetAZs: ""
            CidrBlock: "10.0.0.0/24"
            MapPublicIpOnLaunch: true
            VpcId: 
                Ref: VPC
    PublicRT:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId:
                Ref: VPC
    PublicDefaultRoute:
        Type: AWS::EC2::Route
        Properties: 
            DestinationCidrBlock: "0.0.0.0/0"
            GatewayId: 
                Ref: IGW
            RouteTableId: 
                Ref: PublicRT
    PublicSubnetARouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
            SubnetId:
                Ref: PublicSubnetA
            RouteTableId:
                Ref: PublicRT
    SecurityGroupForWindowsServer:
        Type: "AWS::EC2::SecurityGroup"
        Properties: 
            GroupDescription: String
            SecurityGroupEgress:
            - IpProtocol: -1
              CidrIp: 0.0.0.0/0
            VpcId:
                Ref: VPC
    InstanceForWindowsServer:
        Type: "AWS::EC2::Instance"
        Properties:
            ImageId: ami-1283ed75
            InstanceType: t2.micro
            SecurityGroupIds: 
                - Ref: SecurityGroupForWindowsServer
            SubnetId:
                Ref: PublicSubnetA
            KeyName: ${KEY_PAIR_NAME}
Outputs: 
    InstanceID: 
        Value: !Ref InstanceForWindowsServer

EOF

cat ${CF_TEMPLATE_FILE_NAME}

1.3. CloudFormation テンプレートの検証

コマンド
aws cloudformation validate-template \
    --template-body file://${CF_TEMPLATE_FILE_NAME}
結果
{
    "Description": "JAWS-UG CLI EC2 Systems Manager Hands-on",
    "Parameters": []
}

1.4. CloudFormation Stackの作成

CloudFormation Stack名の指定

コマンド
CF_STACK_NAME="EC2SystemsManager"

同名CloudFormation Stackの不存在を確認

コマンド
aws cloudformation describe-stacks \
    --query "Stacks[?StackName==\`${CF_STACK_NAME}\`]"
結果
[]

CloudFormation Stackの作成

コマンド
aws cloudformation create-stack \
    --stack-name ${CF_STACK_NAME} \
    --template-body file://${CF_TEMPLATE_FILE_NAME}
結果
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/EC2SystemsManager/********-****-****-****-************"
}

CloudFormation Stackの作成完了を待機

3分程度で作成が完了すると思います。

コマンド
aws cloudformation wait stack-create-complete \
    --stack-name ${CF_STACK_NAME}
結果
(返値無し)

CloudFormation Stackの存在を確認

"StackStatus"が"CREATE_COMPLETE"になっていることを確認します。

コマンド
aws cloudformation describe-stacks \
    --stack-name ${CF_STACK_NAME}
結果
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/EC2SystemsManager/********-****-****-****-************",
            "Description": "JAWS-UG CLI EC2 Systems Manager Hands-on",
            "Tags": [],
            "CreationTime": "2017-03-24T07:02:30.435Z",
            "StackName": "EC2SystemsManager",
            "NotificationARNs": [],
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false
        }
    ]
}

1.6. パラメータの確認

以降の手順で必要になるパラメータ(インスタンスID)を抽出します。

コマンド
OUTPUTKEY_INSTANCEID="InstanceID"
コマンド
INSTANCE_ID=$(aws cloudformation describe-stacks \
    --stack-name ${CF_STACK_NAME} \
    --query "Stacks[].Outputs[?OutputKey==\`${OUTPUTKEY_INSTANCEID}\`].OutputValue[]" \
    --output text) \
    && echo ${INSTANCE_ID}
結果
i-*****************

2. インスタンスプロファイルの作成

2.1. ロールの作成

ロール名の指定

コマンド
ROLE_NAME_FOR_INSTANCE_PROFILE="TestProfileForWindowsServer"

同名ロールの不存在を確認

コマンド
aws iam get-role \
    --role-name ${ROLE_NAME_FOR_INSTANCE_PROFILE}
結果
An error occurred (NoSuchEntity) when calling the GetRole operation: Role not found for TestProfileForWindowsServer

信頼関係を定義

コマンド
TRUST_POLICY_FILE='Trust-Policy-for-EC2SystemsManager.json'
コマンド
cat << EOF > ${TRUST_POLICY_FILE}
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "ec2.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF

cat ${TRUST_POLICY_FILE}
コマンド
jsonlint -q ${TRUST_POLICY_FILE}

パラメータを確認

コマンド
cat << ETX

    ROLE_NAME_FOR_INSTANCE_PROFILE: ${ROLE_NAME_FOR_INSTANCE_PROFILE}
    TRUST_POLICY_FILE: ${TRUST_POLICY_FILE}

ETX
結果

    ROLE_NAME_FOR_INSTANCE_PROFILE: TestProfileForWindowsServer
    TRUST_POLICY_FILE: Trust-Policy-for-EC2SystemsManager.json

ロールを作成

コマンド
aws iam create-role \
    --role-name ${ROLE_NAME_FOR_INSTANCE_PROFILE} \
    --assume-role-policy-document file://${TRUST_POLICY_FILE}
結果
{
    "Role": {
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Effect": "Allow",
                    "Principal": {
                        "Service": [
                            "ec2.amazonaws.com"
                        ]
                    }
                }
            ]
        },
        "RoleId": "*********************",
        "CreateDate": "2017-03-24T07:19:19.598Z",
        "RoleName": "TestProfileForWindowsServer",
        "Path": "/",
        "Arn": "arn:aws:iam::************:role/TestProfileForWindowsServer"
    }
}

ロールにアタッチするポリシーを指定

今回は、AWSが提供する管理ポリシーを利用します。

コマンド
POLICY_ARN_FOR_INSTANCE_PROFILE="arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"

ロールにポリシーをアタッチ

コマンド
aws iam attach-role-policy \
    --role-name ${ROLE_NAME_FOR_INSTANCE_PROFILE} \
    --policy-arn ${POLICY_ARN_FOR_INSTANCE_PROFILE}

ロールにポリシーがアタッチされたことを確認

コマンド
aws iam list-attached-role-policies \
    --role-name ${ROLE_NAME_FOR_INSTANCE_PROFILE}
結果
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonEC2RoleforSSM",
            "PolicyArn": "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
        }
    ]
}

2.2. インスタンスプロファイルの作成

インスタンスプロファイル名を指定

今回は、ロールと同じ名前を指定します。

コマンド
INSTANCE_PROFILE_NAME="TestProfileForWindowsServer"

同名インスタンスプロファイルの不存在を確認

コマンド
aws iam get-instance-profile \
    --instance-profile-name ${INSTANCE_PROFILE_NAME}
結果
An error occurred (NoSuchEntity) when calling the GetInstanceProfile operation: Instance Profile TestProfileForWindowsServer cannot be found.

インスタンスプロファイルを作成

コマンド
aws iam create-instance-profile \
    --instance-profile-name ${INSTANCE_PROFILE_NAME}
結果
{
    "InstanceProfile": {
        "InstanceProfileId": "*********************",
        "Roles": [],
        "CreateDate": "2017-03-24T07:27:18.313Z",
        "InstanceProfileName": "TestProfileForWindowsServer",
        "Path": "/",
        "Arn": "arn:aws:iam::************:instance-profile/TestProfileForWindowsServer"
    }
}

インスタンスプロファイルにロールを追加

コマンド
aws iam add-role-to-instance-profile \
    --instance-profile-name ${INSTANCE_PROFILE_NAME} \
    --role-name ${ROLE_NAME_FOR_INSTANCE_PROFILE}

インスタンスプロファイルにロールが追加されたことを確認

コマンド
aws iam get-instance-profile \
    --instance-profile-name ${INSTANCE_PROFILE_NAME}
結果
{
    "InstanceProfile": {
        "InstanceProfileId": "*********************",
        "Roles": [
            {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Action": "sts:AssumeRole",
                            "Effect": "Allow",
                            "Principal": {
                                "ec2.amazonaws.com"
                            }
                        }
                    ]
                },
                "RoleId": "*********************",
                "CreateDate": "2017-03-24T07:19:19Z",
                "RoleName": "TestProfileForWindowsServer",
                "Path": "/",
                "Arn": "arn:aws:iam::************:role/TestProfileForWindowsServer"
            }
        ],
        "CreateDate": "2017-03-24T07:27:18Z",
        "InstanceProfileName": "TestProfileForWindowsServer",
        "Path": "/",
        "Arn": "arn:aws:iam::************:instance-profile/TestProfileForWindowsServer"
    }
}

2.3. インスタンスプロファイルのアタッチ

EC2インスタンスにインスタンスプロファイルを関連付けます。

この機能は、2017年2月9日にリリースされた機能です。

AWS Security Blog | New! Attach an AWS IAM Role to an Existing Amazon EC2 Instance by Using the AWS CLI

インスタンスプロファイルのARNを確認

コマンド
INSTANCE_PROFILE_ARN=$(aws iam get-instance-profile \
    --instance-profile-name ${INSTANCE_PROFILE_NAME} \
    --query "InstanceProfile.Arn" \
    --output text) \
    && echo ${INSTANCE_PROFILE_ARN}

インスタンスプロファイルの指定

コマンド
INSTANCE_PROFILE_FILE_NAME="instance-profile.json"
コマンド
cat << EOF > ${INSTANCE_PROFILE_FILE_NAME}
{
    "Arn": "${INSTANCE_PROFILE_ARN}",
    "Name": "${INSTANCE_PROFILE_NAME}"
}
EOF

cat ${INSTANCE_PROFILE_FILE_NAME}

EC2インスタンスにインスタンスプロファイルを関連付け

コマンド
aws ec2 associate-iam-instance-profile \
    --iam-instance-profile file://${INSTANCE_PROFILE_FILE_NAME} \
    --instance-id ${INSTANCE_ID}
結果
{
    "IamInstanceProfileAssociation": {
        "InstanceId": "i-*****************",
        "State": "associating",
        "AssociationId": "iip-assoc-*****************",
        "IamInstanceProfile": {
            "Id": "*********************",
            "Arn": "arn:aws:iam::************:instance-profile/TestProfileForWindowsServer"
        }
    }
}

EC2インスタンスにインスタンスプロファイルが関連付けられたことを確認

コマンド
aws ec2 describe-instances \
    --instance-ids ${INSTANCE_ID} \
    --query "Reservations[0].Instances[0].IamInstanceProfile"
結果
{
    "Id": "*********************",
    "Arn": "arn:aws:iam::************:instance-profile/TestProfileForWindowsServer"
}

3. 実行結果保存用S3バケットの作成

EC2 Systems Managerで実行した処理の結果をS3バケットに保存することが可能です。

3.1. バケットの作成

バケット名を指定

コマンド
AWS_ID=$(aws sts get-caller-identity \
    --query "Account" \
    --output text) \
    && echo ${AWS_ID}
コマンド
BUCKET_NAME="ec2-systems-manager-${AWS_ID}" \
    && echo ${BUCKET_NAME}

同名バケットの不存在を確認

コマンド
aws s3 ls ${BUCKET_NAME}
結果
An error occurred (NoSuchBucket) when calling the ListObjects operation: The specified bucket does not exist

バケットの作成

コマンド
aws s3 mb s3://${BUCKET_NAME}
結果
make_bucket: ec2-systems-manager-************

バケットの存在を確認

コマンド
aws s3 ls | grep ${BUCKET_NAME}
結果
2017-03-24 08:45:37 ec2-systems-manager-************

3.2. バケットポリシーの定義

S3バケットに対し、EC2 Systems Managerのサービスから書き込みできるようにバケットポリシーを設定します。

ポリシーの生成

コマンド
POLICY_FILE_NAME='ssm_acl.json'
コマンド
cat << EOF > ${POLICY_FILE_NAME}
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "sitemanager",
            "Effect": "Allow",
            "Principal": {
                "Service": "ssm.amazonaws.com"
            },
            "Action": "*",
            "Resource": "arn:aws:s3:::${BUCKET_NAME}"
        }
    ]
}
EOF

cat ${POLICY_FILE_NAME}
結果
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "sitemanager",
            "Effect": "Allow",
            "Principal": {
                "Service": "ssm.amazonaws.com"
            },
            "Action": "*",
            "Resource": "arn:aws:s3:::ec2-systems-manager-************"
        }
    ]
}
コマンド
jsonlint -q ${POLICY_FILE_NAME}

バケットポリシーのアタッチ

コマンド
aws s3api put-bucket-policy \
    --bucket ${BUCKET_NAME} \
    --policy file://${POLICY_FILE_NAME}

バケットにポリシーがアタッチされたことを確認

コマンド
aws s3api get-bucket-policy \
    --bucket ${BUCKET_NAME}
結果
{
    "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"sitemanager\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ssm.amazonaws.com\"},\"Action\":\"*\",\"Resource\":\"arn:aws:s3:::ec2-systems-manager-************\"}]}"
}

4. SNSトピックの作成およびサブスクリプションの設定

EC2 Systems Managerで実行した処理の成否に応じてSNSによる通知を行うことが可能です。

ここでは、そのための設定(SNSトピックの作成をサブスクリプション設定)を行います。

トピック名の指定

コマンド
SNS_TOPIC_NAME_FOR_EC2="ec2-topic" \
    && echo ${SNS_TOPIC_NAME_FOR_EC2}

同名トピックの不存在を確認

コマンド
aws sns list-topics \
    | grep ${SNS_TOPIC_NAME_FOR_EC2}

トピックの作成

コマンド
aws sns create-topic \
    --name ${SNS_TOPIC_NAME_FOR_EC2}
結果
{
    "TopicArn": "arn:aws:sns:ap-northeast-1:788063364413:ec2-topic"
}

トピックのARNを取得

コマンド
SNS_TOPIC_ARN_FOR_EC2=$(aws sns list-topics \
    --query "Topics[?contains(TopicArn, \`${SNS_TOPIC_NAME_FOR_EC2}\`)].TopicArn" \
    --output text) \
    && echo ${SNS_TOPIC_ARN_FOR_EC2}

通知方法および通知先の指定

コマンド
PROTOCOL="email"
EMAIL_ADDRESS="(自身の利用可能なメールアドレスを設定してください)"

トピックを購読(サブスクライブ)

コマンド
aws sns subscribe \
    --topic-arn ${SNS_TOPIC_ARN_FOR_EC2} \
    --protocol ${PROTOCOL} \
    --notification-endpoint ${EMAIL_ADDRESS}
結果
{
    "SubscriptionArn": "pending confirmation"
}

通知先の認証用トークンを取得

コマンド
TOKEN="(受信したメールに記載されたリンクに含まれるTOKENをコピー&ペーストします)"

購読を承認

※通知メールのリンクから購読を停止されることを防止したい場合、以下の通り"authenticate-on-unsubscribe"オプションをtrueにします。

コマンド
aws sns confirm-subscription \
    --topic-arn ${SNS_TOPIC_ARN_FOR_EC2} \
    --token ${TOKEN} \
    --authenticate-on-unsubscribe true
結果
{
    "SubscriptionArn": "arn:aws:sns:ap-northeast-1:************:ec2-topic:********-****-****-****-************"
}

5. SNSトピックによる通知用サービスロールの作成

EC2 Systems Managerで実行した処理の成否に応じてSNSによる通知を行うことが可能です。

ここでは、そのための設定(EC2 Systems ManagerからSNSによる通知権限を委任するIAMロールの作成および権限の付与)を行います。

5.1. ロールの作成

ロール名の指定

コマンド
ROLE_NAME_FOR_NOTIFICATION="NotificationForEC2SystemsManager"

同名ロールの不存在を確認

コマンド
aws iam get-role \
    --role-name ${ROLE_NAME_FOR_NOTIFICATION}
結果
An error occurred (NoSuchEntity) when calling the GetRole operation: Role not found for NotificationForEC2SystemsManager

信頼関係を定義

コマンド
TRUST_POLICY_FILE='Trust-Policy-for-EC2SystemsManager.json'
コマンド
cat << EOF > ${TRUST_POLICY_FILE}
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ssm.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF

cat ${TRUST_POLICY_FILE}
コマンド
jsonlint -q ${TRUST_POLICY_FILE}

パラメータを確認

コマンド
cat << ETX

    ROLE_NAME_FOR_NOTIFICATION: ${ROLE_NAME_FOR_NOTIFICATION}
    TRUST_POLICY_FILE: ${TRUST_POLICY_FILE}

ETX
結果

    ROLE_NAME_FOR_NOTIFICATION: NotificationForEC2SystemsManager
    TRUST_POLICY_FILE: Trust-Policy-for-EC2SystemsManager.json

ロールを作成

コマンド
aws iam create-role \
    --role-name ${ROLE_NAME_FOR_NOTIFICATION} \
    --assume-role-policy-document file://${TRUST_POLICY_FILE}
結果
{
    "Role": {
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "ssm.amazonaws.com"
                    }
                }
            ]
        },
        "RoleId": "*********************",
        "CreateDate": "2017-03-24T09:27:55.783Z",
        "RoleName": "NotificationForEC2SystemsManager",
        "Path": "/",
        "Arn": "arn:aws:iam::************:role/NotificationForEC2SystemsManager"
    }
}

ロールにアタッチするポリシーを指定

※実際にはきちんと権限を絞りましょう。

コマンド
POLICY_ARN_FOR_NOTIFICATION="arn:aws:iam::aws:policy/AmazonSNSFullAccess"

ロールにポリシーをアタッチ

コマンド
aws iam attach-role-policy \
    --role-name ${ROLE_NAME_FOR_NOTIFICATION} \
    --policy-arn ${POLICY_ARN_FOR_NOTIFICATION}

ロールにポリシーがアタッチされたことを確認

コマンド
aws iam list-attached-role-policies \
    --role-name ${ROLE_NAME_FOR_NOTIFICATION}
結果
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonSNSFullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonSNSFullAccess"
        }
    ]
}

ロールのARNを確認

コマンド
ROLE_ARN_FOR_NOTIFICATION=$(aws iam get-role \
    --role-name ${ROLE_NAME_FOR_NOTIFICATION} \
    --query "Role.Arn" \
    --output text) \
    && echo ${ROLE_ARN_FOR_NOTIFICATION}
結果
arn:aws:iam::************:role/NotificationForEC2SystemsManager

以上

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1