min8282

[AWS] AWS CloudFormation을 통한 인프라 구성 본문

Security/Cloud

[AWS] AWS CloudFormation을 통한 인프라 구성

min8282 2025. 3. 7. 15:14

이번 글에서는 AWS CloudFormation을 활용하여 인프라를 코드로 관리하는 방법을 다룹니다. CloudFormation을 사용하면 VPC, EC2, 보안 그룹 등 다양한 AWS 리소스를 템플릿(YAML/JSON) 파일로 정의하고, 자동으로 생성 및 관리할 수 있습니다.

 

실습에서는 다음 내용을 수행합니다.

1️⃣ CloudFormation을 사용한 네트워크 구성

  • lab-network.yaml 템플릿을 이용하여 VPC, 서브넷, 인터넷 게이트웨이 등을 생성

2️⃣ 애플리케이션 배포 (EC2 및 보안 그룹 설정)

  • lab-application.yaml 템플릿을 이용하여 EC2 인스턴스(Web Server) 및 보안 그룹을 생성

3️⃣ 드리프트 감지를 활용한 변경 사항 추적

  • CloudFormation에서 제공하는 드리프트 감지 기능을 활용하여
    소스 코드와 실제 환경 간의 차이를 확인

4️⃣ 스택 삭제 및 정리

  • 실습이 끝난 후 생성된 리소스를 CloudFormation 스택 삭제를 통해 정리

이 과정을 통해 Infrastructure as Code(IaC) 개념을 이해하고, AWS 인프라를 효율적으로 관리하는 방법을 익힐 수 있습니다.

 

실습에서 사용할 AWS 리소스 템플릿은 아래와 같이 작성되어 있습니다.

  • lab-network.yaml
더보기

 

AWSTemplateFormatVersion: 2010-09-09
Description: >-
  Network Template: Sample template that creates a VPC with DNS and public IPs enabled.

# This template creates:
#   VPC
#   Internet Gateway
#   Public Route Table
#   Public Subnet

######################
# Resources section
######################

Resources:

  ## VPC

  VPC:
    Type: AWS::EC2::VPC
    Properties:
      EnableDnsSupport: true
      EnableDnsHostnames: true
      CidrBlock: 10.100.0.0/16
      
  ## Internet Gateway

  InternetGateway:
    Type: AWS::EC2::InternetGateway
  
  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  
  ## Public Route Table

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
  
  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: VPCGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  
  ## Public Subnet
  
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.100.0.0/24
      AvailabilityZone: !Select 
        - 0
        - !GetAZs 
          Ref: AWS::Region
  
  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable
  
  PublicSubnetNetworkAclAssociation:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      NetworkAclId: !GetAtt 
        - VPC
        - DefaultNetworkAcl
  
######################
# Outputs section
######################

Outputs:
  
  PublicSubnet:
    Description: The subnet ID to use for public web servers
    Value: !Ref PublicSubnet
    Export:
      Name: !Sub '${AWS::StackName}-SubnetID'

  VPC:
    Description: VPC ID
    Value: !Ref VPC
    Export:
      Name: !Sub '${AWS::StackName}-VPCID'
  • lab-application.yaml
더보기

AWSTemplateFormatVersion: 2010-09-09
Description: >-
  Application Template: Demonstrates how to reference resources from a different stack.
  This template provisions an EC2 instance in a VPC Subnet provisioned in a different stack.

# This template creates:
#   Amazon EC2 instance
#   Security Group

######################
# Parameters section
######################

Parameters:

  NetworkStackName:
    Description: >-
      Name of an active CloudFormation stack that contains the networking
      resources, such as the VPC and subnet that will be used in this stack.
    Type: String
    MinLength: 1
    MaxLength: 255
    AllowedPattern: '^[a-zA-Z][-a-zA-Z0-9]*$'
    Default: lab-network

  AmazonLinuxAMIID:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2

######################
# Resources section
######################

Resources:

  WebServerInstance:
    Type: AWS::EC2::Instance
    Metadata:
      'AWS::CloudFormation::Init':
        configSets:
          All:
            - ConfigureSampleApp
        ConfigureSampleApp:
          packages:
            yum:
              httpd: []
          files:
            /var/www/html/index.html:
              content: |
                <img src="https://s3.amazonaws.com/cloudformation-examples/cloudformation_graphic.png" alt="AWS CloudFormation Logo"/>
                <h1>Congratulations, you have successfully launched the AWS CloudFormation sample.</h1>
              mode: 000644
              owner: apache
              group: apache
          services:
            sysvinit:
              httpd:
                enabled: true
                ensureRunning: true
    Properties:
      InstanceType: t3.micro
      ImageId: !Ref AmazonLinuxAMIID
      NetworkInterfaces:
        - GroupSet:
            - !Ref WebServerSecurityGroup
          AssociatePublicIpAddress: true
          DeviceIndex: 0
          DeleteOnTermination: true
          SubnetId:
            Fn::ImportValue:
              !Sub ${NetworkStackName}-SubnetID
      Tags:
        - Key: Name
          Value: Web Server
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe
          yum update -y aws-cfn-bootstrap
          # Install the files and packages from the metadata
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --configsets All --region ${AWS::Region}
          # Signal the status from cfn-init
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
    CreationPolicy:
      ResourceSignal:
        Timeout: PT5M

  DiskVolume:
    Type: AWS::EC2::Volume
    Properties:
      Size: 100
      AvailabilityZone: !GetAtt WebServerInstance.AvailabilityZone
      Tags:
        - Key: Name
          Value: Web Data
    DeletionPolicy: Snapshot

  DiskMountPoint:
    Type: AWS::EC2::VolumeAttachment
    Properties:
      InstanceId: !Ref WebServerInstance
      VolumeId: !Ref DiskVolume
      Device: /dev/sdh

  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable HTTP ingress
      VpcId:
        Fn::ImportValue:
          !Sub ${NetworkStackName}-VPCID
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: Web Server Security Group

######################
# Outputs section
######################

Outputs:
  URL:
    Description: URL of the sample website
    Value: !Sub 'http://${WebServerInstance.PublicDnsName}'


1. VPC 생성 (lab-network 스택)

스택 생성

CloudFormation>스택>스택 생성(새 리소스 사용) 선

템플릿 준비: 기존 템플릿 선택

템플릿 지정: 템플릿 파일 업로드 > lab-network.yaml 선택

  • 스택 이름: lab-network
  • 3단계와 4단계는 스킵하고 생성

lab-network 스택 생성 완성

생성 확인

VPC 확인: lab-network 스택에 의해 새로운 VPC가 생성된 것을 확인


2. EC2 및 보안 그룹 생성 (lab-application 스택)

모듈화된 템플릿 사용 이유

  • CloudFormation에서 하나의 YAML 파일로 모든 인프라를 생성할 수도 있지만, 역할별로 모듈화 하여 관리하는 것이 유지보수와 협업에 용이함.

스택 생성

CloudFormation > 스택 생성(새 리소스 사용)

템플릿 준비>기존 템플릿 선택

템플릿 지정: 템플릿 파일 업로드 > lab-application.yaml 선택

스택 이름: lab-application

3,4단계는 스킵하고 생성

lab-application 스택 생성 완료 확인

생성 확인

소스 코드 내용대로 EC2(Web Server)가 생성된 것을 확인


3. 드리프트 감지 (Drift Detection)

드리프트 감지 실행

  • lab-application 스택 선택
  • 스택 작업 > 드리프트 결과 보기 선택

  • 스택 드리프트 감지 클릭

  • 드리프트 상태 확인: IN_SYNC (변경 사항 없음)

변경 후 드리프트 감지

그럼 이제 스택(소스코드)과 다르게 변경된 사항이 있다면 어떻게 되는지 확인해 보겠습니다.

보안 그룹에서 스택에 의해 생성된 Web Server Security 보안 그룹 선택

인바운드 규칙 편집

기존 HTTP 규칙 외에 SSH 규칙 추가 후 저장

인바운드 규칙에 새로운 규칙(SSH)이 추가된 것을 확인


변경 사항 확인

lab-application 스택의 드리프트로 돌아와서 스택 드리프트 감지 클릭

새로고침 후 드리프트 상태DRIFTED로 변경된 것을 볼 수 있습니다. 즉, 스택(소스 코드)과 일치하지 않는 다른 설정이 생겼다는 것을 알 수 있습니다.

변경된 부분을 보기 위해서는 리소스 드리프트 상태에서 드리프트 상태가 MODIFEID인 것을 선택하고 드리프트 세부 정보 보기 클릭

변경된 부분을 보면 SecurityGroup(보안그룹)이 변경된 것을 알 수 있고, 변경된 내용도 위와 같이 확인할 수 있습니다.


4. 마무리(스택 삭제)

lab-application 스택 선택 > 삭제 클릭

스택이 삭제되면서 인스턴스도 자동 종료됩니다.

lab-application 스택이 삭제되어 스택에 의해 생성된 인스턴스가 자동으로 종료된 것을 볼 수 있습니다.


lab-network 스택 선택하고 삭제 클릭

lab-network 스택에 의해 생성된 VPC도 삭제되어 찾을 수 없게 됩니다.

 

이번 실습에서는 AWS CloudFormation을 활용하여 VPC와 EC2 인스턴스를 생성하고, 드리프트 감지를 통해 인프라 변경 사항을 추적하는 방법을 알아보았습니다. CloudFormation을 사용하면 인프라를 코드로 관리(IaC)할 수 있어 변경 이력 추적과 자동화가 용이합니다. 더 나아가, CI/CD 파이프라인과 결합하여 자동 배포 환경을 구축할 수도 있습니다. 기회가 된다면 이를 활용한 자동화 배포 방법을 다뤄보겠습니다.