보통의 회사에서는 사내 네트워크를 별도로 구축하고 외부 네트워크와는 분리한다. 하지만 재택근무가 시작하면서 회사 외부에서 사내 시스템을 접속해야 하는 경우가 빈번해졌다. 그로 인해 외부에서 안전하게 사내 네트워크로 접속할 수 있는 솔루션을 도입하기 시작했다. 이때 대표적으로 사용하는 솔루션이 바로 VPN이다.
VPN은 Virtual Private Network의 약자로, 가상의 사설 네트워크를 의미한다. VPN을 사용하면 사내 네트워크와의 암호화된 가상 네트워크 레이어를 구축할 수 있다. 사용자가 VPN Client를 통해 회사의 네트워크와 연결을 맺으면 가상 네트워크 레이어에서 암호화된 터널이 생기고, 그 터널을 사용해서 통신을 할 수 있게 된다.
클라우드를 주로 사용하는 회사의 경우 사내 시스템도 클라우드에 올려서 사용하는 경우가 많다. 즉, 위에서 설명한 사내 네트워크가 곧 클라우드에 구축한 네트워크를 의미한다. 대표적으로 AWS VPC가 있다. AWS VPC는 완전히 독립된 가상 네트워크로 AWS 상에서만 존재하는 네트워크이다. 외부로 나가는 NAT 혹은 Internet Gateway가 없으면 외부와의 통신도 기본적으로 불가능하다. AWS VPC 위에서 동작하는 Amazon RDS, Elasticache 등의 관리형 서비스들 모두 사설망에 두어 외부에서 접근하지 못하도록 만들 수 있다.
AWS Client VPN 이란?
AWS Client VPN은 AWS VPC와 클라이언트 서버 간에 암호화된 네트워크 터널을 만들 수 있는 솔루션이다. 터널(VPN Session)이 생성된다는 의미는 VPC 네트워크와 직접 소통이 가능함을 뜻한다. 따라서 외부에서 접속할 수 없도록 설정한 Private Subnet에 서버를 두더라도 Client VPN을 통해 호출할 수 있다. 사실상 외부에서 접근할 수 있는 경로를 뚫어준 셈이다.
외부와 격리된 네트워크와 통신이 가능하도록 만들면 보안상 허점이 생긴다. 허점을 막기 위해서는 검증된 사용자만 VPN을 연결할 수 있도록 설정해야 한다. AWS Client VPN은 인증서 기반 상호 인증, IDP 혹은 Active Directory 등을 통한 사용자 기반 인증을 제공한다.
인증서 기반 상호 인증은 동일한 CA로부터 발급받은 서버 인증서와 클라이언트 인증서를 통해 유효성 검증한다. AWS Client VPN을 사용하려면 Private CA로부터 발급받은 서버 인증서를 ACM(AWS Certificate Manager)에 등록해야 한다. AWS Client VPN Endpoint를 생성할 때 서버가 ACM에 등록한 사설 인증서를 사용하도록 설정한다. 클라이언트도 서버와 같은 인증서를 사용하도록 설정할 수 있다. 만약, 클라이언트별로 별도의 인증서를 사용하고자 한다면 클라이언트 인증서를 따로 등록할 수 있다. 클라이언트별로 인증서를 분리하면 추후에 특정 인증서를 Revocation 할 수 있다. 자세한 방법은 AWS Client VPN 문서를 참고하기 바란다.
사용자 기반 인증은 IDP 혹인 Active Directory 등에 저장된 사용자를 통해 인증을 처리한다. 대표적으로 Okta를 통한 인증이 있다. Okta인증을 예시로 사용자 인증 처리를 살펴보면 다음과 같다.
1. 사용자는 Open VPN 기반 Application을 통해 VPN 연결을 시도한다.
2. 사전에 Client VPN을 생성하면서 등록한 IDP 메타데이터 정보에서 Redirect URL을 클라이언트에게 보내 인증을 시도하도록 한다.
3. 사용자는 브라우저를 통해 IDP, 여기서는 Okta인증 사이트를 접속한다. 해당 사이트에 로그인을 진행한다.
4. 로그인이 완료되면 IDP는 인증 정보가 담긴 SAML Assertion을 사용자에게 전달한다.
5. VPN Client Application은 해당 SAML Assertion을 다시 AWS Client VPN Endpoint에 전달한다.
6. AWS Client VPN Endpoint는 SAML Assertion정보를 기반으로 접속을 허용하거나 거부한다. 만약 사용자의 Okta 계정이 AWS Client VPN과 연동된 Okta 애플리케이션에 할당되었다면 접속이 허용된다. 할당되지 않았다면 접근 권한이 없으므로 VPN 연결을 맺을 수가 없다.
접근에 대한 권한을 IDP 사용자로 통제하고, IDP 자체의 인증 처리를 강화하는 방식이 앞서 설명한 인증서 기반 방식보다 안전하다. 인증서는 파일이 외부로 공개되면 다른 사람이 해당 인증서를 통해 접근을 시도할 수 있다. 하지만 IDP의 경우 사용자로 등록을 해야 하고, Two factor Authentication, Bio Authenticaion과 같은 추가 인증 처리를 강제할 수 있기 때문에 해킹이 쉽지 않다.
관리 측면에서도 인증서 방식보다 사용자 기반 인증 방식이 효율적이다. 새로운 사용자를 추가할 때 인증서를 발급받는 것보다 Okta 계정을 만들어주는 것이 편리하다. 특정 사용자의 접속을 원치 않으면 애플리케이션에서 제외시키면 그만이다.
AWS Client VPN 통신
인증처리가 끝나고 VPN과 연결이 생성되면 Client VPN에서 지정한 Client IP 대역으로 Network Interface가 생긴다. 테스트를 위해서 Client IP 대역을 10.100.0.0/16 대역으로 설정하였다.
ifconfig 결과를 살펴보면 아래와 같이 10.100.0.130/32 IP 주소를 할당받은 것을 확인할 수 있다.
기본적으로 Client VPN은 모든 트래픽을 Client VPN 터널을 통해서 전달한다. 로컬 서버에 설정된 라우팅 테이블을 살펴보면 0/1과 128.0.0.0/1 대역이 모두 utun3 인터페이스를 사용하도록 설정되어 있다. 0/1 은 0.0.0.0/32 ~ 127.255.255.255/32를 의미하고, 128.0.0.0/1은 그 외 나머지를 의미한다. 즉, 모든 IP 요청을 의미하는 셈이다.
이 상태에서 ping 8.8.8.8을 해보면 아래와 같이 utun3 인터페이스로 통신하는 것을 확인할 수 있다.
모든 통신이 Client VPN을 통하면, google.com과 같은 외부 사이트를 접속할 때 다음과 같은 네트워크 작업을 거친다.
1. 로컬에서 Client VPN 세션 네트워크 설정으로 요청을 전달한다. 요청 대상은 Client VPN Endpoint이다. Client VPN Endpoint ENI에는 Public IP하나를 할당되기 때문에 로컬과 통신이 가능하다.
2. Client VPN Endpoint ENI에 붙어있는 Security Group Rule에 따라 Outbound로 트래픽을 전달한다. Client VPN Endpoint는 AWS VPC의 특정 Subnet에 종속적이다. 따라서 해당 Subnet에 연결된 라우팅 테이블을 기반으로 트래픽을 전달한다.
3. 외부로 나가는 경우, 라우팅테이블에 등록된 Internet Gateway, 혹은 NAT Gateway를 거친다.
2번 과정에서 설정한 Security Group은 사용자가 별도로 지정할 수 있다. 해당 Security Group에서 Inbound는 별도로 설정할 필요가 없다. Client VPN은 기본적으로 외부 대역에서 들어오는 요청은 받아준다. 하지만 outbound의 경우는 풀어주어야 한다.
서비스를 보호하기 위해 Client VPN에서만 접속할 수 있도록 제어를 할 수 있다. 사용 중인 인스턴스 혹은 로드밸런서의 Security Group에 Client VPN Security Group을 Source로 설정한 inbound 규칙을 할당한다. 그러면 internal 통신이라고 하더라도 Client VPN을 통한 네트워크 트래픽만 허용할 수 있다.
이와 같이, 사설 네트워크에 있는 서비스에 안전하게 접근할 수 있다는 장점이 있지만 이 과정에서 VPC 내 네트워크 사용량이 많아지면 비용이 크게 증가할 수 있다. 특히 NAT는 비용이 상당히 비싼 솔루션이기 때문에 사용 시 주의해야 한다. 비용을 효율적으로 관리하기 위해서는 Client VPN을 사용하는 진입점도 최적화가 필요하다.
보안이 필요한 서비스가 아닌 외부 인터넷 접속은 사실상 Client VPN을 사용할 이유가 없다. 이런 경우를 위해서 Client VPN에서는 Split Tunnel 기능을 지원한다. Split Tunnel은 AWS Client VPN을 타야 하는 네트워크 대역만 따로 지정해서 VPN 세션을 사용하도록 설정하는 기능이다. Split Tunnel을 활성화하면, AWS Client VPN Endpoint은 자신의 라우팅 테이블에 등록된 IP 대역을 클라이언트로 전달한다. 클라이언트 애플리케이션은 이 정보를 바탕으로 로컬 라우팅 테이블을 수정한다.
Split Tunnel을 사용한 후 연결을 하면 로컬 라우팅 테이블 정보가 아래와 같이 변경된다. 172.31.0.0/16 대역이 현재 테스트 중인 VPC의 대역이다. 이 외의 네트워크 대역은 기존에 설정한 인터페이스인 en0를 타고 나간다. 따라서 인터넷에서 구글을 검색하면 Client VPN가 아니라 컴퓨터에 연결된 네트워크(ex, WiFi)를 사용한다.
위와 같이 설정한다고 하더라도 악의적으로 라우팅 테이블을 수정하면 Client VPN을 사용하도록 만들 수는 있다. 기본적인 작업은 Client VPN 애플리케이션에서 해주지만, 사용자가 라우팅 테이블을 수정하는 경우가 생길 수 있다. 또한, 사용자 기반 인증을 사용하는 경우, 여러 네트워크 대역을 등록하더라도 제한된 사용자만 사용할 수 있도록 만들어야 하는 경우가 생긴다. 예를 들어, 개발환경과 운영환경을 같은 VPN으로 접속하는 경우, 운영환경에 대한 접근은 일부 사용자로 제한하는 경우가 있다.
위와 같은 요구사항을 충족시키기 위해 Client VPN은 Authorization Rule이라는 기능을 지원한다. Authorization Rule은 사용자 기반 인증으로 설정한 경우 특정 그룹의 ID, 혹은 사용자의 고유 ID를 확인하고 접근을 허용/제한한다. 예를 들어 Okta의 경우, 그룹이름을 넣을 수 있는데, 만약 사용자가 해당 그룹에 속하지 않으면 대상 네트워크로는 트래픽을 보낼 수 없다.
Authorization Rule을 사용하는 경우에도 트래픽은 일단 Client VPN Endpoint로 전달된다. Authorization Rule을 설정해도 라우팅 테이블에 변화가 생기지 않기 때문이다. 하지만 Endpoint에서 Authorization Rule을 기반으로 접근 권한을 판단할 때 권한이 없으면 패킷이 Drop 된다. 이런 경우에는 VPC Network Access Analyzer를 통해서 Endpoint <-> 서비스 간의 통신 가능 여부를 확인할 수 있다. 만약 VPN Endpoint에서 서비스로 접근이 정상적으로 이뤄진다고 하면, packet은 Endpoint에서 Drop 되었음을 알 수 있다.