Always-Try(정보보안 및 일상)

AWS - CloudFormation을 활용한 기본 네트워크 구성 본문

AWS

AWS - CloudFormation을 활용한 기본 네트워크 구성

Always-Try 2021. 7. 31. 23:59

이전 포스팅에서 AWS 퀵 스타트를 진행하며 AWS CloudFormation을 접해보았다. 접해본 김에 기본 구성에 대한 스택을 담은 yml 파일을 만들어봤다. CloudFormation을 사용하면 인프라를 코드로 작성하여 배포 및 삭제 그리고 배포 실패 시 롤백이 간편하다. 어떤식으로 구성했는지에 대한 구성도와 관련 코드는 아래에 공개하겠다.

 

그리고 시중에 CloudFormation, Terraform 등 다양한 Infrastructure as a Code 서비스들이 많이 활용되고 있다. 인프라팀이 아닌 보안팀에서 과연 저것들을 쓸 일이 뭐가 있을까에 대해 고민해봤는데, 보안 관점에서 어떻게 활용도가 딱히 높지도 않을 것 같고, 별다른 관심도 가지 않는다. (뭐 서버리스로 코드를 배포할 일이 있으면 쓰긴 하겠다만, 그럴일이 딱히?)

 

그럼에도 불구하고 한번쯤은 해보는게 좋을 것 같긴하다. 간혹 CloudFormation, Terraform 이런거 할 줄 안다고 어깨가 올라가는 분들이 있는 것 같은데, 왜 그런지 잘 이해가 안간다. Code 구성 자체가 굉장히 쉽게 만들어져 있고, 설명도 자세히 나와 있는걸.. 흠

 

잡소리가 길었고, 기본 구성은 아래와 같이 했다. AWS에서 실습 시에는 서비스나 자원에 대한 비용이 청구될 수 있으니, 항상 주의하면서 테스트하자. 필자는 개인 AWS 계정으로 테스트하고 배포 성공하면 바로 롤백하는 식으로 테스트를 했다.

 

yml 코드는 다음과 같다. 공개하기 어려운 정보가 담긴 인스턴스, 시큐리티 그룹, VPN 등에 대해서는 삭제하고 VPC, Subnet, 가용 영역, Key Pair, IGW, NGW, Cloudtrail, s3 등에 대한 코드만 공개한다. 나머지 부분은 AWS doc에 굉장히 자세하게 잘 나와 있으니, 필요하면 구글링 해보길 바란다.

 

 

 

Parameters:

  EnvironmentName:

    Description: An environment name that is prefixed to resource names

    Type: String



  KeyName:

    Description: Name of an existing EC2 KeyPair to enable SSH access to the instances

    Type: AWS::EC2::KeyPair::KeyName

    ConstraintDescription: must be the name of an existing EC2 KeyPair.



  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.0.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.1.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.3.0/24



Resources:

  VPC:

    Type: AWS::EC2::VPC

    Properties:

      CidrBlock: !Ref VpcCIDR

      EnableDnsSupport: true

      EnableDnsHostnames: true

      Tags:

        - Key: Name

          Value: !Ref EnvironmentName



  InternetGateway:

    Type: AWS::EC2::InternetGateway

    Properties:

      Tags:

        - Key: Name

          Value: !Ref EnvironmentName



  InternetGatewayAttachment:

    Type: AWS::EC2::VPCGatewayAttachment

    Properties:

      InternetGatewayId: !Ref InternetGateway

      VpcId: !Ref VPC



  PublicSubnet1:

    Type: AWS::EC2::Subnet

    Properties:

      VpcId: !Ref VPC

      AvailabilityZone: !Select [ 1, !GetAZs '' ]

      CidrBlock: !Ref PublicSubnet1CIDR

      MapPublicIpOnLaunch: true

      Tags:

        - Key: Name

          Value: !Sub ${EnvironmentName} Public Subnet C



  PublicSubnet2:

    Type: AWS::EC2::Subnet

    Properties:

      VpcId: !Ref VPC

      AvailabilityZone: !Select [ 0, !GetAZs  '' ]

      CidrBlock: !Ref PublicSubnet2CIDR

      MapPublicIpOnLaunch: true

      Tags:

        - Key: Name

          Value: !Sub ${EnvironmentName} Public Subnet A



  PrivateSubnet1:

    Type: AWS::EC2::Subnet

    Properties:

      VpcId: !Ref VPC

      AvailabilityZone: !Select [ 1, !GetAZs  '' ]

      CidrBlock: !Ref PrivateSubnet1CIDR

      MapPublicIpOnLaunch: false

      Tags:

        - Key: Name

          Value: !Sub ${EnvironmentName} Private Subnet D



  PrivateSubnet2:

    Type: AWS::EC2::Subnet

    Properties:

      VpcId: !Ref VPC

      AvailabilityZone: !Select [ 0, !GetAZs  '' ]

      CidrBlock: !Ref PrivateSubnet2CIDR

      MapPublicIpOnLaunch: false

      Tags:

        - Key: Name

          Value: !Sub ${EnvironmentName} Private Subnet B



  NatGateway1EIP:

    Type: AWS::EC2::EIP

    DependsOn: InternetGatewayAttachment

    Properties:

      Domain: vpc



  NatGateway2EIP:

    Type: AWS::EC2::EIP

    DependsOn: InternetGatewayAttachment

    Properties:

      Domain: vpc



  NatGateway1:



    Type: AWS::EC2::NatGateway

    Properties:

      AllocationId: !GetAtt NatGateway1EIP.AllocationId

      SubnetId: !Ref PublicSubnet1



  NatGateway2:

    Type: AWS::EC2::NatGateway

    Properties:

      AllocationId: !GetAtt NatGateway2EIP.AllocationId

      SubnetId: !Ref PublicSubnet2



  PublicRouteTable:

    Type: AWS::EC2::RouteTable

    Properties:

      VpcId: !Ref VPC

      Tags:

        - Key: Name

          Value: !Sub ${EnvironmentName} Public Routes



  DefaultPublicRoute:

    Type: AWS::EC2::Route

    DependsOn: InternetGatewayAttachment

    Properties:

      RouteTableId: !Ref PublicRouteTable

      DestinationCidrBlock: 0.0.0.0/0

      GatewayId: !Ref InternetGateway



  PublicSubnet1RouteTableAssociation:

    Type: AWS::EC2::SubnetRouteTableAssociation

    Properties:

      RouteTableId: !Ref PublicRouteTable

      SubnetId: !Ref PublicSubnet1



  PublicSubnet2RouteTableAssociation:

    Type: AWS::EC2::SubnetRouteTableAssociation

    Properties:

      RouteTableId: !Ref PublicRouteTable

      SubnetId: !Ref PublicSubnet2




  PrivateRouteTable1:

    Type: AWS::EC2::RouteTable

    Properties:

      VpcId: !Ref VPC

      Tags:

        - Key: Name

          Value: !Sub ${EnvironmentName} Private Routes (AZ1)



  DefaultPrivateRoute1:

    Type: AWS::EC2::Route

    Properties:

      RouteTableId: !Ref PrivateRouteTable1

      DestinationCidrBlock: 0.0.0.0/0

      NatGatewayId: !Ref NatGateway1



  PrivateSubnet1RouteTableAssociation:

    Type: AWS::EC2::SubnetRouteTableAssociation

    Properties:

      RouteTableId: !Ref PrivateRouteTable1

      SubnetId: !Ref PrivateSubnet1



  PrivateRouteTable2:

    Type: AWS::EC2::RouteTable

    Properties:

      VpcId: !Ref VPC

      Tags:

        - Key: Name

          Value: !Sub ${EnvironmentName} Private Routes (AZ2)



  DefaultPrivateRoute2:

    Type: AWS::EC2::Route

    Properties:

      RouteTableId: !Ref PrivateRouteTable2

      DestinationCidrBlock: 0.0.0.0/0

      NatGatewayId: !Ref NatGateway2



  PrivateSubnet2RouteTableAssociation:

    Type: AWS::EC2::SubnetRouteTableAssociation

    Properties:

      RouteTableId: !Ref PrivateRouteTable2

      SubnetId: !Ref PrivateSubnet2





  ### CloudTrail and Logging Bucket

  CloudTrail:

    DependsOn:

      - LogBucketPolicy

    Type: "AWS::CloudTrail::Trail"

    Properties:

      S3BucketName: !Ref LogBucket

      IsLogging: true

      EventSelectors:

        - DataResources:

            - Type: "AWS::S3::Object"

              Values:

                - !Join ['', [!GetAtt DataBucket.Arn, '/']]

          IncludeManagementEvents: true

          ReadWriteType: All

      EnableLogFileValidation: true

      IsMultiRegionTrail: false

      IncludeGlobalServiceEvents: true

      TrailName: SecurityTrailLog

  LogBucket:

    Type: 'AWS::S3::Bucket'

    Properties:

      BucketEncryption:

        ServerSideEncryptionConfiguration:

          - ServerSideEncryptionByDefault:

              SSEAlgorithm: 'AES256'

      AccessControl: LogDeliveryWrite

      BucketName: coinonesecuritycelllogbucket

  LogBucketPolicy:

    DependsOn:

      - LogBucket

    Type: "AWS::S3::BucketPolicy"

    Properties:

      Bucket: !Ref LogBucket

      PolicyDocument:

        Version: "2012-10-17"

        Statement:

          -

            Sid: "AWSCloudTrailAclCheck"

            Effect: "Allow"

            Principal:

              Service: "cloudtrail.amazonaws.com"

            Action: "s3:GetBucketAcl"

            Resource:

              Fn::Join:

                - ''

                - ["arn:aws:s3:::", !Ref LogBucket]

          -

            Sid: "AWSCloudTrailWrite"

            Effect: "Allow"

            Principal:

              Service: "cloudtrail.amazonaws.com"

            Action: "s3:PutObject"

            Resource:

              Fn::Join:

                - ''

                - ["arn:aws:s3:::", !Ref LogBucket,'/AWSLogs/*']

            Condition:

              StringEquals:

                s3:x-amz-acl: "bucket-owner-full-control"

  DataBucket:

    Type: 'AWS::S3::Bucket'

    Properties:

      BucketEncryption:

        ServerSideEncryptionConfiguration:

          - ServerSideEncryptionByDefault:

              SSEAlgorithm: 'AES256'

      LoggingConfiguration:

         DestinationBucketName: !Ref LogBucket

         LogFilePrefix: data-bucket-access-logs

      BucketName: coinonesecuritycelldatabucket







Outputs:

  VPC:

    Description: A reference to the created VPC

    Value: !Ref VPC



  PublicSubnets:

    Description: A list of the public subnets

    Value: !Join [ ",", [ !Ref PublicSubnet1, !Ref PublicSubnet2 ]]



  PrivateSubnets:

    Description: A list of the private subnets

    Value: !Join [ ",", [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 ]]



  CloudTrail:

    Description: A reference to the created VPC

    Value: !Ref CloudTrail

 



  VPGVPCSecurity:

    Description: A vpn gateway 

    Value: !Ref VPGVPCSecurity



  CloudTrail:

    Description: Cloudtrail

    Value: !Ref CloudTrail



  LogBucket:

    Description: Bucket of Log

    Value: !Ref LogBucket



  DataBucket:

    Description: Bucket of Data

    Value: !Ref DataBucket



 

  

 

Comments