SK shieldus Rookies 16기 (클라우드 보안 기술 #03)

만두다섯개·2023년 12월 4일
0

SK 루키즈 16기

목록 보기
25/59

주요 정보

  • 교육 과정명 : 클라우드기반 스마트융합보안 과정 16기
  • 교육 회차 정보 : '23. 12. 04. 클라우드 보안 기술 #03

무엇을 깨달았나

  • AWS를 사용한 인프라 구현을 정보보안 구성에서 본다면, 코드리뷰 검증, 검사가 필요하다.

참고

  • 서울 리전 AZ 4개
  • 인스턴스 유형마다 지원하는 AZ 영역이 다르다. (t2.nano 같은 경우, 버지니아와 서울 리전의 지원 AZ가 다르다)
    -Bitvise SSH Client 설치 : https://www.bitvise.com/ssh-client-download
  • client key manager 가져오기
  • host, port, EC2-User 입력해 로그인 (호스트 퍼블릭 IP, ec2-user )

로드밸런스 사용 이유?

  • 클라이언트는 내부 ip를 지정해 들어가는게 아니라 모르고 접근하는 것이 좋다.
  • 로드밸런스는 내부 네트워크 라우팅 담당(사용자 입장에서도 서비스 품질 향상)

로드 밸런스 적용 영역, 타겟 그룹

  • 타겟 그룹은 로드 밸런스 영역이 적용되는 구간이다.
  • 왜 기존 보안 그룹을 사용하지 않고, 새로운 보안 그룹을 생성하는가? 로드밸런스는 SSH 그룹이 필요없으며 추가로 80 포트 접속 허용 규칙만 가지는 보안그룹을 추가하면 된다.
  • 기존(SSH 접속, 22번 포트) -> 이후 (80번 포트 접속 허용) 규칙을 생성한다.

로드밸런스가 서비스 요청할 요소들을 모아둔 것, 대상그룹

  • 실습에서는 EC2가 대상그룹인 것이다. (내가 이거 추가 안 해서 안 됐었음)
  • 로드밸런스의 DNS 주소로 접근 시, 대상 그룹에 분배된다. (교대로 접속 가능해진다)

여기까지가 2회차에 실습한 내용이다. (로드밸런스를 통해 사용자가 교대로 EC2 로 접근하면 된다.)

로드밸런서를 통해서만 서비스할 수 있도록 제한한다.

  • 현재 로드밸런서 및 EC2 퍼블릭 IP를 사용해 접근 가능.
  • 최소 권한을 부여하기 위해 EC2 퍼블릭 IP 주소를 사용하지 않고 접근 가능하게 한다.
  • 따라서 모든 요청을 로드밸런서를 통해 처리하도록 제한한다.
  • 개별 인스턴스에 로드밸런서로부터 오는 HTTP(80)만 허용하도록 수정한다. ==> 보안그룹
  • 로드밸런서의 보안 그룹 확인한다. (EC2-로드밸런서-보안-보안그룹-인바운드 규칙 편집)
  • 기존 HTTP 유형 규칙 삭제 후 재생성해야 적용된다.
  • 인바운드 규칙에서 HTTP, 소스: 보안그룹(lgSG 선택:

Amazon SNS

  • Simple Notification Service
  • 게시자(생산자)에서 구독자(소비자)로 메시지를 전송하는 관리형 서비스
  • 게시자는 논리적 액세스 지점 및 커뮤니케이션 채널인 주제(topic)에 메시지를 전송하여 구독자와 비동기식으로 통신
  • Fan Out 형 서비스 구현 시, 해당 SNS 방식을 사용한다.

SNS 실습

  • SNS – 주제 생성한다.
  • FIFO: 주제가 발생되는 순서대로 처리한다
  • 순서가 중요하지 않다면 표준 타입으로 유형을 설정한다.

  • 구독을 생성한다.

  • 주제 ARN(생성한 SNS 주제) - 프로토콜(이메일) - 엔드포인트(내 이메일 주소 snddjk...)

  • 내가 메일을 확인해서 confirmed 눌러야 한다. -이후 SNS 구독 상태가 확인으로 변경됨.

  • 웹 서버 인스턴스에 경보를 설정한다. (첫 번째 EC2)

  • 첫 번째 인스턴스로 간다 작업 – 모니터링 및 문제 해결 – CloudWatch 경보 관리

  • 경보 알림(AdminTopic-015) {조건 발생시 해당 토픽을 발행한다} - 경보 임계값

  • CPU 사용률을 30%로 변경 후 생성

  • 로드밸런서를 통해 접근한 첫 번째 EC2에 LOAD TEST를 들어간다

  • 해당 페이지에서는 CPU 사용률을 100%로 올린다.
  • 수 분 내로 CPU 사용량이 올라가고, 메일함에 알람 메일이 온다.
  • cloud watch 에서도 확인 가능하다.
  • 화면 새로고침을 하면(EC2 첫 번째가 새로고침 되어야 한다!!!)
  • 위 방법은 soft 한 방법이다. 즉, 경고 메일만 보내는 것이다. 만약 관리자에게 ~문제가 있다고 조치를 취하라는 알림을 보내라고 하려고 한다면?
  • auto scaling 이 필요하다.

Auto Scaling

  • 애플리케이션 로드(부하) 처리하도록 EC2 인스턴스를 자동으로 증가 또는 감소시키는 기능
  • Scale in out : 개수를 늘리는 것. (동일 사양 H/W 1개 -> 2,3, ... 개), 수평적 확장(로드밸런서 사용한다)
  • Scale Up Down : H/W 성능을 향상 시키는 방법 (메모리 1GB -> 2GB -> ...),

Auto Scaling 실습

  • 인스턴스가 자동으로 추가/삭제 되기 위한 필요한 요소 (Auto Scaling 구성 요소 참고)
  1. 추가/삭제의 기준
  2. 추가/삭제의 명세(시작 템플릿)

Amazon CloudWatch

  • AWS 리소스 및 AWS에서 실행되는 앱 실시간 모니터링 도구
  • 지표를 수집하고 추적 가능하다.

템플릿 생성

  • EC2 – 시작 템플릿 – 시작 템플릿 이름 설정 (webserver-template-015) - Auto Scaling 지침 선택
  • 시작 템플릿 생성 페이지에서 (Auto Scaling 지침)을 설정하면, 필수로 선택해야 하는 항목을 명시해준다.
  • 시작 템플릿 콘텐츠 – Application ans OS Images (webserver-ami-015 선택) - t2.micro 설정 – 키 페어 설정(내가 생성한 Key)
  • 네트워크 설정 – 기존보안그룹 선택 (WebServer 015 추가)
  • 리소스 태그 아래 항목 추가 – 시작 템플릿
  • 대상 그룹에 등록된 대상에 제거 ==> ELB 에 포함되어 있는 인스턴스를 제거
  • Auto Scaling 그룹 == Target Group, 여기서 TG를 제거하면 자동으로 설정된 ASG의 범위가 TG 범위에 포함된 인스턴스들을 포함하게 된다.
  • 따라서 EC2의 보안 그룹의 대상을 삭제한다.

Auto Scaling 그룹 생성

  • EC2 페이지 - webserverASG-015 생성
    시작 템플릿 015, 버전 1 지정
  • 네트워크 : TestVPC-015 지정, 서브넷은 public-subnet-a-015, public-subnet-c-015, 으로 서브넷 지정.
  • 로드 밸런싱 : 기존에 생성한 로드 밸런서에 연결, 상태 확인(인스턴스 상태 확인-미설정으로 사용X), CloudWatch 내 그룹 지표 수집 활성화 설정
  • 그룹 크기 및 크기 조정 구성 : 원하는 용량 2 / 크기조정 : 최소/ 최대 => 2 / 3, 대상 추적 크기 조정 정책 설정 : 평균 CPU 사용률 값이 30% 이상이면 인스턴스를 하나 추가를 할 것이고, 추가하는 인스턴스의 개수를 최소 2개에서 최대 3개 생성할 것이다.
  • 인스턴스 축소 보호란? 급작스러운 인스턴스 축소 조정 작업으로 인해 서비스 제공을 보호하기 위한 기능이다.
  • 알림 추가 : 설정 : SNS 주제 선택(내 이메일)
  • 태그 추가 : 키: Name, 값-선택사항 : webserverASG 추가
  • 로드밸런스 DNS로 접근한 생성된 2개의 인스턴스 확인
  • 부하 100% 발생시킨다. -> 그러면 ASG 설정에 의해 새로운 인스턴스가 추가된다.
  • 로드밸런스로 들어가서 확인 – 3개의 인스턴스가 나누어 보여지는 것을 확인 가능하다.

리소스 삭제 방법

  1. 로드밸런스 삭제
  2. 대상 그룹 삭제 – 내부의 인스턴스들 미사용하기
  3. Auto Scale 삭제 – 삭제 전, 원하는 용량, 최소용량, 최대 용량을 다 0으로 설정 – 삭제
  4. 인스턴스 종료 확인 : 전체 삭제 (WebServer 포함 삭제)
  5. AMI 등록 취소
  6. 스냅샷 삭제
  7. 시작 템플릿 삭제
  8. 보안그룹 삭제
  9. VPC 삭제
  10. 기본 VPC 삭제(VPC 삭제 시, 기본 VPC 생성됌)
  11. SNS에서 주제, 구독 삭제

AWS CloudFormation

  • AWS 리소스를 모델링하고 설정해 리소스 관리 시간을 줄이고, AWS에서 실행되는 애플리케이션에 더 많은 시간을 사용하도록 해 주는 서비스
  • 필요한 모든 AWS 리소스를 설명하는 템플릿을 생성하면 CloudFormation 이 해당 리소스의 프로비저닝과 구성을 담당한다.
  • 프로비저닝이란? 특정 서비스를 제공하기 위해 서비스 실행부터 서비스 제공 받기 전 단계까지의 일련의 절차를 말한다.
  • 클라우드 환경 내 모든 인프라 리소스를 설명하고 프로비저닝할 수 있도록 공통 언어(JSON, YAML)등을 통해 코드 기반 인프라를 구성하고 프로비저닝 할 수 있다.

AWS CloudFormation 사용으로부터 오는 장점

  • 신속한 인프라 복제
  • 인프라 변경 사항을 쉽게 제어, 추적할 수 있다.
  • 인프라 관리 간소화

AWS CloudFormation 구성 요소

  1. 템플릿
  • JSON, YAML 형태 텍스트 파일
  • 스택에서 프로비저닝할 리소스 설명
  • CloudFormation Designer 또는 텍스트 편집기를 사용해 생성 가능
  1. Stack
  • 하나의 단위로 관리할 수 있는 AWS 리소스 모음
  • 스택의 생성, 수정, 삭제를 통해 리소스 모음의 생성, 수정 , 삭제 가능
  • 스택의 모든 리소스는 Cloudformation 템플릿을 통해 정의됌
  • 스택을 삭제하면 관련 리소스가 모두 삭제된다.
  1. 변경 세트
  • 리소스 변경 전 제안된 변경 사항의 요약
  • 변경 사항을 구현하기 이전에 해당 변경이 실행 중인 리소스 특히, 중요 리소스에 미치는 영향을 확인할 수 있다.

CloudFormation 실습 : VPC 생성

1. VPC 생성

  1. VSCode 실행
  • CMD창 – C:\aws 디렉터리이동 – code . 실행
    C:\aws\CreateVPC_01.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Make a VPC 1

Resources:
  ToturialVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 172.0.0.0/16
      EnableDnsHostnames: true

  InternetGateway:
    Type: AWS::EC2::InternetGateway

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref ToturialVPC  (Ref : 내장함수)
      InternetGatewayId: !Ref InternetGateway

  PublicSubnet01:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref ToturialVPC
      CidrBlock: 172.0.0.0/24
      AvailabilityZone: !Select  
        - '0'			=> 가용 영역의 첫 번째 값을 반환
        - !GetAZs ''	=> 만약 서울 리전이라면 ap-northeast-2a, 2b, 2c, 2d를 반환


  PrivateSubnet01:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref ToturialVPC
      CidrBlock: 172.0.1.0/24
      AvailabilityZone: !Select 
        - '0'
        - !GetAZs ''

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref ToturialVPC

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

  PublicSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet01
      RouteTableId: !Ref PublicRouteTable

  PrivateRouteTable:   <= 인터넷 게이트웨이로의 라우팅을 별도로 정의, 연결하지 않음
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref ToturialVPC

  PrivateSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet01
      RouteTableId: !Ref PrivateRouteTable

Outputs:
  VPC:
    Description: Toturial VPC ID
    Value: !Ref ToturialVPC
  AZ1:
    Description: Availability Zone 1
    Value: !GetAtt 
      - PublicSubnet01   => PublicSubnet01에 AZ를 결과물로 내놓는다.
      - AvailabilityZone

내장함수

https://docs.aws.amazon.com/ko_kr/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
1. Ref : 지정된 파라미터 또는 리소스에 대한 정보를 반환한다. (Reference)
2. Fn::Seclect : 인덱스별 객체 목록에서 객체 하나를 반환

  • 짧은 형식으로 !Select [ index, listObjects ]
  1. Fn::GetAZs : 지정된 리전의 가용 영역을 알파벳순으로 나열하는 배열 반환
  • 짧은 형식 => !GetAZs 리전
  • 빈 문자열을 지정하면 AWS:Region 지정하는 것과 같다.
  • AWS:Region 이란? 포괄 리소스를 생성하는 리전을 나타내는 문자열을 반환

2. 스택 생성

  • AWS에서 CloudFormation - 스택 생성
  1. 스택 생성 : 준비된 템플릿 - 템플릿 파일 업록드
    1. VS Code에서 만든 파일 업로드
  2. 스택 이름 CreateVPC-Stack-015 으로 지정

  • 위 .yaml 파일에서 선언한 내용대로 OutPut인 AZ1, VPC가 생성되었다.

3. 생성된 VPC 확인

  • 정말 VPC가 생성되었을까? 확인해보자.

  • VPC ID 가 일치한다.

  • 해당 VPC에는 2개의 서브넷이 존재한다. 서브넷을 확인해보자.
  • 생성된 서브넷 subnet-052df8c996534ab31 /  subnet-00bec86707efcac17

  • 하나의 VPC를 확인해 보니 라우팅 테이블이 존재한다. 이는 외부 인터넷과의 통신을 위한 igw이 라우팅 테이블에 존재한다. 그렇다면 이는 퍼블릭 서브넷이다!
  • 위에서 표기한 .yaml 을 다시 확인해보자.
  1. VPC에서 2개의 서브넷을 생성했다.
    -- 퍼블릭 서브넷은 라우터 테이블과 퍼블릭 라우터를 설정했다.
    -- 프라이빗 서브넷은 프라이빗 테이블만 설정했다.
  2. 두 서브넷의 라우팅 테이블 항목을 비교
    -- 퍼블릭 서브넷은 외부와 통신이 가능
    -- 프라이빗 서브넷은 외부로의 통신이 불가

  • 이런 방식을 사용해 VPC를 생성하면 장점이 뭘까? 이전 실습처럼 하나씩 구성요소를 만드는 것이 아니라 코드만 수정해 다시 VPC를 생성 가능하다.

템플릿 파일 수정 후 VPC 생성

아래와 같이 기존 ymal 에서 수정(추가)하고 저장한다.

AWSTemplateFormatVersion: 2010-09-09
Description: Make a VPC 2

Resources:
  ToturialVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 172.0.0.0/16
      EnableDnsHostnames: true

  InternetGateway:
    Type: AWS::EC2::InternetGateway

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref ToturialVPC
      InternetGatewayId: !Ref InternetGateway

  PublicSubnet02:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref ToturialVPC
      CidrBlock: 172.0.2.0/24
      AvailabilityZone: !Select 
        - '2'
        - !GetAZs ''

  PrivateSubnet02:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref ToturialVPC
      CidrBlock: 172.0.3.0/24
      AvailabilityZone: !Select 
        - '2'
        - !GetAZs ''

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref ToturialVPC

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

  PublicSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet01
      RouteTableId: !Ref PublicRouteTable

  PublicSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet02
      RouteTableId: !Ref PublicRouteTable

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref ToturialVPC

  PrivateSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet01
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet02
      RouteTableId: !Ref PrivateRouteTable

Outputs:
  VPC:
    Description: Toturial VPC ID
    Value: !Ref ToturialVPC
  AZ1:
    Description: Availability Zone 1
    Value: !GetAtt 
      - PublicSubnet01
      - AvailabilityZone
  AZ1:
    Description: Availability Zone 3
    Value: !GetAtt 
      - PublicSubnet02
      - AvailabilityZone
  1. 스택 생성(업데이트)
  • CloudFormation에서 - 기존 스택 - 업데이트 - 현재 템플릿 교체

스택 삭제

  • CloudFormation사용의 장점은 스택을 삭제하면, 리소스들도 한 번에 삭제된다는 점이다.
  • 스택을 삭제해보자.

  • 서브넷을 확인 할 수 없다. 스택 삭제 시, 리소스가 삭제됨을 알 수 있다.
  • 스택 삭제 시 리소스도 동시에 삭제된다. 그러나 스택을 생성 할 때 사용한 템플릿은 따로 삭제해야 한다. (템플릿 파일을 저장하고 있는 S3 버킷은 별도 삭제 필요)

S3란?

  • 파일 저장소 서비스
  • 객체란? 파일, 등 저장되는 내용물
  • 버킷 : 객체를 저장하는 장소
  • 위 실습에서 사용한 S3 버킷을 삭제하자
  • ?? 내가 올린 버킷이름을 확인 중 다른 사용자가 버킷을 삭제하였다..

  • 이렇게 업로드한 yaml 파일이 존재한다.
  • 템플릿 파일(yaml 파일)은 스택삭제와 무관해 별도 삭제 해주어야 한다.
  • 단, S3 버킷은 내용물을 모두 비우고 삭제해야 한다.

CloudFormation을 이용한 웹 애플리케이션 배포 실습

  • 다음은 웹 애플리케이션을 CloudFormation 이용해 배포해보자.
  • 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": {
        "WebServerInstance": {
            "Type": "AWS::EC2::Instance",  // 인스턴스 생성
            "Metadata": {
                "Comment": "Install a simple PHP application",
                "AWS::CloudFormation::Init": {
                    "config": {
                        "packages": { // 사전 패키징된 앱 및 구성 요소를 다운로드 및 설치 예를 들면 아래에서 "/etc/cfn/cfn-hup.conf" 라는 파일 다운로드시켜준다. 
                            "yum": {
                                "httpd": [],
                                "php": []
                            }
                        },
                        "files": { // EC2 인스턴스에 파일을 생성한다
                            "/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.WebServerInstance.Metadata.AWS::CloudFormation::Init\n",
                                            "action=/opt/aws/bin/cfn-init -s ",
                                            {
                                                "Ref": "AWS::StackId"
                                            },
                                            " -r WebServerInstance ",
                                            " --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" // 위에서 "ARSRedgionArch2AMI" 에서 정의한 값을 가져올 때 정하는 기준, 만약 ap-northeast-1 를 사용한다면 하위 "HVM64": "ami-06cd52961ce9f0d85", "HVMG2": "ami-053cdd503598e4a9d" 값들이 리턴되는 것.
                        },
                        {
                            "Fn::FindInMap": [ // 사용자의 [AWSInstanceType2Arch]에 해당하는 값에 따라  Arch의 값을 반환한다. 즉, "t1.micro" 이면, "Arch": "HVM64" 을 가져오는 것이다. 
                                "AWSInstanceType2Arch",
                                {
                                    "Ref": "InstanceType"
                                },
                                "Arch"
                            ]
                        }
                    ]
                },
                "InstanceType": {
                    "Ref": "InstanceType"
                },
                "SecurityGroups": [
                    {
                        "Ref": "WebServerSecurityGroup"
                    }
                ],
                "UserData": {
                    "Fn::Base64": {
                        "Fn::Join": [
                            "",
                            [
                                "#!/bin/bash -xe\n",
                                "yum install -y aws-cfn-bootstrap\n", // AWS에서 제공하는 유틸리티 패키지로, EC2 인스턴스를 프로비저닝, 초기화 하기 위한 도구. 
                                "# Install the files and packages from the metadata\n",
                                "/opt/aws/bin/cfn-init -v ", // EC2 초기 설정 관리
                                "         --stack ",
                                {
                                    "Ref": "AWS::StackName"
                                },
                                "         --resource WebServerInstance ",
                                "         --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 $? ",  // EC2 인스턴스가 성공적으로 초기화 되었음을 CloudFormation 스택에 알림
                                "         --stack ",
                                {
                                    "Ref": "AWS::StackName"
                                },
                                "         --resource WebServerInstance ",
                                "         --region ",
                                {
                                    "Ref": "AWS::Region"
                                },
                                "\n"
                            ]
                        ]
                    }
                }
            },
            "CreationPolicy": {
                "ResourceSignal": {
                    "Timeout": "PT5M"
                }
            }
        },
        "WebServerSecurityGroup": {
            "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": [
                                "WebServerInstance",
                                "PublicDnsName"
                            ]
                        }
                    ]
                ]
            }
        }
    }
}

AWS::CloudFormation::Init 이란?

  • CloudFormation 템플릿에서 사용되는 리소스 유형 중 하나
  • cfn-init 헬퍼 스크립트에 대하나 구성 작업을 정의
  • EC2 인스턴스를 생성할 때 초기 설정, 패키지 설치, 파일 다운로드, 명령 실행 및 다른 구성 단계를 선언적으로 정의

Amazon 머신 이미지 ID 조회(Properties에서 ImageId를 가져오는 로직)

  • Amazon 머신에서 사용하는 이미지 ID 조회하하기 위한 로직을 아래 그림과 같이 설명한다.
  • Properties: 웹 서비스가 가질 수 있는 속성들
  • ImageId : Amazon 머신에서 사용하는 이미지 ID
  • 이제 JSON에서 Amazon 머신 이미지 ID 조회 로직을 알아볼 수 있게 되었다!

스택 생성 실습

  • 위에서 리뷰한 WebApplication.json 파일을 스택으로 생성해보자.
  • 먼저 기본 VPC 가 존재해야 한다.
  1. CloudFormation - 스택 생성
  • CloudFormation - WebApplication.json 파일을 업로드한다.

  • 스택 이름 : WebApplicationStack-015
  • 파라미터 : t2.nano => WebApplication.json 에서 정의된 것이 나오는 것.
  • default 값이 t2.nano이다.
  • 이후 기본설정으로 전송 버튼을 눌러 스택을 생성한다.
  • 스택이 정상적으로 실행되면, EC2를 확인해보자

  • EC2가 생성되었다. 세부 정보를 확인하고, 퍼블릭 IPv4에 접속해보자.

  1. 템플릿 수정으로 스택으로부터 생성한 EC2 SSH 접속하기
  • 템플릿을 수정해서 생성한 EC2에 SSH 접근이 가능케 한다.
  • 아래 소스 코드를 새로 저장한다.
{
    "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": {
            "Description": "SSH 접속을 허용할 IP 대역", 
            "Type": "String", 
            "MaxLength": "18",       
            "MinLength": "9", 
            "Default": "0.0.0.0/0", 
            "AllowedPattern": "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})/(\\d{1,2})", 
            "ConstraintDescription": "IP CIDR 형식(x.x.x.x/x)을 입력하세요."
        },
        "KeyName": {
            "Description": "SSH 접속에 사용할 키페어 이름", 
            "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": {
        "WebServerInstance": {
            "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 '새로운 내용을 추가한 스택';\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.WebServerInstance.Metadata.AWS::CloudFormation::Init\n",
                                            "action=/opt/aws/bin/cfn-init -s ",
                                            {
                                                "Ref": "AWS::StackId"
                                            },
                                            " -r WebServerInstance ",
                                            " --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"
                    },
                    "SecurityGroups": [
                        {
                            "Ref": "WebServerSecurityGroup"
                        }
                    ],
                    "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 WebServerInstance ",
                                    "         --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 WebServerInstance ",
                                    "         --region ",
                                    {
                                        "Ref": "AWS::Region"
                                    },
                                    "\n"
                                ]
                            ]
                        }
                    }
                },
                "CreationPolicy": {
                    "ResourceSignal": {
                        "Timeout": "PT5M"
                    }
                }
            },
            "WebServerSecurityGroup": {
                "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" }
                        }                    
                    ]
                }
            }
        },
        "Outputs": {
            "WebsiteURL": {
                "Description": "Application URL",
                "Value": {
                    "Fn::Join": [
                        "",
                        [
                            "http://",
                            {
                                "Fn::GetAtt": [
                                    "WebServerInstance",
                                    "PublicDnsName"
                                ]
                            }
                        ]
                    ]
                }
            }
        }
    }
    
  • 해당 파일을 기존 스택에서 템플릿 업데이트 한다.

  • 처음 스택을 생성 할때와는 다르게 키페어와 SSHLocation을 지정할 수 있다. (.json 파일 한글이 깨져 ??? 로 표기된다)
  • 내가 가진 키를 선택하고, SSHLocation 은 그대로 두고 다음을 누른다.
  • 최종 스택 템플릿 업데이트 전, 변경 사항을 확인 가능하다

  • 스택 템플릿 업데이트로 EC2가 새로 생성되었고, 기존의 EC2는 종료되었다.

  • 새로 생성된 EC2를 들어가보면, 수정된 템플릿 내용이 반영됌을 확인 가능하다. (??? 가 나오는 이유는 한글이 깨져서이다.)

  • 웹 페이지에서 나온 ???? 부분은 템플릿의 어느 부분에 존재할까? 바로 이 echo 부분이다.

  • 이제 이 EC2에 Bitvise SSH 프로그램을 사용해 접속해 보자.

  • Client key manager 에서 나의 키페어를 등록해 준다. (import 로 가져온다)

  • 아래 그림처럼 Server, Authentication, 키페어를 가지고 Log in 버튼을 누른다. 성공적으로 시작하면, New Terminal console 창이 나온다. 해당 아이콘을 클릭해보자.

업로드중..

  • 해당 터미널에서 인스턴스의 코드를 확인할 수 있다.

업로드중..

스택 실습 종료 및 스택 정리

  • 실습이 종료되었으니 리소스를 정리하자.
  • 스택 삭제 및 S3 버킷을 삭제한다. (버킷은 자동으로 삭제된다)
  • 스택 삭제 시, 인스턴스도 삭제된다.

업로드중..

profile
磨斧爲針

0개의 댓글