【CloudFormation】一撃でプライベートサブネットにEC2を起動し、SSMポートフォワード経由でRDPする

2022.04.22

この記事は公開されてから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も作ってみたいと思います。

参考