😸

【CloudFormation】パブリックサブネットにCloud9(SSH)をデプロイしてみる

2022/07/03に公開

1. はじめに

 こんにちわ、Mitsuoです。
今住んでいる家にようやくクーラーが設置され快適な環境が手に入りました。
今年も暑いようですので、体調にはお気を付けください。

2. 今回のお題

 さて、今回のお題に入りますが、「CloudFormationを用いてCloud9をデプロイ」してみました。
Cloud9をコンソールで作成すると、裏でCloudFormationのスタックが作成され、Cloud9用のEC2が生成されると思います。
しかしながら、ブログ主は凄く怠惰なのでコンソールでは無くテンプレートで持っておきたいな、と言うのが今回のネタになります。

3. 作成したリソース

 テンプレートで作成するリソースは以下の通りです。

  • VPC
  • Subnet(Public)
  • RouteTable
  • InternetGateway
  • NACL
  • Cloud9

image

「プライベートサブネットになぜ配置しないの?」、「Session Managerを使えよ」と思ったそこのあなた、おっしゃる通りです。
言い訳をすると、初心者の方にも取っ掛かりやすい内容で書きたかったんです。
後は、もう少しコンパクトに書いても良いのですが、補足を入れると結構な文字数になるなという訳で・・・。今回は書きませんが、ストックは持っているので、近いうちに記事にする予定です。

4 テンプレート情報

 作成したテンプレートになります。

AWSTemplateFormatVersion: 2010-09-09
Description: Create Cloud9 for Public subnet, network and related resources such as subnet, route table.
# ------------------------------------------------------------#
#  Caution:
#  This template is for deploying resources on AZ-1a in Tokyo region(ap-northeast-1).
#  If you deploy them in another region, make sure that you understand below content and make modification for parameters such as AvailabilityZone.
# ------------------------------------------------------------#
#  Metadata:
#  This can privide details about the template.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html.
#  As Metadata Keys, AWS::CloudFormation::Interface can Defines the grouping and ordering of input parameters
#  when they are displayed in the AWS CloudFormation console.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-interface.html.
# ------------------------------------------------------------#

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      -
        Parameters:
          - SystemName
          - EnvType
          - Tagprefix
          - Owner
          - VPCCIDR
          - PublicSubnet1CIDR

    ParameterLabels: 
      SystemName:
        default: "Please type the Systemname"
      EnvType:
        default: "Please select the environment to which you want to deploy resources"
      Tagprefix:
        default: "Please type the Tagprefix which is logical unit name about this stack(e.g. Webserver,Monitoring,Logging)"
      Owner:
        default: "Please type who owns these resources (e.g. project name or worker, whether this purpose is just verification or not)"        
      VPCCIDR: 
        default: "Please type VPC's CIDR such as NN.NN.NN.NN/NN based on RFC 1918"
      PublicSubnet1CIDR:
        default: "Please type your subnet's CIDR in AZ-A such as NN.NN.NN.NN/NN based on RFC 1918"

# ------------------------------------------------------------#
# Parameters
# This Can enable templates to input custom values each time you create or update a stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html.
# ------------------------------------------------------------# 

Parameters:
  SystemName:
    Type: String
  EnvType:
    Type: String
    Default: "dev"
    AllowedValues:
      - dev
      - stg
      - prod
  Tagprefix:
    Type: String
  Owner:
    Type: String
  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"
    ConstraintDescription: "Please type VPC's CIDR such as NN.NN.NN.NN/NN based on RFC 1918"  
  PublicSubnet1CIDR:
    Type: String
    Default: "10.0.1.0/24"
    ConstraintDescription: "Please type your subnet's CIDR in AZ-A such as NN.NN.NN.NN/NN based on RFC 1918"

# ------------------------------------------------------------#
# Resources
# This can declare the AWS resources that you want to include in the stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------#

Resources:

# ------------------------------------------------------------#
# Create VPC
# ------------------------------------------------------------#

  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsHostnames: "true"
      EnableDnsSupport: "true"
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-VPC
        - Key: Owner
          Value: !Sub ${Owner}

# ------------------------------------------------------------#
# Create PublicSubnet
# ------------------------------------------------------------#

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PublicSubnet1CIDR
      AvailabilityZone: ap-northeast-1a
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-PublicSubnet-1a
        - Key: Owner
          Value: !Sub ${Owner}

# ------------------------------------------------------------#
# Create InternetGateway and associate it with VPC
# ------------------------------------------------------------#

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-Internet-Gateway
        - Key: Owner
          Value: !Sub ${Owner}

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

# ------------------------------------------------------------#
# Create Route Table and associate it with Public Subnet
# ------------------------------------------------------------#

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-RouteTable-PublicSubnet
      - Key: Owner
        Value: !Sub ${Owner}

  PublicSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway

# ------------------------------------------------------------#
# Create NetworkACL and associate it with Public Subnet
# ------------------------------------------------------------#
  PublicNetworkACL:
    Type: AWS::EC2::NetworkAcl
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-Public-Networkacl
        - Key: Owner
          Value: !Sub ${Owner}

  PublicNaclInboundRule:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
       NetworkAclId: !Ref PublicNetworkACL
       RuleNumber: 100
       Protocol: -1
       Egress: false
       RuleAction: allow
       CidrBlock: 0.0.0.0/0

  PublicNaclOutboundRule:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
       NetworkAclId: !Ref PublicNetworkACL
       RuleNumber: 100
       Protocol: -1
       Egress: true
       RuleAction: allow
       CidrBlock: 0.0.0.0/0

  PublicNetworkACLAssoc1:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties:
      NetworkAclId: !Ref PublicNetworkACL
      SubnetId: !Ref PublicSubnet1

# ------------------------------------------------------------#
# Create Cloud9
# ------------------------------------------------------------#

  Cloud9:
    Type: AWS::Cloud9::EnvironmentEC2
    Properties: 
      AutomaticStopTimeMinutes: 30
      ConnectionType: CONNECT_SSH
      Description: The Cloud9 on Public subnet connecting Via SSH.  
      ImageId: amazonlinux-2-x86_64
      InstanceType: t3.small
      Name: !Sub ${SystemName}-${EnvType}-${Tagprefix}-Cloud9-SSH
#     OwnerArn: Please use this property if you want to set up the ARN of environment owner. 
#     Repositories: Please use this property if you want to set up any CodeCommit source code repositories to be cloned into the environment.
      SubnetId: !Ref PublicSubnet1
      Tags: 
        - Key: Owner
          Value: !Sub ${Owner}
    DependsOn: PublicSubnet1

# ------------------------------------------------------------#
# Outputs
# This can output each value specified as output section.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------# 

Outputs:

  VPC:
    Description: VPC
    Value: !Ref VPC    

  PublicSubnet1:
    Description: PublicSubnet1
    Value: !Ref PublicSubnet1

  PublicRouteTable:
    Description: PublicRouteTable
    Value: !Ref PublicRouteTable

  InternetGateway:
    Description: InternetGateway
    Value: !Ref InternetGateway

  PublicNetworkACL:
    Description: PublicNetworkACL
    Value: !Ref PublicNetworkACL

  Cloud9:
    Description: Cloud9
    Value: !Ref Cloud9
     

5. テンプレートの補足

テンプレートに関して、以下の通り補足します。

5.1 Metadata/Parameters

 メタデータおよびパラメターセクションで、4つの値を定義します。

項目 備考
ProjectName プロジェクト名や利用目的等を入力する
EnvType デプロイする環境を選択する
検証、ステージング、本番の3点
Tagprefix 任意で入力するPrefix値
Owner 作業者、所有者、コスト管理用に入力する

Cloud9を除くNameタグの値に、ProjectNameEnvTypeTagprefixの3点を含みます。
OwnerはOwnerタグの値に利用します。
Cloud9は、Nameプロパティがある為、テンプレートでNameタグの指定が出来ない仕様になっています。
指定したNameプロパティに加えて、ランダム文字列を付与します。

5.2 Resources

 以下のリソースセクションを設定しています。

AWS::EC2::VPC
AWS::EC2::Subnet
AWS::EC2::InternetGateway
AWS::EC2::VPCGatewayAttachment
AWS::EC2::RouteTable
AWS::EC2::SubnetRouteTableAssociation
AWS::EC2::Route
AWS::EC2::NetworkAcl
AWS::EC2::NetworkAclEntry
AWS::EC2::SubnetNetworkAclAssociation
AWS::Cloud9::EnvironmentEC2

VPC、サブネット周りは、他にも有用な記事が沢山あるので、私の記事では割愛します。
Cloud9だけ補足します。

5.3 Cloud9(Type: AWS::Cloud9::EnvironmentEC2)

  • Cloud9が起動してから自動的に停止する時間を分単位で指定
      AutomaticStopTimeMinutes: 30
  • Cloud9への接続方式
    SSH接続かSystems Manager(Session Manager)で指定可能
    デフォルトがSSH接続
      ConnectionType: CONNECT_SSH
  • Cloud9の説明、名前欄に記入する項目
    Cloud9はNameタグの指定が出来ず、プロパティ側で設定する必要がある
      Description: The Cloud9 on Public subnet connecting Via SSH.  
      Name: !Sub ${SystemName}-${EnvType}-${Tagprefix}-Cloud9-SSH
  • Cloud9で実行するイメージを指定、AMIのエイリアスかSSM Pathsの指定が必要
    インスタンスタイプも指定出来る
      ImageId: amazonlinux-2-x86_64
      InstanceType: t3.small
  • Cloud9の所有者をARNベースで指定出来る
    デフォルトは、ログインユーザ(スイッチロール含む)になる
# OwnerArn: Please use this property if you want to set up the ARN of environment owner. 
  • Cloud9はCodeCommitと統合されており、CodeCommitのソース情報をCloud9にクローン(Git Cloneと同じように同期)したい場合、利用する
# Repositories: Please use this property if you want to set up any CodeCommit source code repositories to be cloned into the environment.

5.4 その他

  • CloudFormationでCloud9を作成してもCloud9用テンプレートが別途作成されます。
    合計2個ですね。

image

別途作成されたテンプレートのステータスがCREATE_COMPLETEになれば、Cloud9にアクセス出来る状況のはずです。
Cloud9のIDE環境にアクセスした後、どちらのテンプレートのステータスもCREATE_COMPLETEになっている事を確認済みです。

  • SSH接続のCloud9の場合は、セキュリティグループが自動的に生成されますが、SSMを利用するためのIAMロール(実際にアタッチされているのはインスタンスプロファイル)はインスタンスにアタッチされません。この辺りは、コンソールと同じですね。

image

6. まとめ

 今回はCloud9のテンプレートを作成してみました。需要があるかはさておき一時的にCloud9を使いたい、かつネットワークリソースは他と分けたい様なニーズがあれば使えるテンプレートだとは思います。
とはいえ、パブリックサブネットに配置するCloud9はセンスが無いので、プライベートサブネット用のテンプレートもブログで書くようにします。

この記事が誰かの役に立てれば嬉しいです。Mitsuoでした!

Discussion