Software Engineering에서 네트워크는 주로 서로 다른 두 서버 간의 통신을 의미한다. 같은 네트워크 내 두 서버 간 통신을 이해하기는 어렵지 않다. 하지만 서로 다른 네트워크 간 통신을 이해하려면 중간의 과정들을 이해해야 한다. AWS에서는 독립적인 네트워크 대역인 VPC를 제공한다. 하나의 서비스 단위로 VPC를 만드는 경우도 있고, 여러 서비스는 하나의 VPC에 넣는 경우도 있다. 일반적으로 회사가 커질수록 서비스 안정성과 보안을 위해 각 용도별로 VPC를 나눈다. 이렇게 VPC를 나누게 되었을 때 네트워크를 구성하는 방법들과 그 원리에 대해서 알아보고자 한다.
VPC
하나의 VPC는 완전 독립적 네트워크 망을 의미한다. 아무런 설정을 하지 않으면 VPC는 외부와 완전히 단절된다. VPC는 여러 개의 서브넷으로 구성된다. 서브넷은 VPC 네트워크 대역을 목적에 맞게 분리한 구역을 의미한다. 예를 들어, VPC가 하나의 학교라고 하면, 서브넷을 각 교실을 의미한다. 각 교실에는 해당 교실의 성격에 맞는 학생들이 들어가듯, 서브넷에는 특정 목적의 서버들이 들어간다. 만약 서버가 외부에 공개되어야 한다면 Public 서브넷, 외부에 공개되지 않아도 된다면 Private 서브넷에 속하는 것이 보통이다.
Public Subnet
Public 서브넷과 Private 서브넷은 AWS에서 사용하는 용어이지만 실제 서비스로 구분되지는 않는다. Public 서브넷과 Private 서브넷을 구분하는 가장 큰 차이는 공인 IP를 가지고 있는가이다.. 서브넷을 생성할 때, 퍼블릭 IPv4 주소 자동 할당 옵션을 활성화할 수 있다. 해당 옵션은 서버가 새롭게 생성될 때, 공인 IP를 자동으로 부여하는 옵션이다.
상식적이라면 공인 IP를 할당받은 서버는 외부에서 접근 가능하다. 테스트를 위해서 Public 서브넷에 인스턴스 하나를 생성하고, ICMP 통신만 허용하도록 설정하였다.
그런데, 이상하게도 통신이 되지 않는다. 이유가 뭘까?
이유는 공인 IP로 들어올 창구인 인터넷 게이트웨이를 만들지 않았기 때문이다. 인터넷 게이트웨이는 VPC의 서버에서 외부 인터넷으로 나가는 통로가 되기도 하지만, 외부에서 VPC 안으로 들어오는 통로이기도 하다. 따라서 공인 IP를 부여받았다고 해서 Public 서브넷의 역할을 온전히 하지 못한다. Public 서브넷으로 만들기 위해서는 인터넷 게이트웨이를 생성하고, 해당 인터넷 게이트웨이를 라우팅 테이블에 등록해야 한다.
위와 같이 인터넷 게이트웨이를 연결하고 나면 통신이 되는 것을 볼 수 있다.
요약하자면, VPC는 외부와 완전하게 격리된 네트워크이다. 만약 외부에서 통신을 하고 싶다고 하면, 인터넷 게이트웨이가 존재해야 한다. 또한 해당 인터넷 게이트웨이를 서브넷의 라우팅 테이블에 등록해야 비로소 외부와 통신할 수 있다. 위 조건을 만족하지 않는다면 설령 Public IP를 부여받더라도 외부와 통신되지 않는다.
Private Subnet
모든 서브넷은 기본적으로 Private 서브넷이다. Public 서브넷과 다르게 Private 서브넷에 생성되는 서버에는 외부에서 통신할 수 있는 공인 IP가 존재하지 않는다. 따라서 외부에서 직접 통신할 수가 없다. 하지만 서버가 외부로 나갈 수 있는 통로는 필요할 수 있다. 예를 들어, 서버를 구성하기 위해 Nginx와 같은 외부 패키지를 설치해야 한다고 하면 서버는 외부 인터넷으로 Outbound 트래픽을 발생시킨다. 외부 인터넷 망에서 통신하기 위해서는 NAT가 필요하다.
NAT는 외부 네트워크와의 통신을 위해서 IP를 중간에 교체해 주는 것을 의미한다. 10.0.0.0/16 대역을 사용하는 VPC에서는 외부 Nginx 서버를 특정할 수 있지만, Nginx 서버는 10.0.0.0/16 대역이 도대체 어디인지 알 방법이 없다. 왜냐하면 10.0.0.0/16 대역은 나의 VPC 안에서만 인식 가능한 private 네트워크 대역이기 때문이다. 따라서 Nginx도 알 수 있는 IP를 가진 서버를 중간에 경유에서 통신을 해야 한다. 이 서버가 바로 NAT 서버이다.
AWS에서 지원하는 NAT 서버는 자체 운영 가능한 NAT Instance와 AWS Managed인 NAT Gateway가 있다. NAT Instance는 Public 서브넷에 직접 서버를 운영하여 NAT 기능을 직접 구현하는 방식으로, 서버 사양을 직접 정할 수 있다는 장점이 있다. 하지만 직접 운영하는 만큼 이중화와 관리의 부담이 크다. NAT Gateway는 AWS가 직접 관리해 주는 NAT 서버이다. NAT Instance와는 다르게 서버 사양을 직접 선택할 수 없다. 다만 AWS에서 관리해 주는 만큼 이중화나 관리의 부담이 없다.
만약 외부와 통신할 일이 없다면 NAT가 연결되어 있지 않는 별도의 Private Subnet을 두는 것이 좋다. 예를 들어 RDS Database 같은 경우 외부 패키지를 설치하거나, 인터넷으로 통신을 하는 경우가 없다. 이런 경우는 완전히 외부와 격리시키기 위해서 NAT가 되지 않는 별도 서브넷이 둘 수 있다.
지금까지 알아본 Single VPC에서의 구성은 다음과 같다. 정식 명칭은 아니지만, 사용법에 따라 서브넷을 크게 3가지로 구분하였다.
Public 서브넷: 인터넷 게이트웨이를 통해서 외부 인터넷과 통신이 자유로운 구간
Private 서브넷: 외부에서 서버로 접근은 불가하고, 서버에서 외부로는 접근이 가능한 구간
Isolated 서브넷: 인터넷과는 통신이 아예 불가한 구간
위 그림과 같이 VPC가 외부와 통신하기 위해서는 여러 가지 리소스와 설정이 필요하다. 다른 VPC의 서버와 통신할 때도 마찬가지이다. 같은 계정에 있더라도 서로 다른 VPC는 네트워크 망이 다르기 때문에 외부 네트워크나 다름이 없다. 하지만 같은 AWS Backbone 네트워크 내에서 존재하는 가상 네트워크 망이기 때문에 물리적으로는 안전하게 소통하도록 만드는 방안이 있다.
지금부터는 여러 VPC 간의 네트워크 통신에 대해서 알아보고자 한다.
VPC Peering
다시 한번 강조하자면, VPC는 하나의 독립된 네트워크 망이다. 서로 다른 VPC는 서로 다른 네트워크 망이다. 따라서 서로 다른 두 네트워크가 통신하기 위해서는 별도의 통로가 필요하다. 그 통로를 만들어 주는 가장 대표적인 방법이 VPC Peering이다.
VPC Peering은 VPN Gateway나 별도 NAT Gateway를 통하지 않고 서로 다른 VPC 간의 통신을 지원하는 기능이다. VPC Peering은 계정, 리전과 상관없이 연결이 가능하다. VPC Peering은 한쪽에서 Peering 요청을 보내고, 받은 쪽에서 이를 수락하는 방식으로 맺어진다.
VPC Peering을 맺는다고 해도 특별하게 새로운 게이트웨이가 생기지 않는다. 즉, NAT Gateway처럼 특정 서버를 통해서 통신이 중계되는 것이 아니라는 의미이다. 즉, 네트워크 Hop이 하나 더 증가하는 구조가 아니라는 의미이다. Peering이 맺어지면, private 네트워크 간 통신이 자유롭게 가능하다. 서로 다른 VPC 간 통신에 있어서 외부 인터넷을 타는 일은 없다. 모든 통신은 AWS Backbone 네트워크 내에서 통신이 이루어진다.
VPC Peering을 맺는다고 모든 서브넷에 있는 서버가 서로 통신할 수 있는 건 아니다. 각 서브넷에 매핑되어 있는 라우팅 테이블에서 목적지 대역과 Peering Connection ID를 추가해야 한다. 따라서 Subnet의 라우터는 목적지 VPC의 IP 대역으로 통신이 발생하면 해당 트래픽을 Peering Connection으로 보낸다.
VPC Peering은 point-to-point 방식의 연결이다. Point-to-point 방식은 1 대 1로만 연결이 되는 구조라서 Transitive 라우팅은 지원하지 않는다. 예를 들어 A와 B가 Peering을 맺고, B와 C가 Peering을 맺어도 A와 C는 소통할 수 없다는 의미이다. 참고로 Transitive 라우팅은 중간에서 자신과 연결과 다른 쪽으로 라우팅을 해주는 것을 뜻한다.
VPC Peering을 맺기 위해서는 두 VPC가 서로 다른 네트워크 대역을 사용해야 한다. 만약 네트워크 대역이 겹친다면 특정 IP가 어느 VPC에 있는 서버를 가리키는지 알 수 없게 된다. 따라서 라우팅 테이블 입장에서는 어디로 트래픽을 보내야 할지 모르는 상황이 발생한다.
Peering을 사용하면 위 그림처럼 통신을 가능하도록 만들고 싶은 모든 VPC 간에 모두 Peering을 맺는 Full Mesh 구조가 나타난다. 중간에 게이트웨이를 거치는 구조가 아니라서 속도가 빠르지만, Peering 수가 많아질수록 구조가 복잡해진다.
AWS Transit Gateway
AWS Transit Gateway는 Peering과는 다르게 hub and spoke 구조로 네트워크를 구성할 수 있는 기능을 지원한다. Transit Gateway는 VPC와의 연결뿐만 아니라 VPN Connection, Direct Connect Connection까지 다양한 연결 형태를 지원한다.
Transit Gateway는 hub로서의 역할을 수행한다. spoke로 연결된 커넥션들을 Attachment라는 구성요소로 생성하여 관리한다. 예를 들어 특정 VPC로 전송하기 위한 통로를 Attachment로 만들어서 Transit Gateway에 붙인다. Transit Gateway는 해당 Attachment를 사용해서 별도의 라우팅 테이블을 구성한다. 라우팅 테이블에 따라서 Tansit Gateway는 트래픽을 다른 곳으로 전달할 수 있다. 이것이 Peering에서는 불가능했던 Transitive 라우팅이다.
아래 그림은 Transit Gateway를 통한 Spoke and Hub 네트워크 디자인이다.
Transit Gateway attachment를 생성하면 별도의 Network Interface(ENI)도 함께 구성된다(정확하게는 Subnet마다 하나씩 생성된다). ENI를 가진다는 것은 특정 서버를 통해서 통신이 중개된다는 의미이다. 예를 들어 VPC 내부 서버(A)에서 다른 VPC에 있는 서버(B)와 통신한다고 가정해 보자. A에서 트래픽이 나갈 때는 서브넷의 라우팅 테이블을 참조한다. 서브넷의 라우팅 테이블에서는 목적지 VPC에 대해서 Transit Gateway를 사용하라고 지정한다. 그러면 라우팅 테이블은 해당 트래픽을 Transit Gateway로 보낸다. 이후에는 Transit Gateway에 연결된 라우팅 테이블에 따라 어떤 Attachment로 나갈지 결정된다. 따라서 Transit Gateway를 사용하면 Network Hop이 하나 더 생긴다.
Transit VPC Solution
Transit VPC는 특정 VPC자체를 Transitive 라우팅을 위한 VPC로 사용하는 방식이다. Transit VPC는 VPC Peering의 한계점을 극복하기 위해서 IPSec 기반의 VPN 연결을 통해 VPC 간 연결을 구현한다. 특정 인스턴스에 라우팅을 위한 소프트웨어를 설치하고, 해당 장비를 통해 VPN overlay 네트워크를 구성한다. 따라서 IP대역이 겹치는 한계점 등을 효과적으로 극복할 수 있다.
Transit VPC도 특정 VPC가 중간에서 라우팅을 해주는 구조이므로 hub and spoke 디자인을 형성한다.
AWS Private Link
AWS Private Link는 AWS Backbone 네트워크만을 이용해서 다른 계정의 VPC 혹은 온프레미스에서 자신의 VPC서비스를 호출할 수 있는 설루션이다. AWS Private Link를 생성하기 위해 우선 자신의 VPC에 Network Load Balancer를 생성한다. 이후에 VPC Endpoint Service를 통해 자신의 Network Load Balancer를 위한 엔트포인트 서비스를 만든다. 사용하는 쪽에서는 Endpoint를 생성할 때 이전에 만든 Endpoint Service를 지정한다. 그러면 서브넷에 Endpoint 서비스와 통신하기 위한 별도의 Network Interface가 생긴다. 그러면 해당 엔드포인트를 타고 안전하게 다른 VPC의 서비스를 호출할 수 있다.
본문 전체 사진 출처: AWS Whitepaper [Building a Scalable and Secure Multi-VPC AWS Network Infrastructure]