📝 서론
최근 사내 인프라를 분석하던 중, 모든 서비스들이 가상 사설 네트워크인 VPC를 기반으로 분리되어 관리하고 있는 것을 알게되었다. 일반적으로 VPC는 사설 네트워크 인프라로, Public IP를 통하지 않으면 외부 AWS 리소스를 접근할 수 없는 것으로 알고 있는데, 일부 AWS 리소스가 다른 VPC의 AWS 리소스를 Private IP를 통해 사용하고 있는 것으로 확인하였다.
어떤 이유로 이런 동작이 가능한 것인지 조사해보니, VPC Peering 을 통해 다른 VPC에 속한 리소스들과 마치 동일한 VPC 내부에 있는 것처럼 통신이 가능하다는 것을 알게 되었다.
이번 글에서는 VPC Peering을 사용하기 위한 가장 기초적인 토대가 되는 VPC에 대해 살펴보고, Terraform을 이용하여 VPC Peering을 구현함으로써 AWS 인프라를 효과적으로 구축하는 방법을 하나씩 알아보고자 한다.
🔓 VPC 란?
VPC Peering을 알아보기에 앞서, 모든 AWS 리소스의 중심이 되는 VPC에 대한 개념부터 알아보고자 한다.
AWS VPC(Virtual Private Cloud)는 클라우드 환경에서 사용자의 네트워크 인프라를 제공하는 역할을 수행한다. 일반적으로 가정집에서 사용하는 네트워크 인프라를 클라우드 환경에 구현해준 것과 비슷한 역할을 담당하는것이 VPC라고 볼 수 있다.
대다수의 AWS 사용자들은 VPC라는 개념을 명확하게 알고 있지는 못하더라도, AWS Console에서 몇 번의 클릭으로 VPC를 자동적으로 구축하는 경험을 하였을 것이다. 이렇게 생성된 VPC는 지속적인 서비스를 제공하기 위해 EC2를 생성하거나 RDS와 같은 데이터베이스를 구축하려 할 때 자동적으로 VPC에 소속된상태로 관리된다.
AWS를 상세하게 다뤄본 사용자들은 VPC와 연관된 Subnet, Internet Gateway, Route Table 등의 구성요소로 인해 외부 네트워크와의 통신 문제를 겪어본 적이 있을 것이다. 이처럼 VPC는 AWS 인프라에서 가장 기초가 되지만, 이를 명확하게 이해하지 못한다면 인프라 구축에서 많은 문제를 발생시킬 수 있다.
다음 섹션에서는 지금까지 알아본 VPC가 여러 VPC 간의 연결을 가능하게 하는 VPC Peering에 대해 더욱 자세히 알아볼 예정이다.
🔗 VPC Peering
VPC Peering은 별도의 VPC 간 통신을 가능하게 하는 AWS 서비스이다.
일반적으로 VPC는 사설 네트워크로써, 동일한 VPC 내에서만 통신이 가능하다고 알고 있을 것이다. 하지만, VPC Peering은 이러한 제한을 극복하고 별도의 VPC 간에도 Private 한 통신이 가능하게 해준다.
VPC Peering은 왜 필요한가?
모든 AWS 리소스를 하나의 VPC에서만 관리한다면 많은 문제가 발생할 수 있다. 예를 들어, VPC를 생성할 때 CIDR을 잘못 설정하여 IP 할당 대역폭이 비정상적으로 낮아 AWS 리소스를 여러개 생성할 수 없는 상황이거나, 너무 많은 AWS 리소스가 하나의 VPC에 소속되어 있어, 인프라 관리 포인트가 비정상적으로 늘어나는 문제가 발생할 수도 있다.
이러한 문제가 발생하는 상황에서 하나의 VPC가 아니라, 특정 서비스 인프라 단위로 VPC 구분하게 된다면, 여러 관리 포인트를 분산할 수 있게 될 것이고, 우리는 더욱 효율적으로 VPC를 관리할 수 있게 될 것이다.
VPC Peering의 문제점
하지만, VPC Peering은 장점만을 가지고 있지는 않다.
VPC Peering은 Transitive 하지 않은 특성을 가지고 있는데, 예를 들어, VPC A와 B가 Peering 되어 있고, A와 C가 Peering 되어 있어도, B와 C는 통신할 수 없는 특성을 가지고 있다. 즉, 연관된 모든 VPC와 통신하기 위해서는 각각의 VPC마다 Peering을 설정해야하는 문제를 가지고 있다는 것이다.
또다른 문제점은 이후 예제에서도 확인할 예정이지만, VPC Peering은 단순한 Peering 설정 뿐만아니라 Route Table과 Security Group에서도 해당 타겟 VPC에 대한 CIDR를 설정해주어야한다. 그로인해 추가적인 VPC Peering을 위한 관리 포인트가 늘어나게되는 것이다.
이러한 문제점을 가진 VPC Peering을 사용해야하는가?
하지만, 이러한 이유가 있더라도 VPC Peering을 사용하게 된다면, 각각의 관리 포인트를 분산시킬수 있다는 점이 더욱 많은 이점을 얻을 수 있다는 것으로 판단하였고, 해당하는 방법으로 AWS 인프라를 구축해볼 것이다.
다음 섹션에서는 지금까지 알아본 VPC Peering을 통해 2개의 VPC를 구축하고, 해당 VPC가 서로 통신할 수 있는 AWS 인프라를 Terraform으로 구현하여 한번의 CLI 명령어를 통해 모든 인프라를 배포해보도록 할 예정이다.
🌎 Terraform으로 구현하는 VPC Peering
시작하기에 앞서, 일반적으로 VPC는 최대 5개 까지만 생성이 가능하다. 이번에 구현하게될 예제는 2개의 VPC 생성할 예정이므로, 계정에 생성된 VPC가 3개를 초과하였을 경우 에러가 발생할 수 있으므로, 예제를 실행하기 전 실행중인 VPC의 갯수를 확인할 필요가있다.
이번 예제의 경우 Terraform과 AWS Configuration이 설정되어 있다는 것을 가정하고 진행하도록 하겠다. 만약, Terraform과 관련된 설정이 되어 있지않다면, 아래의 링크를 참조하자.
또한, 이번 예제에 대한 Terraform 코드 전문은 아래의 Github Repository 링크에서 확인할 수 있다.
1️⃣ VPC 구현하기
가장 먼저, VPC Peering을 구현하기 위해서는 서로 다른 VPC를 구축해야한다. 이번 예제에서는 a
, b
에 해당하는 2개의 VPC를 구현하고, 각각 임의의 CIDR 블록을 할당한다.
resource "aws_vpc" "a" {
cidr_block = "10.24.0.0/16"
tags = {
Name = "${var.project_name}-vpc-a"
}
}
resource "aws_vpc" "b" {
cidr_block = "10.25.0.0/16"
tags = {
Name = "${var.project_name}-vpc-b"
}
}
2️⃣ Subnet 구현하기
VPC 내에서 Subnet을 이용하여 AWS 리소스(EC2, RDS 등)를 할당한다. 현재 2개의 VPC가 구성된 상태이므로, 각 VPC에 Subnet을 할당하여 다른 AWS 리소스를 정의할 수 있도록 구현해보자.
# VPC A, Subnet
resource "aws_subnet" "a" {
vpc_id = aws_vpc.a.id
cidr_block = "10.24.16.0/20"
availability_zone = "ap-northeast-2a"
tags = {
Name = "${var.project_name}-subnet-a"
}
}
# VPC B, Subnet
resource "aws_subnet" "b" {
vpc_id = aws_vpc.b.id
cidr_block = "10.25.16.0/20"
availability_zone = "ap-northeast-2a"
tags = {
Name = "${var.project_name}-subnet-b"
}
}
각각의 Subnet은 VPC A와 VPC B에 소속되며, Subnet의 CIDR 블록은 각 VPC의 CIDR 블록을 기반으로 구성하였다. 이 외에도 가용 영역(AZ)은 ap-northeast-2a
로 설정하였지만, 실제 환경에서는 다른 AZ를 설정할 수도 있다.
3️⃣ Route Table 설정하기
Route Table은 VPC 내의 네트워크 트래픽이 어떻게 라우팅될지 결정한다. 각 Subnet은 Route Table에 연결되어 있으며, 이를 통해 특정 목적지로 트래픽을 전달할 수 있게된다.
Public Subnet을 구현하기 위해서는 Route Table에 Internet Gateway를 지정해야 하는데, 이번에는 VPC Default Route Table에 설정하여 Subnet의 리소스가 외부 인터넷과 통신할 수 있도록 구현하도록 하겠다.
# AWS Internet gateway
resource "aws_internet_gateway" "a" {
vpc_id = aws_vpc.a.id
tags = {
Name = "${var.project_name}-ig-a"
}
}
resource "aws_internet_gateway" "b" {
vpc_id = aws_vpc.b.id
tags = {
Name = "${var.project_name}-ig-b"
}
}
# VPC A, Route Table
resource "aws_default_route_table" "a" {
default_route_table_id = aws_vpc.a.default_route_table_id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.a.id
}
tags = {
Name = "${var.project_name}-rt-a"
}
}
resource "aws_route_table_association" "a" {
subnet_id = aws_subnet.a.id
route_table_id = aws_default_route_table.a.id
}
# VPC B, Route Table
resource "aws_default_route_table" "b" {
default_route_table_id = aws_vpc.b.default_route_table_id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.b.id
}
tags = {
Name = "${var.project_name}-rt-b"
}
}
resource "aws_route_table_association" "b" {
subnet_id = aws_subnet.b.id
route_table_id = aws_default_route_table.b.id
}
VPC A와 VPC B의 Default Route Table이 모든 외부 트래픽(0.0.0.0/0
)을 Internet Gateway로 라우팅하도록 설정하였다.
4️⃣ VPC Peering 구현하기
두 개의 VPC와 각 VPC에 대한 Subnet을 구축을 완료하였다. 이제 마지막으로 VPC Peering 연결을 구현해보도록 하자.
# AWS Caller Identity
data "aws_caller_identity" "current" {}
# VPC Peering, VPC A -> B
resource "aws_vpc_peering_connection" "this" {
peer_owner_id = data.aws_caller_identity.current.account_id # 대상 VPC의 계정 ID
peer_vpc_id = aws_vpc.b.id # 대상 VPC의 ID
vpc_id = aws_vpc.a.id # 현재 VPC의 ID
auto_accept = true # 자동으로 피어링 연결을 수락할지 여부
tags = {
Name = "${var.project_name}-vpc-peering"
}
}
# Add VPC Peering Route
resource "aws_route" "a_to_b" {
route_table_id = aws_vpc.a.default_route_table_id # 현재 VPC의 라우팅 테이블 ID
destination_cidr_block = aws_vpc.b.cidr_block # 대상 VPC의 CIDR 블록
vpc_peering_connection_id = aws_vpc_peering_connection.this.id # VPC 피어링 연결 ID
}
resource "aws_route" "b_to_a" {
route_table_id = aws_vpc.b.default_route_table_id # 현재 VPC의 라우팅 테이블 ID
destination_cidr_block = aws_vpc.a.cidr_block # 대상 VPC의 CIDR 블록
vpc_peering_connection_id = aws_vpc_peering_connection.this.id # VPC 피어링 연결 ID
}
aws_vpc_peering_connection
aws_vpc_peering_connection
Terraform 리소스를 이용하여 두 VPC를 연결하였다. 해당 설정 중에서 vpc_id
와 peer_vpc_id
의 개념이 등장하게 되는데, vpc_id
의 경우 현재 AWS 계정에서 관리하고 있는 VPC를 설정하는 것이고, peer_vpc_id
는 특정 대상의 VPC Id를 나타내는 것이다.
VPC Peering은 동일한 계정에서 관리하는 VPC 뿐만 아니라, 다른 AWS 계정에서 관리하고 있는 VPC 또한 연결해주는 역할을 담당할 수 있어 peer_vpc_id
라는 개념이 나타나게 되었는데, 만약 다른 계정의 VPC와 연결을 설정하려 한다면 peer_owner_id
또한 설정해야한다.
auto_accept
VPC Peering은 일반적으로 AWS Console을 사용해야만 구현할 수 있다. AWS에서 Github의 권한을 얻기 위한 CodeStar와 같이 외부 서비스와 통신하는 서비스의 경우 직접 AWS Console에 접근하여 승인 또는 거절을 명확하게 전달해주어야하는데, VPC Peering 또한 동일한 사유로 인해 Console에서 승인을 해주어야한다.
하지만, Terraform에서는 auto_accept
라는 속성으로 동일한 계정과 리전에 소유한 VPC의 경우 AWS Console에 접근하여 승인하지 않고 구현할 수 있게 된다.
aws_route
VPC Peering 연결이 설정된다면, 각 VPC의 Route Table에 Peering 연결을 통한 라우팅 규칙을 추가하여야한다. 그렇기 때문에, 단순히 Terraform의 aws_vpc_peering_connection
Resource를 선언하는것 뿐만 아니라, 해당하는 정보를 VPC Default Route Table에서 연결할 대상의 CIDR을 선언해주어야한다.
5️⃣ AWS Console 확인하기
모든 Terraform 코드 작성이 완료되고, terraform apply
를 실행하여 AWS 인프라를 배포해보도록 하자.
[AWS Console] VPC Peering
AWS Console로 이동하여 VPC 대시보드에서 피어링 연결 섹션으로 이동하여, VPC Peering이 정상적으로 생성된 것을 확인할 수 있다.
여기서 Peering 수락 여부를 설정하지 않더라도, 상태 여부가 “활성”으로 설정된 것을 확인할 수 있는데, 이는 auto_accept
설정이 성공적으로 반영된 것을 확인할 수 있다.
[AWS Console] Route Table
각 VPC에서 해당하는 Route Table을 확인하여, Terraform을 통해 설정한 라우팅 규칙이 제대로 적용되었는지 확인해보도록하자.
VPC A와 VPC B의 Route Table에서 서로의 CIDR 블록에 대한 라우팅 경로가 정상적으로 설정되어 있는 것을 확인할 수 있다. 만약, VPC Peering만 설정하고, Route Table에 설정을 깜빡하였다면, VPC간의 통신을 수행할 수 없으므로, 유의하도록하자.
✏️ 마지막으로
이렇게 두 개의 VPC를 연결하는 VPC Peering 작업을 수행하였다.
일반적으로 한 개의 프로젝트를 관리하는 상황이라고 한다면, VPC Peering은 그렇게 좋은 판단은 아닐 수 있다.
하지만, VPC Peering은 일반적으로 대규모 프로젝트 또는 수많은 AWS 리소스를 관리하는 복잡한 시나리오에서 엄청난 효율을 보여주게 되는데, 예를 들어, 서로 다른 부서 또는 프로젝트 간에 분리된 네트워크 환경을 유지하면서도 필요한 외부 리소스에 대한 접근을 안전하게 제공할 수 있다는 것이 아주 큰 장점이라고 볼 수 있다.
'Infrastructure > Terraform' 카테고리의 다른 글
효율적인 인프라 관리를 위한 Terraform 모듈 입문하기 (0) | 2024.03.03 |
---|---|
지구를 Terraform으로 물들이다. (Terraform 입문하기) (1) | 2024.02.18 |
[Terraform] 이미 존재하는 AWS 리소스를 가져오기 (0) | 2023.06.03 |