AWS Systems Manager(以下SSM)のマネージドインスタンス化についての解説をしていきたいと思います。
SSMのマネージドインスタンスとは
マネージドする = 管理される という意味です。
SSMでEC2を管理しますよ、という意味に置き換えられます。
ではどのように管理すればいいのか?
マネージド化するにはいくつか条件があります。
その条件が以下です。
SSM Agentの導入
SSM APIとSSM Agentが連携し、コントロールを行います。
SSM Agentは以下AWS公式にもある通り、すでにプリインストールされたAMIが存在します。
Amazon Linux2などはすでにインストールされているため、インストール作業などは必要ありません。
SSM APIへの経路を確保
SSM APIとの通信をするためにSSM AgentからAWSサービスエンドポイントに対してHTTPS(443)のアウトバウンドの通信経路を確保してあげる必要があります。
ここででいうサービスエンドポイントへの通信経路の確保には以下の2パターンがあります。
プライベートサブネットに配置したEC2にVPCエンドポイントを経由して通信する方法
パブリックサブネットにNAT gatewayを配置してインターネットを経由して通信する方法
IAM Roleの付与
AmazonSSMManagedInstanceCoreというロールをEC2にアタッチする必要があります。
AmazonSSMManagedInstanceCoreをアタッチすることで、AWSリソースへのアクセスを許可を得ることができます。
この場合、EC2インスタンスはSSMへアクセスするための権限を引き受けたため、SSMとの通信のやり取りが可能になります。
IAMロールをEC2へ引き渡すための信頼関係を表しているのが、以下の信頼ポリシーです。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
}
}
]
}
どうする: sts:AssumeRole: 一時的な役割をAllow(許可)します
誰に: ec2.amazonaws.com(EC2インスタンスに)
直訳すると、主要なサービスはEC2です。一時的なAmazonSSMManagedInstanceCoreという役割を許可します。という意味合いになるかと思います。
ここまでできればSSMのマネージドインスタンスの前準備が整いました。
以下CloudFormationを使用していただくと、VPCエンドポイント経由するマネージドインスタンス化されたEC2の作成が可能です。
AWSTemplateFormatVersion: 2010-09-09
Description: "VPC Template"
Parameters:
#---------------------------------------------------------------------#
# Common
#---------------------------------------------------------------------#
Prefix:
Type: String
Default: "stg"
ec2Prefix:
Type: String
Default: "step-server"
#---------------------------------------------------------------------#
# Network
#---------------------------------------------------------------------#
VpcCidr:
Type: String
Default: "10.0.0.0/16"
PrivateSubnet1Cidr:
Type: String
Default: "10.0.2.0/24"
#---------------------------------------------------------------------#
# EC2
#---------------------------------------------------------------------#
EC2InstanceName:
Type: String
Default: "step-server"
EC2InstanceAMI:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
EC2InstanceType:
Type: String
Default: "t2.micro"
EC2InstanceVolumeType:
Type: String
Default: "gp2"
EC2InstanceVolumeSize:
Type: String
Default: "8"
Resources:
#---------------------------------------------------------------------#
# Network
#---------------------------------------------------------------------#
StgVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub "${Prefix}-vpc"
StgPrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Sub ${AWS::Region}a
VpcId: !Ref StgVPC
CidrBlock: !Ref PrivateSubnet1Cidr
Tags:
- Key: Name
Value: !Sub "${Prefix}-private-subnet1"
StgPrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref StgVPC
Tags:
- Key: Name
Value: !Sub "${Prefix}-rtb-private"
# ルートテーブルをサブネットに関連付け
PrivateSubnet1TableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
# どのサブネットを指定するか
SubnetId: !Ref StgPrivateSubnet1
RouteTableId: !Ref StgPrivateRouteTable
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${ec2Prefix}-sg"
GroupDescription: !Sub "${ec2Prefix}-sg"
VpcId: !Ref StgVPC
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: -1
FromPort: -1
ToPort: -1
Tags:
- Key: Name
Value: !Sub "${ec2Prefix}-sg"
#---------------------------------------------------------------------#
# VPC Endpoint
#---------------------------------------------------------------------#
SsmVpcEndpointSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${Prefix}-ssm-vpc-endpoint-sg"
GroupDescription: !Sub "${Prefix}-ssm-vpc-endpoint-sg"
VpcId: !Ref StgVPC
SecurityGroupIngress:
- CidrIp: !Ref VpcCidr
IpProtocol: tcp
FromPort: 443
ToPort: 443
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
Tags:
- Key: Name
Value: !Sub "${Prefix}-ssm-vpc-endpoint-sg"
SsmVpcEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
VpcEndpointType: Interface
SecurityGroupIds:
- !Ref SsmVpcEndpointSecurityGroup
ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
SubnetIds:
- !Ref StgPrivateSubnet1
VpcId: !Ref StgVPC
SsmMessagesVpcEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
VpcEndpointType: Interface
SecurityGroupIds:
- !Ref SsmVpcEndpointSecurityGroup
ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
SubnetIds:
- !Ref StgPrivateSubnet1
VpcId: !Ref StgVPC
Ec2MessagesVpcEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
# PolicyDocument: Json
PrivateDnsEnabled: true
VpcEndpointType: Interface
SecurityGroupIds:
- !Ref SsmVpcEndpointSecurityGroup
ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
SubnetIds:
- !Ref StgPrivateSubnet1
VpcId: !Ref StgVPC
#---------------------------------------------------------------------#
# Ec2InstanceProfile
#---------------------------------------------------------------------#
Ec2Role:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${Prefix}-EC2SSMRoleForRDSAccess"
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Ec2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: !Sub "${Prefix}-ec2-instance-profile"
Roles:
- !Ref Ec2Role
EC2Instance:
Type: AWS::EC2::Instance
Properties:
Tags:
- Key: Name
Value: !Sub "${ec2Prefix}"
DisableApiTermination: false
EbsOptimized: false
ImageId: !Ref EC2InstanceAMI
InstanceType: !Ref EC2InstanceType
IamInstanceProfile: !Ref Ec2InstanceProfile
SecurityGroupIds:
- !Ref EC2SecurityGroup
SubnetId: !Ref StgPrivateSubnet1
BlockDeviceMappings:
-
DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
VolumeType: !Ref EC2InstanceVolumeType
VolumeSize: !Ref EC2InstanceVolumeSize
CloudFormationデプロイ方法
以下コマンドをAWS CLIコマンドで実行します。
aws cloudformation deploy \
--stack-name StackName \
--template-file filename.yml
--capabilities CAPABILITY_NAMED_IAM
AWS CLIコマンドをすぐに使用するためにはAmazon CloudShellを使用すると便利です。
AWSサービスを「CloudShell」で検索します。
次のようなコマンドライン画面が表示されます。
右上のアクション -> ファイルのダウンロードから作成したymlファイルをアップロードします
ファイルがアップロードされたことを確認するためにlsで確認することができます。
ファイルがアップロードされたことを確認できたら、先ほど示したAWS CLIコマンドでdeployします。
aws cloudformation deploy \
--stack-name StackName \
--template-file filename.yml
--capabilities CAPABILITY_NAMED_IAM
問題なくdeployが実行されると以下のように表示されます。
deployが問題なく完了すると以下のようにステータスがCREATE_COMPLETEと表示され無事にdeployが完了です。