【AWS】CloudFormationテンプレート作成(SSMを使用してプライベートサブネット上のEC2に接続する構成)

# はじめに
CloudFormationテンプレートを用いて効率的に環境構築を実施したいと思ったので備忘録として記載。
最近SSMを使用してプライベートサブネット上のEC2に接続できるような環境を構築したので、テンプレートで書いてみる。

# ゴール
CloudFormationテンプレートでSMを使用してプライベートサブネット上のEC2に接続できるような環境を構築する。
※実際に接続できるところまでは今回確認はしません。

# 目的
CloudFormationテンプレートの書き方の理解

# スタックの作成
Nameタグとか論理IDがセンス無いですが、CloudFormationテンプレートから作成されたものだとわかるように今回はあまり気にしないことにします。

```Create_SSM.yml
AWSTemplateFormatVersion: 2010-09-09
Resources:
  # ------------------------------------------------------------#
  #  VPC
  # ------------------------------------------------------------#
  CFTestVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 172.30.0.0/21
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: TestVPCfromCF

  # ------------------------------------------------------------#
  #  Sunbet
  # ------------------------------------------------------------#
  CFTestPrivateSubnet1a:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: 172.30.0.0/24
      VpcId: !Ref CFTestVPC
      Tags:
        - Key: Name
          Value: TestPrivateSubnet-1afromCF

  # ------------------------------------------------------------#
  #  SecurityGroup
  # ------------------------------------------------------------#
  CFTestSGforEC2:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: TestSGforEC2
      GroupDescription: TestSGforEC2
      VpcId: !Ref CFTestVPC
      Tags:
        - Key: Name
          Value: TestSGforEC2fromCF

  CFTestSGforVPCe:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: TestSGforVPCe
      GroupDescription: TestSGforVPCe
      VpcId: !Ref CFTestVPC
      SecurityGroupIngress:
        IpProtocol: tcp
        FromPort: 443
        ToPort: 443
        CidrIp: 172.30.0.0/24
      Tags:
        - Key: Name
          Value: TestSGforVPCfromCF

  # ------------------------------------------------------------#
  #  VPC Endpoint
  # ------------------------------------------------------------#
  SSMEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref CFTestSGforVPCe
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref CFTestPrivateSubnet1a
      VpcEndpointType: Interface
      VpcId: !Ref CFTestVPC

  EC2MessagesEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref CFTestSGforVPCe
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref CFTestPrivateSubnet1a
      VpcEndpointType: Interface
      VpcId: !Ref CFTestVPC

  SSMMessagesEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref CFTestSGforVPCe
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref CFTestPrivateSubnet1a
      VpcEndpointType: Interface
      VpcId: !Ref CFTestVPC

  # ------------------------------------------------------------#
  #  VPC Endpoint
  # ------------------------------------------------------------#
  InstanceProfile:
    DependsOn: TestSSMRole
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: '/'
      Roles:
        - !Ref TestSSMRole
  TestSSMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Principal:
              Service:
                - 'ec2.amazonaws.com'
            Action:
              - 'sts:AssumeRole'
      Path: '/'
      RoleName: TestSSMRolefromCF
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

  # ------------------------------------------------------------#
  #  EC2
  # ------------------------------------------------------------#
  SSMEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: #任意のAMIID
      InstanceType: t2.micro
      SubnetId: !Ref CFTestPrivateSubnet1a
      IamInstanceProfile: !Ref InstanceProfile
      SecurityGroupIds:
        - !Ref CFTestSGforEC2
      Tags:
        - Key: Name
          Value: Test-SSMInstance
      KeyName: !Ref SSMKeypair
  SSMKeypair:
    Type: AWS::EC2::KeyPair
    Properties:
      KeyName: SSMkeypair2022
```

上記のテンプレートの内容で作成に成功していることを確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086543/59cdd426-0e02-ae46-0cdb-2213736b2866.png)

※VPCエンドポイントは放置しておくと費用が発生するため、不要であればスタックを削除してください。


# おわりに
上記のテンプレートで簡単に環境を構築することができました。
もっといい書き方があると思うので、どんどん修正を加えていきたいと思っています。
基本を抑えつつ、今後は応用が利くテンプレートも作成していきたいです。

# 参考資料
SSMの手順については以下のブログが非常にわかりやすかったので、詳細手順はこちらを参照いただけると助かります。

■SSM を使用したプライベート EC2 インスタンスへの接続
https://blog.logical.co.jp/entry/2021/06/15/130000