実験用の使い捨てEC2を建てたくなることが多々あるため、CloudFormationでデフォルトVPCにEC2を簡単に建てるメモ。

準備

CloudFomationのTemplateを用意する。
Templateでは以下のリソースを作成している。

  • InstanceProfileに紐づけるRoleの作成。ポリシーにはAmazonSSMManagedInstanceCOreを付与してSSM経由で接続できるようにする。

  • Outboundだけ許可するSG

  • KeyPair(後でSSMParameterStoreから鍵を取得する)

  • DockerインストールのUserDataを含んだLaunchTemplate(UserDataをコンソールから確認したいため)

  • EC2

ec2.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Create EC2 Instance
Parameters:
  latestAmazonLinux2AmiId:
    Type : AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Resources:
  Ec2Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement: 
          - 
            Effect: Allow
            Principal: 
              Service: 
                - ec2.amazonaws.com
            Action: 
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
  Ec2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
      - !Ref Ec2Role
  Ec2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EC2SecurityGroup
      # VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-Ec2SecurityGroup
  Ec2SecurityGroupEgress:
    Type: AWS::EC2::SecurityGroupEgress
    Properties:
      IpProtocol: -1
      CidrIp: 0.0.0.0/0
      GroupId: !GetAtt Ec2SecurityGroup.GroupId
  Ec2SecurityGroupIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: -1
      CidrIp: 127.0.0.1/32
      GroupId: !GetAtt Ec2SecurityGroup.GroupId
  Ec2KeyPair:
    Type: AWS::EC2::KeyPair
    Properties:
      KeyName: !Sub ${AWS::StackName}-KeyPair
  Ec2LaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: !Sub ${AWS::StackName}-LaunchTemplate
      LaunchTemplateData:
        UserData:
          Fn::Base64: |-
            #!/bin/bash
            yum update -y
            amazon-linux-extras install docker -y
            systemctl enable docker
            systemctl start docker
            usermod -aG docker ec2-user
            curl -L --fail https://github.com/docker/compose/releases/download/1.29.2/run.sh -o /usr/local/bin/docker-compose
            chmod +x /usr/local/bin/docker-compose
  Ec2:
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: !Ref latestAmazonLinux2AmiId
      InstanceType: t2.micro
      KeyName: !Ref Ec2KeyPair
      SecurityGroupIds:
        - !Ref Ec2SecurityGroup
      IamInstanceProfile:
        !Ref Ec2InstanceProfile
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-Ec2
      LaunchTemplate:
        LaunchTemplateId: !Ref Ec2LaunchTemplate
        Version: !GetAtt Ec2LaunchTemplate.LatestVersionNumber
Outputs:
  StackName:
    Value: !Sub ${AWS::StackName}
    Export:
      Name: StackName
  KeyPairId:
    Value: !GetAtt Ec2KeyPair.KeyPairId
  KeyPairPath:
    Value: !Sub
      - /ec2/keypair/${KeyPairId}
      - KeyPairId: !GetAtt Ec2KeyPair.KeyPairId
    Export:
      Name: KeyPairPath

手順

  1. リソース作成

  2. 起動しているEC2のインスタンスIDの取得

  3. SSMParameterStoreに格納されたキーペアのパスを取得

  4. 生成したKeyPairのプライベートキーを取得

  5. SSMを使用してポートフォワード開始

  6. EC2に接続

  7. リソース削除

1. リソース作成

cmd
aws cloudformation deploy --template-file ./ec2.yml --stack-name sample-ec2 --capabilities CAPABILITY_NAMED_IAM

2. 起動しているEC2のインスタンスIDの取得

cmd
aws ec2 describe-instances --filter "Name=instance-state-name,Values=running" "Name=tag:Name,Values=sample-ec2-Ec2" --query "Reservations[0].Instances[0].InstanceId" --output text
結果
C:\Users\szk>aws ec2 describe-instances --filter "Name=tag:Name,Values=sample-ec2-Ec2" --query "Reservations[0].Instances[0].InstanceId" --output text
i-06ca26d6c01bfdf03

3. SSMParameterStoreに格納されたキーペアのパスを取得

cmd
aws cloudformation describe-stacks --stack-name sample-ec2 --query "Stacks[0].Outputs[?OutputKey==`KeyPairPath`].OutputValue" --output text
結果
C:\Users\szk>aws cloudformation describe-stacks --stack-name sample-ec2 --query "Stacks[0].Outputs[?OutputKey==`KeyPairPath`].OutputValue" --output text
/ec2/keypair/key-0ec16c1a1e6b69305

4. 生成したKeyPairのプライベートキーを取得

cmd
aws ssm get-parameter --name "/ec2/keypair/key-0ec16c1a1e6b69305" --with-decryption --query "Parameter.Value" --output text > ec2.key

5. SSMを使用してポートフォワード開始

cmd
aws ssm start-session --target i-06ca26d6c01bfdf03 --document-name AWS-StartPortForwardingSession --parameters "{\"portNumber\":[\"22\"],\"localPortNumber\":[\"10022\"]}"

6. EC2に接続

cmd
ssh -i ec2.key -p 10022 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ec2-user@localhost

7. リソース削除

cmd
aws cloudformation delete-stack --stack-name sample-ec2