AWS VPC Origin 설정 방법 – CloudFront와 내부 ALB 연결하기 (보안 강화)

안녕하세요. Point-Checks입니다.

이번 포스팅에서는 AWS의 VPC Origin 기능을 활용하여 CloudFront와 내부(Application Load Balancer) ALB를 연결하는 방법을 정리하겠습니다. 기존에는 CloudFront와 ALB를 연결하려면 ALB가 Public Subnet에 위치해야 했습니다. 하지만 VPC Origin을 사용하면 ALB가 내부 네트워크(Private Subnet)에 위치하더라도 CloudFront와 연동할 수 있습니다. 이를 통해 보안성을 높이고 불필요한 인터넷 노출을 방지할 수 있습니다.


1. VPC Origin이란?

VPC Origin은 AWS CloudFront에서 Private ALB를 직접 오리진(Origin)으로 설정할 수 있도록 지원하는 기능입니다. 기존 방식과 비교하면 다음과 같은 차이가 있습니다.

기존 방식: Public Subnet에 위치한 ALB를 통해 CloudFront와 연결


VPC Origin 방식: Private Subnet에 위치한 ALB를 CloudFront의 오리진으로 설정

이를 통해 Public Subnet을 필수적으로 구성할 필요가 없으며, ALB를 Private Subnet에 위치시킬 수 있어 보안성을 강화할 수 있습니다.


2. VPC Origin을 활용한 네트워크 아키텍처

아래는 VPC Origin을 활용한 네트워크 구성 예시입니다.

📌 VPC 구성 요소

  • Public Subnet A: ECS Task가 컨테이너 이미지를 가져오기 위해 사용됨 (ALB와는 무관)
  • Private Subnet B, C: 내부 ALB와 ECS 서비스 배포
  • Internet Gateway 및 NAT Gateway: 인터넷 액세스 필요 시 사용

📌 ALB & CloudFront 구성

  • Private ALB: 내부 트래픽을 처리하는 ALB (인터넷에 노출되지 않음)
  • CloudFront: Private ALB를 오리진으로 설정

3. VPC Origin을 위한 CloudFormation 템플릿 예제

아래는 VPC Origin 환경을 자동으로 생성하는 AWS CloudFormation 코드입니다.

AWSTemplateFormatVersion: 2010-09-09
Resources:
# VPC 생성
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 192.168.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
InstanceTenancy: default
Tags:
- Key: Name
Value: VPC-ORIGIN

# 인터넷 게이트웨이 생성
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: IGW-SEOUL

# VPC에 인터넷 게이트웨이 연결
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
DependsOn:
- VPC
- InternetGateway

# 퍼블릭 서브넷 생성
PublicSubnetB:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 192.168.0.0/20
AvailabilityZone: ap-northeast-2b
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: Public-Subnet-B
DependsOn:
- VPC

# NAT 게이트웨이를 위한 EIP 생성
NatEIP:
Type: AWS::EC2::EIP
DependsOn:
- InternetGateway

# NAT 게이트웨이 생성
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatEIP.AllocationId
SubnetId: !Ref PublicSubnetB
Tags:
- Key: Name
Value: NAT-Gateway
DependsOn:
- PublicSubnetB
- NatEIP

# 프라이빗 서브넷 생성
PrivateSubnetB:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 192.168.80.0/20
AvailabilityZone: ap-northeast-2b
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: Private-Subnet-B
DependsOn:
- VPC

PrivateSubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 192.168.96.0/20
AvailabilityZone: ap-northeast-2c
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: Private-Subnet-C
DependsOn:
- VPC


# 퍼블릭 서브넷 라우트 테이블 생성
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: Public-RouteTable
DependsOn:
- VPC

# IGW를 사용하는 라우트 추가
PublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
DependsOn:
- PublicRouteTable
- InternetGateway

# 퍼블릭 서브넷과 라우트 테이블 연결
PublicARouteAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetB
RouteTableId: !Ref PublicRouteTable
DependsOn:
- PublicSubnetB
- PublicRouteTable

# 프라이빗 서브넷 라우트 테이블 생성
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: Private-RouteTable
DependsOn:
- VPC

# NAT 게이트웨이를 사용하는 라우트 추가
PrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
DependsOn:
- PrivateRouteTable
- NatGateway

# 프라이빗 서브넷과 라우트 테이블 연결
PrivateSubnetBRouteAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetB
RouteTableId: !Ref PrivateRouteTable
DependsOn:
- PrivateSubnetB
- PrivateRouteTable

PrivateSubnetCRouteAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetC
RouteTableId: !Ref PrivateRouteTable
DependsOn:
- PrivateSubnetC
- PrivateRouteTable


# ALB 보안그룹
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow CloudFront access only
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourcePrefixListId: pl-22a6434b
Tags:
- Key: Name
Value: ALB-SG
DependsOn:
- VPC


# Private ALB 추가
PrivateALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: Private-ALB
Scheme: internal
Type: application
Subnets:
- !Ref PrivateSubnetB
- !Ref PrivateSubnetC
SecurityGroups:
- !Ref ALBSecurityGroup
Tags:
- Key: Name
Value: Private-ALB
DependsOn:
- PrivateSubnetB
- PrivateSubnetC

# ALB Target Group 추가
ALBTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
VpcId: !Ref VPC
Protocol: HTTP
Port: 80
TargetType: ip
HealthCheckProtocol: HTTP
HealthCheckPort: traffic-port
HealthCheckPath: "/"
HealthCheckIntervalSeconds: 30
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
Tags:
- Key: Name
Value: ALB-TargetGroup
DependsOn:
- VPC

# ALB Listener 추가
ALBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref PrivateALB
Protocol: HTTP
Port: 80
DefaultActions:
- Type: forward
TargetGroupArn: !Ref ALBTargetGroup
DependsOn:
- PrivateALB
- ALBTargetGroup


# ECS Security Group 추가 (ALB SG만 허용)
ECSServiceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow traffic from ALB only
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ALBSecurityGroup
Tags:
- Key: Name
Value: ECS-Service-SG
DependsOn:
- VPC
- ALBSecurityGroup

# ECS Task Definition 추가
ECSTaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: ecs-task
RequiresCompatibilities:
- FARGATE
Cpu: "256"
Memory: "512"
NetworkMode: awsvpc
ExecutionRoleArn: !Ref TaskExecutionRole
ContainerDefinitions:
- Name: vpc-orign-con
Image: nginx
PortMappings:
- ContainerPort: 80
Memory: 512
Cpu: 256
DependsOn:
- TaskExecutionRole

# ECS Task Execution Role 추가
TaskExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: ECS-TaskExecutionRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: AmazonECSTaskExecutionRolePolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ecr:GetAuthorizationToken
- ecr:BatchCheckLayerAvailability
- ecr:GetDownloadUrlForLayer
- ecr:DescribeImages
- ecr:ListImages
- ecr:BatchGetImage
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "*"
Tags:
- Key: Name
Value: ECS-TaskExecutionRole

# ECS Cluster 추가
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: MyECSCluster
Tags:
- Key: Name
Value: MyECSCluster


# ECS Service 추가
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref ECSCluster
TaskDefinition: !Ref ECSTaskDefinition
LaunchType: FARGATE
DesiredCount: 2 # 태스크 개수 2개
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED
Subnets:
- !Ref PrivateSubnetB
- !Ref PrivateSubnetC
SecurityGroups:
- !Ref ECSServiceSecurityGroup
LoadBalancers:
- TargetGroupArn: !Ref ALBTargetGroup
ContainerName: vpc-orign-con
ContainerPort: 80
DeploymentConfiguration:
DeploymentCircuitBreaker:
Enable: true
Rollback: true
MinimumHealthyPercent: 50
MaximumPercent: 200
DependsOn:
- ECSCluster
- ECSTaskDefinition
- PrivateALB
- ALBTargetGroup
- TaskExecutionRole

4. CloudFront에서 VPC Origin 등록하기

1️⃣ AWS 콘솔에서 CloudFront 이동


2️⃣ VPC Origin 생성

  • 오리진 ARN: Private ALB ARN 설정
  • 프로토콜 설정

3️⃣ CloudFront 배포 생성

  • 생성한 VPC Origin 선택
  • 테스트 환경이므로 WAF 비활성화 가능

4️⃣ 배포 완료 후 CloudFront 도메인 접속

  • 배포까지 약 5분 정도 소요

5. 마무리

이번 포스팅에서는 AWS VPC Origin을 활용하여 CloudFront와 내부 ALB를 연결하는 방법을 살펴봤습니다. 기존 방식과 비교했을 때, Public Subnet 없이도 ALB를 CloudFront와 연결할 수 있어 보안성을 높이고 네트워크 구성을 최적화할 수 있습니다.

💡 추가적인 보안 강화를 위해 WAF(Web Application Firewall) 및 보안 그룹(Security Group) 설정도 함께 고려하는 것이 좋습니다.

다음 포스팅에서는 CloudFront 배포 이후의 성능 최적화 및 추가 보안 설정에 대해 다뤄보겠습니다. 감사합니다! 😊

답글 남기기