LoginSignup
0
0

CloudFormationでEC2作業環境を構築

Last updated at Posted at 2023-11-05

目的

AWSで仮想マシンやオブジェクトストレージ、仮想マシンを置く仮想ネットワーク環境をまるっと作る.
マネジメントコンソールでもできるが、結構手間なのと、同じ環境を再現するのが大変なので、
環境構築をCloudFormationでスクリプト化する

構築したい環境

  • 仮想ネットワークとしてVPCと一つのパブリックサブネットを用意
  • 仮想ネットワーク環境の中にEC2を一つ建てる.
  • オブジェクトストレージ(S3)のバケットを作成
  • EC2には作成したバケットのみにアクセスできる権限(policy)を付与
  • 起動するEC2はubuntu20.04イメージを使用し、awscliを起動時にインストール

セキュリティ

  • EC2へはsshのみ接続のみ許可
  • ssh接続時にkeypairを要求

CloudFrmation

AWSでIaCを実現するツールの一つで、起動したいAWSサービスをまとめてjsonやymlに記述し、AWSで実行させることでまとめてサービスを起動する. CloudFormationで起動される一連のサービス群をstackと呼ぶ

メリットは

  • 同じAWS環境を再現できる
  • タグが必ず振られるので、コスト管理の際にstackごとのコストが確認できる
  • 起動したサービスはまとめて削除できる

など。

AWSでIaCをやりたい場合、Terraformという選択肢もある. が、AWSネイティブのサービスであるCloudFormationを使用.

事前準備

以下は事前に実施しておく必要がある

  • AWSのアカウント作成
  • IAMユーザーの作成

ymlの用意

作成したいAWSサービス群(stack)を記載したファイルを作成. jsonでも良いが、ymlのようがコメントかけたりして便利なのでymlを使用.

cloudformationのymlは基本的に以下の構成

Parameters: # ここに設定値などを記載しておく
Resources: # ここに作成/起動したいサービスとその条件を記載
Outputs: # 実行結果の出力

以下に今回作成したymlを格納している
cloudformation yml sample (github)

yml記載内容説明

Parameter設定

パラメータ部分は以下のように設定. パラメータの値はAWSでstackを起動する際に使用.

Parameters:
  PJPrefix:
    Type: String

  VPCCIDR:
    Type: String
    Default: "10.1.0.0/16"

  PublicSubnetACIDR:
    Type: String
    Default: "10.1.10.0/24"

Resources

Resources以下に起動するサービスの条件を設定していく.

ネットワークの設定

    VPC: 
      Type: "AWS::EC2::VPC"
      Properties: 
        CidrBlock: !Ref VPCCIDR
        EnableDnsSupport: "true"
        EnableDnsHostnames: "true"
        InstanceTenancy: default
        Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-vpc"

    InternetGateway: 
      Type: "AWS::EC2::InternetGateway"

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

    PublicSubnetA: 
      Type: "AWS::EC2::Subnet"
      Properties: 
        AvailabilityZone: "us-east-1a"
        CidrBlock: !Ref PublicSubnetACIDR
        VpcId: !Ref VPC 

    PublicRouteTableA: 
      Type: "AWS::EC2::RouteTable"
      Properties: 
        VpcId: !Ref VPC 

    PublicRouteA: 
      Type: "AWS::EC2::Route"
      Properties: 
        RouteTableId: !Ref PublicRouteTableA 
        DestinationCidrBlock: "0.0.0.0/0"
        GatewayId: !Ref InternetGateway 

    PublicSubnetARouteTableAssociation: 
      Type: "AWS::EC2::SubnetRouteTableAssociation"
      Properties: 
        SubnetId: !Ref PublicSubnetA 
        RouteTableId: !Ref PublicRouteTableA

構成要素はVPC, Subnet, RouteTable, InternetGatway.
InternetGatewayはVPCから外部インターネットと通信する際に必要. subnetは今回public subnetを一つだけ作成した.

subnetのAvailabilityZone: "us-east-1a"ではsubnetのazを指定している。azはリージョンごとに指定できる値が異なる。
CloudFormationはリージョンごとのサービスなので、適宜リージョンを変えて実行.
このymlはバージニア北部リージョンで実行できる.

EC2のセキュリティ周り

ssh key pairとセキュリティグループを以下のように作成

    DemoKeyPair:
        Type: AWS::EC2::KeyPair
        Properties:
            KeyName: demo-key-pair

    EC2SG:
      Type: AWS::EC2::SecurityGroup
      Properties:
        GroupName: "${PJPrefix}-sg"
        GroupDescription: Allow SSH access
        SecurityGroupIngress:
          - IpProtocol: tcp
            FromPort: 22
            ToPort: 22
            CidrIp: 0.0.0.0/0

ssh private keyの情報はAWS system managerのパラメータストアに保存される(後述)

セキュリティーグループはここではsshのみを許可してて、接続元ipは0.0.0.0/0(anywhere)としていて、これはセキュリティ的に少々不安なので、CidrIp:の部分を自分のipに設定し直した方が良いかもしれない

IAM Role

EC2にアタッチするIAMロールを設定

    S3AccessRole:
      Type: "AWS::IAM::Role"
      Properties:
        AssumeRolePolicyDocument:
          Version: "2012-10-17"
          Statement: 
            - 
              Effect: "Allow"
              Principal: 
                Service: 
                  - "ec2.amazonaws.com"
              Action: 
                - "sts:AssumeRole"
        Path: "/"
        Tags:
            - Key: Name
              Value: !Sub "iamrole-${PJPrefix}"
  
    S3AccessPolicies:
      Type: AWS::IAM::Policy
      Properties:
        PolicyName: s3access
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
              - "s3:ListAllMyBuckets"
              - "s3:GetBucketLocation"
            Resource: "arn:aws:s3:::*"
          - Effect: Allow
            Action: "*"
            Resource:
              - !Sub "arn:aws:s3:::s3-bucket-${PJPrefix}"
              - !Sub "arn:aws:s3:::s3-bucket-${PJPrefix}/*"
        Roles:
        - !Ref S3AccessRole

    S3AccessInstanceProfile:
      Type: AWS::IAM::InstanceProfile
      Properties:
        Path: "/"
        Roles:
        - !Ref S3AccessRole

ここでは

            Resource:
              - !Sub "arn:aws:s3:::s3-bucket-${PJPrefix}"
              - !Sub "arn:aws:s3:::s3-bucket-${PJPrefix}/*"

に対して全ての動作を許可している.

EC2起動

EC2を以下のような設定で起動

    MyEC2Instance:
      Type: AWS::EC2::Instance
      Properties:
          ImageId: ami-06aa3f7caf3a30282
          InstanceType: t2.micro
          KeyName: !Ref DemoKeyPair
          SecurityGroups:
            - !Ref  EC2SG
          IamInstanceProfile:
            !Ref S3AccessInstanceProfile
          Tags:
            - Key: Name
              Value: !Sub "ec2-${PJPrefix}"
          UserData:
            Fn::Base64: |
              #!/bin/bash
              sudo apt update 
              sudo apt upgrade
              sudo apt  install awscli -y

InstanceType: t2.microでインスタンスタイプを設定.

ImageId: ami-06aa3f7caf3a30282でimage(osなどベースになるソフトウェア)を指定していて、
今回はubuntu20.04が入ったAMIを指定してる.

          UserData:
            Fn::Base64: |

に続けて起動時に実行したいコマンドを記載できる.今回はaws cliをインストールしている.

S3

    S3Bucket:
        Type: "AWS::S3::Bucket"
        Properties: 
            BucketName: !Sub "s3-bucket-${PJPrefix}"

デフォルトの設定だとpublic accessはblockされている.今回はそのまま。

CloudFormation実行

AWS マネジメントコンソールにいき、サービス一覧からAWS CloudFormationを選択.

スタックの作成という場所をクリックする

テンプレートの準備完了、テンプレートファイルのアップロード、を選択して先ほど作成したyml(githubのurl貼ったやつ)をuploadする.

ここでマネジメントコンソール右上のリージョンが想定通りか確認しておく.

スクリーンショット 2023-11-05 16.16.57.png

uploadしたら次へを選択.

ここでは

  • スタック名
  • PJPrefix
  • VPCCIDR
  • PublicSubnetACIDR

を指定する. CIDRについてはデフォルト値のままでよければそのままでよい.

スクリーンショット 2023-11-05 16.31.06.png

次の画面はそのまま次へと押せばよく、そうすると最終画面になる.
一番下の送信を押すと実行されるが、その前に

「AWS CloudFormation によって IAM リソースが作成される場合があることを承認します。」という
確認事項が出てくるのでチェックする

(これはEC2にアタッチするIAM RoleをCloudFormationで作成するため)

スクリーンショット 2023-11-05 16.26.41.png

送信を押すと、プロセス実行中の画面になるのでしばらく待つと起動が完了する.
スクリーンショット 2023-11-05 16.31.20.png

右上のリロードマークを押すと進捗が更新される.

命名したスタック名のプロセスが完了したらOK.

何かエラーになったプロセスがある場合は「根本原因を抽出」でどのプロセスがエラーの大元かわかる.

成功した画面はこんな感じ

スクリーンショット 2023-11-05 16.38.53.png

作成した環境に接続 

Private Keyの取得

サービス一覧からSystem Managerを選択し、左側のパラメータストアを選択

パラメータストアには先ほどcloudformationで作成したキーが格納されている

スクリーンショット 2023-11-05 16.41.07.png

キーを選択し、「値」の復号化された値を表示を押すと、private keyのテキストが表示される.

スクリーンショット 2023-11-05 16.43.14.png

グレーで隠しているが、左下の部分にprivate keyの値が格納されているので、
local pcの適当なpathに key-for-ec2.pemを作成して表示された中身を貼り付ける

key-for-ec2.pem
-----BEGIN RSA PRIVATE KEY-----
表示された中身のの文字列
-----END RSA PRIVATE KEY-----

ここで注意なのは、そのままペーストすると、-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----が改行されないので、ちゃんと改行する.

EC2へ接続

EC2>Instanceで作成されたインスタンスを選択する. 選択したらpublic ipをコピーする.

chmod 400 <path to key-for-ec2.pem>
ssh -i <path to key-for-ec2.pem> ubuntu@<public ip for ec2>

には先ほど作成したkeyのパスをにはインスタンスのpubic ipをコピーする.

接続すると、

This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?

と聞かれるのでyesとタイプしエンター.
そうすると接続できているはず。

また、作成したbucketをaws s3 lsでみれていることを確認.

課題事項

stackで作成したkey pairをいちいちコピーするのが面倒.
downloadはできないっぽい. EC2 Instance Connectとかの方が良いのかも

あとこれstackが巨大になると大変そうだから、cloud formationをpythonで叩けるAWS CDKも試してみたい

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0