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

More than 1 year has passed since last update.


この記事について

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


以上

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