0
0

AWS Hands-on for Beginners Network編#1 をCloudFormationでやってみる

Posted at

AWS 初心者向けハンズオン
「Network編#1 AWS上にセキュアなプライベートネットワーク空間を作成する」をCloudFormationで実施してみました。

目的

  • AWS CLIとCloudFormationの実装方法を比較
  • スタックの作成、削除はAWS CLIから実施

完成系
hands-on-beginers_1.drawio.png

AWS CLI編はこちら

スタックの作成方法

※TEMPLATE_FILE名, STACK_NAMEは適宜変更
※IAM リソースを含む場合--capabilities CAPABILITY_NAMED_IAMオプションが必要

TEMPLATE_FILE='~/template/handson_nat.yml'
STACK_NAME=handson

aws cloudformation deploy \
  --template-file ${TEMPLATE_FILE} \
  --stack-name ${STACK_NAME} \
  --capabilities CAPABILITY_NAMED_IAM

スタックの削除方法

※STACK_NAMEは適宜変更

STACK_NAME=handson

aws cloudformation delete-stack \
  --stack-name ${STACK_NAME} 

テンプレート(NAT編)

hands-on-beginers-Step2.drawio.png

handson_nat.yml
AWSTemplateFormatVersion: 2010-09-09
Description: ---

Parameters: 
  VpcCIDR:
    Description: Please enter the IP range (CIDR notation) for this VPC
    Type: String
    Default: "10.0.0.0/16"

  PublicSubnet1CIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
    Type: String
    Default: 10.0.1.0/24

  PublicSubnet2CIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
    Type: String
    Default: 10.0.2.0/24

  PrivateSubnet1CIDR:
    Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
    Type: String
    Default: 10.0.11.0/24

  PrivateSubnet2CIDR:
    Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
    Type: String
    Default: 10.0.12.0/24

Resources: 
  ### VPC
  handsonVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsHostnames: 'true'
      Tags:
      - Key: Name
        Value: handson

  ### Subnet_Public
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref PublicSubnet1CIDR
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Public Subnet - a"

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1c"
      CidrBlock: !Ref PublicSubnet2CIDR
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Public Subnet - c"

  ### Subnet_Private
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref PrivateSubnet1CIDR
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Private subnet - a"

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1c"
      CidrBlock: !Ref PrivateSubnet2CIDR
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Private subnet - c"

  ### Internet Gateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: handson-igw

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

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Public Route Table"

  DefaultPublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Private Route Table"

  ### RouteTable_Association
  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet1

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet2

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet1

  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet2
  
  ### SecurityGroup
  SecurityGroupPublic:
    Type: AWS::EC2::SecurityGroup
    Properties:
        GroupDescription: "beginers-handson SecurityGroup."
        GroupName: "beginers-handson-sg"
        VpcId: !Ref handsonVPC
        SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 80
              ToPort: 80
              CidrIp: 0.0.0.0/0
  
  SecurityGroupPrivate:
    Type: AWS::EC2::SecurityGroup
    Properties:
        GroupDescription: "ssm"
        GroupName: "ssm"
        VpcId: !Ref handsonVPC
        SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 443
              ToPort: 443
              CidrIp: !Ref VpcCIDR

  ### EC2用ロール
  ec2Role:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: 'handson-ssm'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSSMFullAccess'
        - 'arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess'
  
  ### Create IAM Profile
  ec2InstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      InstanceProfileName: handson-ssm
      Path: "/"
      Roles:
        - !Ref ec2Role

  ### Create Public EC2
  PublicEC2:
    Type: "AWS::EC2::Instance"
    Properties:
      AvailabilityZone: ap-northeast-1a
      IamInstanceProfile: !Ref ec2InstanceProfile
      ImageId: "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
      InstanceType: t2.micro
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet1
          GroupSet:
           - !Ref SecurityGroupPublic
      UserData:
        Fn::Base64: |
          #!/bin/bash

          yum -y update
          yum -y install httpd
          systemctl enable httpd.service
          systemctl start httpd.service
      Tags:
      - Key: Name
        Value: "Web"

  ### Create Private EC2
  PrivateEC2:
    Type: "AWS::EC2::Instance"
    Properties:
      AvailabilityZone: ap-northeast-1c
      IamInstanceProfile: !Ref ec2InstanceProfile
      ImageId: "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
      InstanceType: t2.micro
      NetworkInterfaces:
        - AssociatePublicIpAddress: "false"
          DeviceIndex: "0"
          SubnetId: !Ref PrivateSubnet2
          GroupSet:
           - !Ref SecurityGroupPublic
      Tags:
      - Key: Name
        Value: "Internal"

  ### NatGateway
  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
        AllocationId: !GetAtt NatGatewayEIP.AllocationId
        SubnetId: !Ref PublicSubnet2
        Tags:
        - Key: Name
          Value: handson-natgateway

  NatGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
        Domain: vpc

  DefaultPrivateRoute:
    Type: AWS::EC2::Route
    Properties:
        RouteTableId: !Ref PrivateRouteTable
        DestinationCidrBlock: '0.0.0.0/0'
        NatGatewayId: !Ref NatGateway

テンプレート(エンドポイント編)

hands-on-beginers-Step3.drawio.png

hands-on-beginers-Step4.drawio.png

handson_endpoint.yml
AWSTemplateFormatVersion: 2010-09-09
Description: ---

Parameters: 
  VpcCIDR:
    Description: Please enter the IP range (CIDR notation) for this VPC
    Type: String
    Default: "10.0.0.0/16"

  PublicSubnet1CIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
    Type: String
    Default: 10.0.1.0/24

  PublicSubnet2CIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
    Type: String
    Default: 10.0.2.0/24

  PrivateSubnet1CIDR:
    Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
    Type: String
    Default: 10.0.11.0/24

  PrivateSubnet2CIDR:
    Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
    Type: String
    Default: 10.0.12.0/24

Resources: 
  ### VPC
  handsonVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsHostnames: 'true'
      Tags:
      - Key: Name
        Value: handson

  ### Subnet_Public
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref PublicSubnet1CIDR
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Public Subnet - a"

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1c"
      CidrBlock: !Ref PublicSubnet2CIDR
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Public Subnet - c"

  ### Subnet_Private
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref PrivateSubnet1CIDR
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Private subnet - a"

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1c"
      CidrBlock: !Ref PrivateSubnet2CIDR
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Private subnet - c"

  ### Internet Gateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: handson-igw

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

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Public Route Table"

  DefaultPublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref handsonVPC
      Tags:
      - Key: Name
        Value: "Private Route Table"

  ### RouteTable_Association
  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet1

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet2

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet1

  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet2
  
  ### SecurityGroup
  SecurityGroupPublic:
    Type: AWS::EC2::SecurityGroup
    Properties:
        GroupDescription: "beginers-handson SecurityGroup."
        GroupName: "beginers-handson-sg"
        VpcId: !Ref handsonVPC
        SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 80
              ToPort: 80
              CidrIp: 0.0.0.0/0
  
  SecurityGroupPrivate:
    Type: AWS::EC2::SecurityGroup
    Properties:
        GroupDescription: "ssm"
        GroupName: "ssm"
        VpcId: !Ref handsonVPC
        SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 443
              ToPort: 443
              CidrIp: !Ref VpcCIDR

  ### EC2用ロール
  ec2Role:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: 'handson-ssm'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSSMFullAccess'
        - 'arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess'
  
  ### Create IAM Profile
  ec2InstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      InstanceProfileName: handson-ssm
      Path: "/"
      Roles:
        - !Ref ec2Role

  ### Create Public EC2
  PublicEC2:
    Type: "AWS::EC2::Instance"
    Properties:
      AvailabilityZone: ap-northeast-1a
      IamInstanceProfile: !Ref ec2InstanceProfile
      ImageId: "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
      InstanceType: t2.micro
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet1
          GroupSet:
           - !Ref SecurityGroupPublic
      UserData:
        Fn::Base64: |
          #!/bin/bash

          yum -y update
          yum -y install httpd
          systemctl enable httpd.service
          systemctl start httpd.service
      Tags:
      - Key: Name
        Value: "Web"

  ### Create Private EC2
  PrivateEC2:
    Type: "AWS::EC2::Instance"
    Properties:
      AvailabilityZone: ap-northeast-1c
      IamInstanceProfile: !Ref ec2InstanceProfile
      ImageId: "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
      InstanceType: t2.micro
      NetworkInterfaces:
        - AssociatePublicIpAddress: "false"
          DeviceIndex: "0"
          SubnetId: !Ref PrivateSubnet2
          GroupSet:
           - !Ref SecurityGroupPublic
      Tags:
      - Key: Name
        Value: "Internal"

  ### NatGateway
  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
        AllocationId: !GetAtt NatGatewayEIP.AllocationId
        SubnetId: !Ref PublicSubnet2
        Tags:
        - Key: Name
          Value: handson-natgateway

  NatGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
        Domain: vpc

  # DefaultPrivateRoute:
  #   Type: AWS::EC2::Route
  #   Properties:
  #       RouteTableId: !Ref PrivateRouteTable
  #       DestinationCidrBlock: '0.0.0.0/0'
  #       NatGatewayId: !Ref NatGateway

  SSMEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: "com.amazonaws.ap-northeast-1.ssm"
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      VpcId: !Ref handsonVPC
      SubnetIds:
        - !Ref PublicSubnet2
      SecurityGroupIds:
        - !Ref SecurityGroupPrivate

  SSMAgentEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub "com.amazonaws.ap-northeast-1.ssmmessages"
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      VpcId: !Ref handsonVPC
      SubnetIds:
        - !Ref PublicSubnet2
      SecurityGroupIds:
        - !Ref SecurityGroupPrivate

  EC2MessageEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub "com.amazonaws.ap-northeast-1.ec2messages"
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      VpcId: !Ref handsonVPC
      SubnetIds:
        - !Ref PublicSubnet2
      SecurityGroupIds:
        - !Ref SecurityGroupPrivate

  MyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: hands-on-beginners-bucket-20240218

  s3Endpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub "com.amazonaws.ap-northeast-1.s3"
      VpcEndpointType: Gateway
      VpcId: !Ref handsonVPC
      RouteTableIds:
        - !Ref PublicRouteTable
        - !Ref PrivateRouteTable

まとめ

ハンズオンをやった上でのCloudFormationで実装のメリット(AWS CLIでの実装と比較)

  • テンプレートを作成すれば、環境の作成/削除が楽
  • パラメータの値を変えることでIPアドレス等を変えた別環境が簡単に作成できる
  • リソースIDの紐づけが簡単

ハンズオンをやった上でのCloudFormationで実装方法、不明点

  • エンドポイントのタグ名のつけ方が不明
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