[SK shieldus Rookies 19기] 클라우드 보안 기술 6일차

기록하는짱구·2024년 4월 8일
0

SK Shieldus Rookies 19기

목록 보기
28/43
post-thumbnail

📌 AWS Cloudformation

AWS 리소스를 모델링하고 설정하여 리소스 관리 시간을 줄이고 AWS에서 실행되는 애플리케이션에 더 많은 시간을 사용하도록 해주는 서비스

필요한 모든 AWS 리소스(예: Amazon EC2 인스턴스 또는 Amazon RDS DB 인스턴스)를 설명하는 템플릿을 생성하면 CloudFormation이 해당 리소스의 프로비저닝과 구성을 담당
AWS 리소스를 개별적으로 생성하고 구성할 필요가 없으며 어떤 것이 무엇에 의존하는지 파악할 필요 없이 CloudFormation에서 모든 것을 처리

AWS CloudFormation을 사용하는 경우에는 템플릿 및 스택으로 작업
템플릿을 생성하여 AWS 리소스와 해당 속성에 대해 설명
스택을 생성할 때마다 CloudFormation에서 템플릿에 설명된 리소스를 프로비저닝

AWS Cloudformation 구성요소

템플릿

스택

  • 하나의 단위로 관리할 수 있는 AWS 리소스 모음

  • 스택을 생성, 업데이트, 삭제하여 리소스 모음을 생성, 업데이트 및 삭제

  • 스택의 모든 리소스는 스택의 CloudFormation 템플릿으로 정의

  • 스택을 삭제하면 관련 리소스가 모두 삭제됨

변경 세트

  • 리소스를 변경하기 전에 제안된 변경 사항의 요약

  • 변경 세트를 사용하면 변경 사항을 구현하기 이전에 해당 변경이 실행 중인 리소스에 미치는 영향을 확인할 수 있음

LAB 1. AWS Cloudformation을 활용한 네트워크 생성

VPC를 생성하고, 퍼블릭 서브넷과 프라이빗 서브넷을 각각 한 개씩 생성

① 템플릿 생성

C:\Users\r2com> mkdir c:\aws

C:\Users\r2com>cd c:\aws

c:\aws>code create_vpc.yaml
AWSTemplateFormatVersion: "2010-09-09"

Description: Make a VPC 

Resources:
  RookiesInstVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
  
  RookiesInstIGW:
    Type: AWS::EC2::InternetGateway

  RookiesInstVPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref RookiesInstIGW
      # VpcId: !Ref RookiesInstVPC
      VpcId:
        Ref: RookiesInstVPC

  RookiesInstPublicSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref RookiesInstVPC
      CidrBlock: 10.0.10.0/24
      AvailabilityZone: !Select
        - '0'
        - !GetAZs ''
      
  RookiesInstPrivateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref RookiesInstVPC
      CidrBlock: 10.0.20.0/24
      AvailabilityZone: !Select 
        - '0'
        - !GetAZs ''

  RookiesInstPublicRT:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref RookiesInstVPC

  RookiesInstPublicRoute:
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref RookiesInstIGW
      RouteTableId: !Ref RookiesInstPublicRT

  RookiesInstPublicSubnetRTAssociationA:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref RookiesInstPublicSubnetA
      RouteTableId: !Ref RookiesInstPublicRT

  RookiesInstPrivateRT:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref RookiesInstVPC

  RookiesInstPrivateSubnetRTAssociationA:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref RookiesInstPrivateSubnetA
      RouteTableId: !Ref RookiesInstPrivateRT

Outputs:
  VPC:
    Description: Rookies037VPC's VPC ID
    Value: !Ref Rookies037VPC
  AZa: 
    Description: Availability Zone a
    Value: !GetAtt
      - Rookies037PublicSubnetA
      - AvailabilityZone
Resources:
  Logical ID:				→ 논리적 이름(a-zA-Z0-9)으로 템플릿 내에서 고유
    Type: Resource type		→ 리소스 및 속성 유형 service-provider::service-name::data-type-name
    Properties:
      Set of properties		⇐ 리소스 및 속성 유형별로 가지는 속성

리소스 및 속성 유형

https://docs.aws.amazon.com/ko_kr/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html

AWS::EC2::VPC
https://docs.aws.amazon.com/ko_kr/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpc.html

AWS::EC2::InternetGateway
https://docs.aws.amazon.com/ko_kr/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-internetgateway.html

AWS::EC2::VPCGatewayAttachment
https://docs.aws.amazon.com/ko_kr/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpcgatewayattachment.html

내장 함수

https://docs.aws.amazon.com/ko_kr/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html

가상 파라미터

https://docs.aws.amazon.com/ko_kr/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html

② 스택 생성

나머지 설정을 기본값으로 유지한 상태에서 [다음]과 [전송] 버튼 클릭

③ 출력(output) 확인

템플릿에 outputs 항목의 내용이 출력되는 것을 확인

④ VPC 생성 확인

⑤ 퍼블릭 서브넷 확인

⑥ 퍼블릭 서브넷에 맵핑된 라우팅 테이블 확인

⑦ 프라이빗 서브넷 확인

⑧ 프라이빗 서브넷에 맵핑된 라우팅 테이블 확인

LAB 2. 스택 업데이트

퍼블릭 서브넷, 프라이빗 서브넷 각각을 한 개씩 추가

① 템플릿 수정

AWSTemplateFormatVersion: "2010-09-09"

Description: Make a VPC 

Resources:
  Rookies037VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
  
  Rookies037IGW:
    Type: AWS::EC2::InternetGateway

  Rookies037VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref Rookies037IGW
      # VpcId: !Ref Rookies037VPC
      VpcId:
        Ref: Rookies037VPC

  Rookies037PublicSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref Rookies037VPC
      CidrBlock: 10.0.10.0/24
      AvailabilityZone: !Select
        - '0'
        - !GetAZs ''
      
  Rookies037PrivateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref Rookies037VPC
      CidrBlock: 10.0.20.0/24
      AvailabilityZone: !Select 
        - '0'
        - !GetAZs ''

  Rookies037PublicSubnetB:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref Rookies037VPC
      CidrBlock: 10.0.30.0/24
      AvailabilityZone: !Select
        - '1'
        - !GetAZs ''

  Rookies037PrivateSubnetB:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref Rookies037VPC
      CidrBlock: 10.0.40.0/24
      AvailabilityZone: !Select 
        - '1'
        - !GetAZs ''      

  Rookies037PublicRT:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Rookies037VPC

  Rookies037PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref Rookies037IGW
      RouteTableId: !Ref Rookies037PublicRT

  Rookies037PublicSubnetRTAssociationA:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Rookies037PublicSubnetA
      RouteTableId: !Ref Rookies037PublicRT
  
  Rookies037PublicSubnetRTAssociationB:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Rookies037PublicSubnetB
      RouteTableId: !Ref Rookies037PublicRT

  Rookies037PrivateRT:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Rookies037VPC

  Rookies037PrivateSubnetRTAssociationA:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Rookies037PrivateSubnetA
      RouteTableId: !Ref Rookies037PrivateRT

  Rookies037PrivateSubnetRTAssociationB:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Rookies037PrivateSubnetB
      RouteTableId: !Ref Rookies037PrivateRT

Outputs:
  VPC:
    Description: Rookies037VPC's VPC ID
    Value: !Ref Rookies037VPC
  AZa: 
    Description: Availability Zone a
    Value: !GetAtt
      - Rookies037PublicSubnetA
      - AvailabilityZone

  AZb: 
    Description: Availability Zone b
    Value: !GetAtt
      - Rookies037PublicSubnetB
      - AvailabilityZone

② 스택 업데이트

③ 서브넷 추가 확인

④ 스택 삭제

⑤ 스택에 포함되었던 리소스 확인

⑥ 스택 생성에 사용한 템플릿 파일은 S3 버킷에 보관되어 있으므로 수동으로 삭제해야 함

LAB 3. Cloudformation을 이용한 웹 애플리케이션 배포

기본 VPC에 웹 서버가 설치된 EC2 인스턴스 생성

① 템플릿 정의

C:\aws\WebApplication.json

{
    "AWSTemplateFormatVersion" : "2010-09-09",
    "Description" : "AWS CloudFormation Sample Template: Sample template that can be used to test EC2 updates. **WARNING** This template creates an Amazon Ec2 Instance. You will be billed for the AWS resources used if you create a stack from this template.",
    "Parameters" : {
      "InstanceType" : {
        "Description" : "WebServer EC2 instance type",
        "Type" : "String",
        "Default" : "t2.nano",
        "AllowedValues" : [ 
          "t1.micro", 
          "t2.nano",
          "t2.micro", 
          "t2.small"
        ],
        "ConstraintDescription" : "must be a valid EC2 instance type."
      }
    },
    "Mappings" : {
      "AWSInstanceType2Arch" : {
          "t1.micro"    : { "Arch" : "HVM64"  },
          "t2.nano"     : { "Arch" : "HVM64"  },
          "t2.micro"    : { "Arch" : "HVM64"  },
          "t2.small"    : { "Arch" : "HVM64"  }
      },
      "AWSRegionArch2AMI" : {
        "us-east-1"        : {"HVM64" : "ami-0ff8a91507f77f867", "HVMG2" : "ami-0a584ac55a7631c0c"},
        "us-west-2"        : {"HVM64" : "ami-a0cfeed8", "HVMG2" : "ami-0e09505bc235aa82d"},
        "us-west-1"        : {"HVM64" : "ami-0bdb828fd58c52235", "HVMG2" : "ami-066ee5fd4a9ef77f1"},
        "eu-west-1"        : {"HVM64" : "ami-047bb4163c506cd98", "HVMG2" : "ami-0a7c483d527806435"},
        "eu-west-2"        : {"HVM64" : "ami-f976839e", "HVMG2" : "NOT_SUPPORTED"},
        "eu-west-3"        : {"HVM64" : "ami-0ebc281c20e89ba4b", "HVMG2" : "NOT_SUPPORTED"},
        "eu-central-1"     : {"HVM64" : "ami-0233214e13e500f77", "HVMG2" : "ami-06223d46a6d0661c7"},
        "ap-northeast-1"   : {"HVM64" : "ami-06cd52961ce9f0d85", "HVMG2" : "ami-053cdd503598e4a9d"},
        "ap-northeast-2"   : {"HVM64" : "ami-0a10b2721688ce9d2", "HVMG2" : "NOT_SUPPORTED"},
        "ap-northeast-3"   : {"HVM64" : "ami-0d98120a9fb693f07", "HVMG2" : "NOT_SUPPORTED"},
        "ap-southeast-1"   : {"HVM64" : "ami-08569b978cc4dfa10", "HVMG2" : "ami-0be9df32ae9f92309"},
        "ap-southeast-2"   : {"HVM64" : "ami-09b42976632b27e9b", "HVMG2" : "ami-0a9ce9fecc3d1daf8"},
        "ap-south-1"       : {"HVM64" : "ami-0912f71e06545ad88", "HVMG2" : "ami-097b15e89dbdcfcf4"},
        "us-east-2"        : {"HVM64" : "ami-0b59bfac6be064b78", "HVMG2" : "NOT_SUPPORTED"},
        "ca-central-1"     : {"HVM64" : "ami-0b18956f", "HVMG2" : "NOT_SUPPORTED"},
        "sa-east-1"        : {"HVM64" : "ami-07b14488da8ea02a0", "HVMG2" : "NOT_SUPPORTED"},
        "cn-north-1"       : {"HVM64" : "ami-0a4eaf6c4454eda75", "HVMG2" : "NOT_SUPPORTED"},
        "cn-northwest-1"   : {"HVM64" : "ami-6b6a7d09", "HVMG2" : "NOT_SUPPORTED"}
      }
    },
    "Resources" : {
      "Rookies037WebServerInstance": {  
        "Type" : "AWS::EC2::Instance",
        "Metadata" : {
          "Comment" : "Install a simple PHP application",
          "AWS::CloudFormation::Init" : {
            "config" : {
              "packages" : {                           
                "yum" : {
                  "httpd"             : [],
                  "php"               : []
                }
              },
              "files" : {                              
                "/var/www/html/index.php" : {
                  "content" : { "Fn::Join" : ["", [
                    "<?php\n",
                    "echo '<h1>AWS CloudFormation sample PHP application</h1>';\n",
                    "?>\n"
                  ]]},
                  "mode"    : "000644",
                  "owner"   : "apache",
                  "group"   : "apache"
                },
                "/etc/cfn/cfn-hup.conf" : {
                  "content" : { "Fn::Join" : ["", [
                    "[main]\n",
                    "stack=", { "Ref" : "AWS::StackId" }, "\n",
                    "region=", { "Ref" : "AWS::Region" }, "\n"
                  ]]},
                  "mode" : "000400",
                  "owner" : "root",
                  "group" : "root"
                },
                "/etc/cfn/hooks.d/cfn-auto-reloader.conf" : {
                  "content": { "Fn::Join" : ["", [
                    "[cfn-auto-reloader-hook]\n",
                    "triggers=post.update\n",
                    "path=Resources.Rookies037WebServerInstance.Metadata.AWS::CloudFormation::Init\n", 
                    "action=/opt/aws/bin/cfn-init -s ", { "Ref" : "AWS::StackId" }, 
                       " -r Rookies037WebServerInstance "," --region ", { "Ref" : "AWS::Region" }, "\n",
                    "runas=root\n"
                  ]]}
                }
              },
              "services" : {
                "sysvinit" : {
                  "httpd"   : { "enabled" : "true", "ensureRunning" : "true" },
                  "cfn-hup" : { 
                    "enabled" : "true", "ensureRunning" : "true",
                    "files" : ["/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf"]
                  }
                }
              }
            }
          }
        },
        "Properties": {
          "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" }, { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
          "InstanceType" : { "Ref" : "InstanceType" },
          "SecurityGroups" : [ {"Ref" : "Rookies037WebServerSecurityGroup"} ],
          "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
               "#!/bin/bash -xe\n",
               "yum install -y aws-cfn-bootstrap\n",
               "# Install the files and packages from the metadata\n",
               "/opt/aws/bin/cfn-init -v ",
               "         --stack ", { "Ref" : "AWS::StackName" },
               "         --resource Rookies037WebServerInstance ",
               "         --region ", { "Ref" : "AWS::Region" }, "\n",
               "# Start up the cfn-hup daemon to listen for changes to the Web Server metadata\n",
               "/opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'\n",
               "# Signal the status from cfn-init\n",
               "/opt/aws/bin/cfn-signal -e $? ",
               "         --stack ", { "Ref" : "AWS::StackName" },
               "         --resource Rookies037WebServerInstance ",
               "         --region ", { "Ref" : "AWS::Region" }, "\n"
          ]]}}        
        },
        "CreationPolicy" : {
          "ResourceSignal" : {
            "Timeout" : "PT5M"
          }
        }
      },
      "Rookies037WebServerSecurityGroup" : {
        "Type" : "AWS::EC2::SecurityGroup",
        "Properties" : {
          "GroupDescription" : "Enable HTTP access via port 80",
          "SecurityGroupIngress" : [
            {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"}
          ]
        }      
      }          
    },
    "Outputs" : {
      "WebsiteURL" : {
        "Description" : "Application URL",
        "Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "Rookies037WebServerInstance", "PublicDnsName" ]}]] }
      }
    }
  }

② 스택 생성

InstanceType 파라미터의 값으로 t2.micro를 선택하고, 나머지 설정을 기본값으로 유지한 상태에서 [다음]과 [전송] 버튼 클릭

③ 기본 VPC가 존재하지 않는 경우 오류가 발생하고 스택 생성에 실패

④ 기본 VPC 생성

⑤ 스택을 삭제하고 새로 생성

⑥ EC2 인스턴스 확인

⑦ EC2 인스턴스의 퍼블릭 IP 주소로 접근

LAB 4. 스택 업데이트

SSH 접속이 가능하도록 키페어를 지정하고, 보안그룹에 22번 포트를 허용하도록 수정

① 템플릿 수정

{
    "AWSTemplateFormatVersion" : "2010-09-09",
    "Description" : "AWS CloudFormation Sample Template: Sample template that can be used to test EC2 updates. **WARNING** This template creates an Amazon Ec2 Instance. You will be billed for the AWS resources used if you create a stack from this template.",
    "Parameters" : {
      "InstanceType" : {
        "Description" : "WebServer EC2 instance type",
        "Type" : "String",
        "Default" : "t2.nano",
        "AllowedValues" : [ 
          "t1.micro", 
          "t2.nano",
          "t2.micro", 
          "t2.small"
        ],
        "ConstraintDescription" : "must be a valid EC2 instance type."
      },
      "SSHLocation" : {     → SSH 접속을 허용할 IP 대역             
        "Description" : "The IP address range that can be used to SSH to the EC2 instance", 
        "Type" : "String", 
        
        "MinLength" : "9",
        # 0.0.0.0/0 → 가장 짧은 IP CIDR 표현 = 5개 숫자와 4개의 기호(./)으로 구성
        
        "MaxLength" : "18",     
        # 255.255.255.255/24 → 가장 긴 IP CIDR 표현 = 14개의 숫자와 4개의 기호로 구성
        
        "Default" : "0.0.0.0/0", 
        "AllowedPattern" : "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})/(\\d{1,2})", 
                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~
                            \d{1,3} → 한 자리부터 세 자리까지의 숫자 ⇒ 0 ~ 999
                            \.      → 문자 점(.)을 의미 (정규 표현식에서 점을 이스케이프)
                            \\      → JSON 표현식에서 \ 기호를 이스케이프

        "ConstraintDescription" : "must be a valid IP CIDR range of the form x.x.x.x/x"
      }, 
      
      "KeyName" : {        → SSH 접속에 사용할 키 페어 이름 
      
        "Description" : "Name of existing EC2 key pair for SSH access", 
        "Type" : "AWS::EC2::KeyPair::KeyName"
      }
    },
    "Mappings" : {
      "AWSInstanceType2Arch" : {
          "t1.micro"    : { "Arch" : "HVM64"  },
          "t2.nano"     : { "Arch" : "HVM64"  },
          "t2.micro"    : { "Arch" : "HVM64"  },
          "t2.small"    : { "Arch" : "HVM64"  }
      },
      "AWSRegionArch2AMI" : {
        "us-east-1"        : {"HVM64" : "ami-0ff8a91507f77f867", "HVMG2" : "ami-0a584ac55a7631c0c"},
        "us-west-2"        : {"HVM64" : "ami-a0cfeed8", "HVMG2" : "ami-0e09505bc235aa82d"},
        "us-west-1"        : {"HVM64" : "ami-0bdb828fd58c52235", "HVMG2" : "ami-066ee5fd4a9ef77f1"},
        "eu-west-1"        : {"HVM64" : "ami-047bb4163c506cd98", "HVMG2" : "ami-0a7c483d527806435"},
        "eu-west-2"        : {"HVM64" : "ami-f976839e", "HVMG2" : "NOT_SUPPORTED"},
        "eu-west-3"        : {"HVM64" : "ami-0ebc281c20e89ba4b", "HVMG2" : "NOT_SUPPORTED"},
        "eu-central-1"     : {"HVM64" : "ami-0233214e13e500f77", "HVMG2" : "ami-06223d46a6d0661c7"},
        "ap-northeast-1"   : {"HVM64" : "ami-06cd52961ce9f0d85", "HVMG2" : "ami-053cdd503598e4a9d"},
        "ap-northeast-2"   : {"HVM64" : "ami-0a10b2721688ce9d2", "HVMG2" : "NOT_SUPPORTED"},
        "ap-northeast-3"   : {"HVM64" : "ami-0d98120a9fb693f07", "HVMG2" : "NOT_SUPPORTED"},
        "ap-southeast-1"   : {"HVM64" : "ami-08569b978cc4dfa10", "HVMG2" : "ami-0be9df32ae9f92309"},
        "ap-southeast-2"   : {"HVM64" : "ami-09b42976632b27e9b", "HVMG2" : "ami-0a9ce9fecc3d1daf8"},
        "ap-south-1"       : {"HVM64" : "ami-0912f71e06545ad88", "HVMG2" : "ami-097b15e89dbdcfcf4"},
        "us-east-2"        : {"HVM64" : "ami-0b59bfac6be064b78", "HVMG2" : "NOT_SUPPORTED"},
        "ca-central-1"     : {"HVM64" : "ami-0b18956f", "HVMG2" : "NOT_SUPPORTED"},
        "sa-east-1"        : {"HVM64" : "ami-07b14488da8ea02a0", "HVMG2" : "NOT_SUPPORTED"},
        "cn-north-1"       : {"HVM64" : "ami-0a4eaf6c4454eda75", "HVMG2" : "NOT_SUPPORTED"},
        "cn-northwest-1"   : {"HVM64" : "ami-6b6a7d09", "HVMG2" : "NOT_SUPPORTED"}
      }
    },
    "Resources" : {
      "Rookies037WebServerInstance": {  
        "Type" : "AWS::EC2::Instance",
        "Metadata" : {
          "Comment" : "Install a simple PHP application",
          "AWS::CloudFormation::Init" : {
            "config" : {
              "packages" : {                           
                "yum" : {
                  "httpd"             : [],
                  "php"               : []
                }
              },
              "files" : {                              
                "/var/www/html/index.php" : {
                  "content" : { "Fn::Join" : ["", [
                    "<?php\n",
                    "echo '<h1>AWS CloudFormation sample PHP application</h1>';\n",
                    "echo '<h2>Upgraded version via UpdateStack</h2>';\n",
                    "?>\n"
                  ]]},
                  "mode"    : "000644",
                  "owner"   : "apache",
                  "group"   : "apache"
                },
                "/etc/cfn/cfn-hup.conf" : {
                  "content" : { "Fn::Join" : ["", [
                    "[main]\n",
                    "stack=", { "Ref" : "AWS::StackId" }, "\n",
                    "region=", { "Ref" : "AWS::Region" }, "\n"
                  ]]},
                  "mode" : "000400",
                  "owner" : "root",
                  "group" : "root"
                },
                "/etc/cfn/hooks.d/cfn-auto-reloader.conf" : {
                  "content": { "Fn::Join" : ["", [
                    "[cfn-auto-reloader-hook]\n",
                    "triggers=post.update\n",
                    "path=Resources.Rookies037WebServerInstance.Metadata.AWS::CloudFormation::Init\n", 
                    "action=/opt/aws/bin/cfn-init -s ", { "Ref" : "AWS::StackId" }, 
                       " -r Rookies037WebServerInstance "," --region ", { "Ref" : "AWS::Region" }, "\n",
                    "runas=root\n"
                  ]]}
                }
              },
              "services" : {
                "sysvinit" : {
                  "httpd"   : { "enabled" : "true", "ensureRunning" : "true" },
                  "cfn-hup" : { 
                    "enabled" : "true", "ensureRunning" : "true",
                    "files" : ["/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf"]
                  }
                }
              }
            }
          }
        },
        "Properties": {
          "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" }, { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
          "InstanceType" : { "Ref" : "InstanceType" },
          
          "KeyName" : { "Ref" : "KeyName" }, 
           → 파라미터로 입력받은 SSH 접속에 사용할 키를 지정
          
          "SecurityGroups" : [ {"Ref" : "Rookies037WebServerSecurityGroup"} ],
          "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
               "#!/bin/bash -xe\n",
               "yum install -y aws-cfn-bootstrap\n",
               "# Install the files and packages from the metadata\n",
               "/opt/aws/bin/cfn-init -v ",
               "         --stack ", { "Ref" : "AWS::StackName" },
               "         --resource Rookies037WebServerInstance ",
               "         --region ", { "Ref" : "AWS::Region" }, "\n",
               "# Start up the cfn-hup daemon to listen for changes to the Web Server metadata\n",
               "/opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'\n",
               "# Signal the status from cfn-init\n",
               "/opt/aws/bin/cfn-signal -e $? ",
               "         --stack ", { "Ref" : "AWS::StackName" },
               "         --resource Rookies037WebServerInstance ",
               "         --region ", { "Ref" : "AWS::Region" }, "\n"
          ]]}}        
        },
        "CreationPolicy" : {
          "ResourceSignal" : {
            "Timeout" : "PT5M"
          }
        }
      },
      "Rookies037WebServerSecurityGroup" : {
        "Type" : "AWS::EC2::SecurityGroup",
        "Properties" : {
          "GroupDescription" : "Enable HTTP access via port 80",
          "SecurityGroupIngress" : [
            {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"},
            
            {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "SSHLocation" }}
             → 파라미터로 입력한 IP 주소로 부터의 SSH 접속을 허용
          ]
        }      
      }          
    },
    "Outputs" : {
      "WebsiteURL" : {
        "Description" : "Application URL",
        "Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "Rookies037WebServerInstance", "PublicDnsName" ]}]] }
      }
    }
  }

② 스택 업데이트

③ EC2 인스턴스의 퍼블릭 IP 주소로 접속

[ec2-user@ip-172-31-29-231 ~]$ sudo cat /etc/cfn/cfn-hup.conf
[main]
stack=arn:aws:cloudformation:us-west-2:730335253727:stack/rookies037-webserver-stack/b9914e60-f584-11ee-8fc4-0ad20c4ffffd
region=us-west-2
"/etc/cfn/cfn-hup.conf" : {
                  "content" : { "Fn::Join" : ["", [
                    "[main]\n",
                    "stack=", { "Ref" : "AWS::StackId" }, "\n",
                    "region=", { "Ref" : "AWS::Region" }, "\n"
                  ]]},
                  "mode" : "000400",
                  "owner" : "root",
                  "group" : "root"
                },
[ec2-user@ip-172-31-29-231 ~]$ sudo cat /var/www/html/index.php
<?php
echo '<h1>AWS CloudFormation sample PHP application</h1>';
echo '<h2>Upgraded version via UpdateStack</h2>';
?>
                "/var/www/html/index.php" : {
                  "content" : { "Fn::Join" : ["", [
                    "<?php\n",
                    "echo '<h1>AWS CloudFormation sample PHP application</h1>';\n",
                    "echo '<h2>Upgraded version via UpdateStack</h2>';\n",                    
                    "?>\n"
                  ]]},
                  "mode"    : "000644",
                  "owner"   : "apache",
                  "group"   : "apache"
                },

④ 리소스 정리

스택 및 S3 버킷 삭제

참조: 샘플 템플릿

실습 후에는 반드시 스택과 S3 버킷을 삭제할 것

https://docs.aws.amazon.com/ko_kr/AWSCloudFormation/latest/UserGuide/cfn-sample-templates.html

AWS SDK를 사용한 AWS CloudFormation용 교차 서비스 예제: COVID-19 데이터를 추적하는 API Gateway REST API 생성
https://docs.aws.amazon.com/ko_kr/AWSCloudFormation/latest/UserGuide/example_cross_ApiGatewayDataTracker_section.html

0개의 댓글