0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CloudFormationで基本的なシステム構成を作成してみた

Last updated at Posted at 2024-08-15

以前の記事をバージョンアップさせてみました。
CloudFormationテンプレートサンプルとしてお使いください。

個人的にはMappingsで自動でCIDR範囲を区切ってくれるようにしたところがポイントです。

このテンプレートを使用することで、以下のリソースが作成されます。

  • ネットワーク
    • VPC x1
    • PublicSubnet x2
    • PrivateSubnet(ProtectedSubnet) x2
    • NatGateway x2
  • コンピューティング
    • EC2(Bastion) x1
    • 起動テンプレート x1
      • 暗号化済みEBS
      • 詳細モニタリング有効化
      • UserData(Apache起動、サンプルページ表示)
    • AutoScaling Group x1
      • Target Tracking Policy
      • オートスケーリンググループ別モニタリング有効化
    • Application Load Balancer
      • TargetGroup
      • リスナールール(パスベースルーティング)
      • AccessLogs(宛先はS3)
    • Security Group
      • ALB用セキュリティグループ
      • サーバー用セキュリティグループ
  • IAM
    • インスタンス用ロール
      • AmazonSSMManagedInstanceCore
    • インスタンスプロファイル

イメージはこんな感じ
image.png

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  VPCCidrBlock:
    Description: The primary IPv4 CIDR block for the VPC.
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 10.0.0.0/16
    AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'

  SubnetCidrBits:
    Description: Subnet CidrBits, alowed bitween 8 and 30.
    Type: String
    MinLength: '1'
    MaxLength: '2'
    Default: '24'
    AllowedPattern: '(\d{1,2})'

  PJPrefix:
    Type: String
    Default: base

  AMIID:
    Type: String
    Default: ami-0c8e23f950c7725b9

  AccessLogsAccountID:
    Type: String
    Description: This value will be used in the bucket policy for storing access logs. Change it according to the region you are deploying.
    Default: 127311923021

Mappings:
  CidrBits:
    '30':
      bit: 2
    '29':
      bit: 3
    '28':
      bit: 4
    '27':
      bit: 5
    '26':
      bit: 6
    '25':
      bit: 7
    '24':
      bit: 8
    '23':
      bit: 9
    '22':
      bit: 10
    '21':
      bit: 11
    '20':
      bit: 12
    '19':
      bit: 13
    '18':
      bit: 14
    '17':
      bit: 15
    '16':
      bit: 16
    '15':
      bit: 17
    '14':
      bit: 18
    '13':
      bit: 19
    '12':
      bit: 20
    '11':
      bit: 21
    '10':
      bit: 22
    '9':
      bit: 23
    '8':
      bit: 24

Resources:
################ Create Network ################
  VPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      CidrBlock: !Ref VPCCidrBlock
      Tags:
        - Key: Name
          Value: !Sub '${PJPrefix}-VPC'
  PublicSubnet1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      AvailabilityZone: !Select
        - 0
        - 'Fn::GetAZs': !Ref 'AWS::Region'
      CidrBlock:
        Fn::Select:
          - 0
          - Fn::Cidr:
            - Fn::GetAtt:
              - VPC
              - CidrBlock
            - 4
            - Fn::FindInMap:
              - CidrBits
              - !Ref SubnetCidrBits
              - bit
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub '${PJPrefix}-PublicSubnet1'
      VpcId: !Ref VPC
  PublicSubnet2:
    Type: 'AWS::EC2::Subnet'
    Properties:
      CidrBlock:
        Fn::Select:
          - 1
          - Fn::Cidr:
            - Fn::GetAtt:
              - VPC
              - CidrBlock
            - 4
            - Fn::FindInMap:
              - CidrBits
              - !Ref SubnetCidrBits
              - bit
      AvailabilityZone: !Select
        - 1
        - 'Fn::GetAZs': !Ref 'AWS::Region'
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub '${PJPrefix}-PublicSubnet2'
      VpcId: !Ref VPC
  PrivateSubnet1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      CidrBlock:
        Fn::Select:
          - 2
          - Fn::Cidr:
            - Fn::GetAtt:
              - VPC
              - CidrBlock
            - 4
            - Fn::FindInMap:
              - CidrBits
              - !Ref SubnetCidrBits
              - bit
      AvailabilityZone: !Select
        - 0
        - 'Fn::GetAZs': !Ref 'AWS::Region'
      Tags:
        - Key: Name
          Value: !Sub '${PJPrefix}-PrivateSubnet1'
      VpcId: !Ref VPC
  PrivateSubnet2:
    Type: 'AWS::EC2::Subnet'
    Properties:
      CidrBlock:
        Fn::Select:
          - 3
          - Fn::Cidr:
            - Fn::GetAtt:
              - VPC
              - CidrBlock
            - 4
            - Fn::FindInMap:
              - CidrBits
              - !Ref SubnetCidrBits
              - bit
      AvailabilityZone: !Select
        - 1
        - 'Fn::GetAZs': !Ref 'AWS::Region'
      Tags:
        - Key: Name
          Value: !Sub '${PJPrefix}-PrivateSubnet2'
      VpcId: !Ref VPC
  InternetGateway:
    Type: 'AWS::EC2::InternetGateway'
    DependsOn: VPC
    Properties:
      Tags:
        - Key: Name
          Value: InternetGateway
  VPCGatewayAttachment:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    DependsOn:
      - VPC
      - InternetGateway
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  PublicRouteTable:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      Tags:
        - Key: Name
          Value: PublicRouteTable
      VpcId: !Ref VPC
  PublicRoute:
    Type: 'AWS::EC2::Route'
    DependsOn: VPCGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicSubnetRouteTableAssociation1:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    DependsOn:
      - PublicSubnet1
      - PublicRouteTable
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetRouteTableAssociation2:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    DependsOn:
      - PublicSubnet2
      - PublicRouteTable
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable
  ElasticIP1:
    Type: 'AWS::EC2::EIP'
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: ElasticIP1
  ElasticIP2:
    Type: 'AWS::EC2::EIP'
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: ElasticIP2
  NATGateway1:
    Type: 'AWS::EC2::NatGateway'
    Properties:
      AllocationId: !GetAtt
        - ElasticIP1
        - AllocationId
      SubnetId: !Ref PublicSubnet1
      Tags:
        - Key: Name
          Value: NATGateway1
  NATGateway2:
    Type: 'AWS::EC2::NatGateway'
    Properties:
      AllocationId: !GetAtt
        - ElasticIP2
        - AllocationId
      SubnetId: !Ref PublicSubnet2
      Tags:
        - Key: Name
          Value: NATGateway2
  PrivateRoutetable1:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: PrivateRouteTable1
  PrivateRoute1:
    Type: 'AWS::EC2::Route'
    DependsOn:
      - NATGateway1
    Properties:
      RouteTableId: !Ref PrivateRoutetable1
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway1
  PrivateSubnetRouteTableAssociation1:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      RouteTableId: !Ref PrivateRoutetable1
      SubnetId: !Ref PrivateSubnet1
  PrivateRoutetable2:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: PrivateRouteTable2
  PrivateRoute2:
    Type: 'AWS::EC2::Route'
    Properties:
      RouteTableId: !Ref PrivateRoutetable2
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway2
  PrivateSubnetRouteTableAssociation2:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRoutetable2
  PrivateRoutetable3:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: PrivateRouteTable3
################ Create BastionServer ################
  EC2Instance:
    Type: 'AWS::EC2::Instance'
    Properties: 
      ImageId: !Ref AMIID
      InstanceType: t3.micro
      IamInstanceProfile: !Ref EC2InstanceProfile
      SubnetId: !Ref PrivateSubnet1
      SecurityGroupIds:
        - !Ref InstanceSecurityGroup
      Tags: 
        - Key: Name
          Value: Bastion
  InstanceRole:
    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:
      InstanceProfileName: InstanceRole
      Roles: 
        - !Ref InstanceRole
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow http to client host
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref ALBSecurityGroup
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
################ Create ApplicationLoadBalancer ################
  ALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: alb
      Scheme: internet-facing
      SecurityGroups: 
        - !Ref ALBSecurityGroup
      Subnets: 
        - !Ref PublicSubnet1
        - !Ref PublicSubnet2
      LoadBalancerAttributes:
        - Key: "access_logs.s3.enabled"
          Value: true
        - Key: "access_logs.s3.bucket"
          Value: !Ref AccessLogsBucket
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow http to client host
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: target
      TargetType: instance
      Protocol: HTTP
      Port: 80
      VpcId: !Ref VPC
  HTTPlistener:
    Type: "AWS::ElasticLoadBalancingV2::Listener"
    Properties:
      DefaultActions:
        - Type: forward
          ForwardConfig:
            TargetGroups: 
              - TargetGroupArn: !Ref TargetGroup
      LoadBalancerArn: !Ref ALB
      Port: 80
      Protocol: "HTTP"
  ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions: 
        - Type: forward
          ForwardConfig:
            TargetGroups: 
              - TargetGroupArn: !Ref TargetGroup
      Conditions: 
        - Field: path-pattern
          Values:
            - /main
            - /main/*
      ListenerArn: !Ref HTTPlistener
      Priority: 10
  AccessLogsBucket:
    Type: AWS::S3::Bucket
  
  SampleBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref AccessLogsBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action:
              - 's3:PutObject'
            Effect: Allow
            Resource: !Sub 'arn:aws:s3:::${AccessLogsBucket}/AWSLogs/${AWS::AccountId}/*'
            Principal:
              AWS: !Sub 'arn:aws:iam::${AccessLogsAccountID}:root'

################ Create AutoScalingGroup ################
  LaunchTemplate:
    Type: 'AWS::EC2::LaunchTemplate'
    Properties:
      LaunchTemplateName: ServerTemplate
      LaunchTemplateData:
        IamInstanceProfile:
          Arn: !GetAtt
            - EC2InstanceProfile
            - Arn
        ImageId: !Ref AMIID
        InstanceType: t3.micro
        BlockDeviceMappings:
          - Ebs:
              VolumeSize: 8
              VolumeType: gp2
              DeleteOnTermination: true
              Encrypted: true
            DeviceName: /dev/xvda
        Monitoring: 
          Enabled: true
        MetadataOptions: 
          InstanceMetadataTags: enabled
        SecurityGroupIds:
          - !Ref InstanceSecurityGroup
        TagSpecifications:
          - ResourceType: instance
            Tags:
            - Key: Name
              Value: Server
        UserData:
          Fn::Base64: |
            #!/bin/bash
            yum update -y
            yum install -y httpd
            echo "<h1>Hello World</h1>" > /var/www/html/index.html
            systemctl start httpd
            
  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
      LaunchTemplate:
        LaunchTemplateId: !Ref LaunchTemplate
        Version: !GetAtt LaunchTemplate.LatestVersionNumber
      MaxSize: '10'
      MinSize: '1'
      MetricsCollection:
        - Granularity: 1Minute
      TargetGroupARNs:
        - !Ref TargetGroup
  CPUUtilicationTrackingPolicy:
    Type: AWS::AutoScaling::ScalingPolicy
    Properties:
      AutoScalingGroupName: !Ref AutoScalingGroup
      PolicyType: TargetTrackingScaling
      TargetTrackingConfiguration:
        PredefinedMetricSpecification:
          PredefinedMetricType: ASGAverageCPUUtilization
        TargetValue: 50


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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?