この記事について
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日にリリースされた機能です。
インスタンスプロファイルの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
以上