この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、森田です。
本記事では、CloudFormationを用いてプライベートサブネット上にEC2を起動させ、SSMポートフォワード経由でRDP接続できるようにエンドポイントの構築を行います。
構成図
CloudFormationでは、以下のアーキテクチャを構築します。
前提条件
VPC, Private Subnetは作成済みとします。
また、EC2起動のため、事前にキーペアの作成を行っておく必要があります。
使用するCloudFormationテンプレート
以下のCloudFormationテンプレートを実行します。
入力パラメータとして、VPC ID、Subent ID、キーペア名の入力が必要となります。
AWSTemplateFormatVersion:
"2010-09-09"
Description:
AWS Private Subnet EC2 Launch and Connect by SSM
Parameters:
InstanceType:
Type: String
Default: "t2.nano"
VPCId:
Type: String
SubnetId:
Type: String
KeyPairName:
Type: String
PJPrefix:
Type: String
Default: "privatelaunch"
WindowsLatestAmi:
Description: "EC2 AMI image SSM path"
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-windows-latest/Windows_Server-2019-Japanese-Full-Base
AllowedValues:
- /aws/service/ami-windows-latest/Windows_Server-2019-Japanese-Full-Base
- /aws/service/ami-windows-latest/Windows_Server-2019-English-Full-Base
Resources:
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "Bastion EC2 Security Group"
VpcId: !Ref VPCId
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-ec2-bastion-sg"
EndpointSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "Bastion Endpoint Security Group"
VpcId: !Ref VPCId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
SourceSecurityGroupId: !Ref EC2SG
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-endpoint-bastion-sg"
IamRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${PJPrefix}-ec2-bastion-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref IamRole
EC2Instance:
Type: "AWS::EC2::Instance"
Properties:
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-bastion"
ImageId: !Ref WindowsLatestAmi
InstanceType: !Ref InstanceType
KeyName: !Ref KeyPairName
DisableApiTermination: false
EbsOptimized: false
SecurityGroupIds:
- !Ref EC2SG
SubnetId: !Ref SubnetId
IamInstanceProfile: !Ref InstanceProfile
SSMVPCEndpoint:
Type: "AWS::EC2::VPCEndpoint"
Properties:
VpcEndpointType: Interface
PrivateDnsEnabled: true
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssm'
VpcId: !Ref VPCId
SubnetIds:
- !Ref SubnetId
SecurityGroupIds:
- !Ref EndpointSG
SSMMessagesVPCEndpoint:
Type: "AWS::EC2::VPCEndpoint"
Properties:
VpcEndpointType: Interface
PrivateDnsEnabled: true
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssmmessages'
VpcId: !Ref VPCId
SubnetIds:
- !Ref SubnetId
SecurityGroupIds:
- !Ref EndpointSG
EC2MessagesVPCEndpoint:
Type: "AWS::EC2::VPCEndpoint"
Properties:
VpcEndpointType: Interface
PrivateDnsEnabled: true
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ec2messages'
VpcId: !Ref VPCId
SubnetIds:
- !Ref SubnetId
SecurityGroupIds:
- !Ref EndpointSG
CloudFormationで作成するメリット
エンドポイントは、時間単位での課金かつ個人的によく削除を忘れやすいリソースだったりします。
また、Private Subnet内のEC2への接続には、エンドポイントが3つ必要となり、作成・削除も手間だったりします。
CloudFormationで作成することで、
- 同じ操作を一括で行うことができる
- スタックの削除では、リソースの削除も一括で行うことができる
ため、作業の簡略化やリソースの削除を忘れを防ぐことができます。
最後に
今回は、Private Subnet 内のEC2へ VPC Endpointから接続を行いましたが、エンドポイントが複数あるため、長時間利用すると結構コストが発生する可能性もあります。
一時的にPublic Subnet の構築が許容できる場合では、
Public Subnetを構築しその中にEC2を起動する方がコストは抑えられますので、機会があればこのCloudFormationも作ってみたいと思います。