Cloud Architect/AWS

[AWS CVPN] 안전하게 VPC 내부에 접근하는 방법은?

"Everything about infra" 2025. 11. 3. 14:48

안녕하세요,

AWS Console에서도 작업이 가능하지만,

부득이하게 VPC 내부 자원에 직접 접근하여 작업을 해야 할 경우

원격으로 안전하게 접속할 수 있는 방법을 알아보도록 하겠습니다.

 

01. AWS Client VPN Endpoint란?

클라우드 환경이 아니여도, VPN을 사용하여 외부에서 내부로 원격 접근을 하는 경우가 많습니다.

하지만 VPN도 어찌되었든 외부와 내부를 연결하는 통로이기 때문에 보안적인 리스크가 존재합니다.

 

AWS Client VPN Endpoint의 장점은 AWS의 IAM 및 ACM 인증서 기반 보안이 결합된 VPN 솔루션입니다 !

  • TLS 기반 암호화 : OpenVPN 프로토콜
  • 인증 방식 : 인증서 기반, Active Directory, SAML 지원
  • 확장성 : 수천 명의 Client 동시 접속 가능.
  • AWS Native 통합 : VPC, IAM, CloudWatch, Lambda 등.

이번에 알아볼 인증 방식은 인증서 기반이며, ACM 인증서와 사설 CA 구축을 통해 CVPN을 사용해볼 예정입니다.

또한 고급 기능 2가지를 아래와 같이 사용해볼 예정입니다

  • Split Tunnel : VPN 연결 시 인터넷 트래픽은 Local에서, 내부 VPC 트래픽만 VPN을 통해 내부 통신 가능.
  • Lambda Authorization : 연결 시 Lambda를 호출하여 동적으로 정책 핸들링.

이 밖에도 SAML 인증 방식을 사용하여 기업 IdP와 연동하여 인증 방식을 더 강력하게 사용이 가능합니다.

 

CVPN의 아키텍처는 위 그림과 같으며, AWS 내부 환경으로 진입 시 Client 인증이 필요합니다.

인증 성공 시에 VPN의 세션이 맺어지며 CVPN에서 설정한 CIDR의 대역을 제공받아 내부 환경에 접근 가능!!

 

또한, 인증이 성공하기 위해 Client 인증서와 서버 인증서가 필요하며, 두 인증서간 신뢰를 검증하기 위해

Root CA라는 CA 인증서가 별도로 필요합니다.

 

그래서 CA 인증서를 생성하기 위해 별도의 EC2 인스턴스를 생성하여 사설 CA인증용 서버를 구축하기로 하였다.


1-1. Easy-rsa CA

Easy-rsa 란?

  • PKI (Public Key Infrastructure) 관리 툴.
  • OpenVPN 등에서 사용하는 인증서 기반 보안을 위해 CA(인증기관) 구축 및 인증서 발급을 자동화.
  • CLI 기반으로 생성을 하며, OpenSSL을 내부적으로 사용하여 내부 서비스 인증서 관리에 적합.

핵심 기능은 아래와 같습니다.

  • CA 생성(Root 인증서 + Key)
  • Server, Client 인증서 발급
  • 인증서 폐기 + CRL 생성

 Easy-rsa PKI 구조

 

/pki/ca.crt : Root CA 인증서

/pki/private/ca.key : Root CA 개인key

/pki/private/*.key : 인증서 개인키

/pki/issued/*.crt : 발급된 인증서

PKI 구조이며, 보안을 위해 일부 내용을 가렸습니다.

 

위에서 말씀드린 ca.crt와 crt, key를 생성한 후에 ACM 인증서에서 위 내용들을 가져온 후 인증서 발급하기.

  • CVPN을 사용하기 위해 총 2개의 인증서가 필요합니다 (Client용, Server용)
  • 즉, 하나의 Root CA를 가지고 두개의 key와 cert를 생성한 후에 ACM에서 가져오자.

ACM 인증서가 성공적으로 발급된 화면입니다.

 

 인증에 필요한 파일

  • <ca>...</ca>
    • AWS Client VPN Endpoint의 인증서를 검증하는데 사용되는 CA 인증서이며, Client는 이 CA 인증서를 신뢰하여 서버가 제시하는 인증서가 유효한지 확인함.
    • 공통된 신뢰 루트이기 때문에 서버와 클라이언트의 CA가 다르면 인증X
  • <cert>...</cert>
    • Client 자신을 VPN 서버에 인증하기 위한 Client 인증서가 포함되어 있으며 Client가 허용된 사용자인지 확인하며 이 인증서는 CA에 의해 서명됨.
  • <key>...</key>
    • Client 인증서에 해당하는 개인키가 포함되어 있으며 개인키를 사용하여 VPN 서버와 통신을 암호화, Client 인증서 소유자 임을 증명한다.

1-2. Easy-rsa 설치하기.

ACM에 인증서를 발급받기 위한 CA 및 키 생성 절차는 아래와 같다.

 

1. 패키지 설치

sudo yum update -y
sudo yum install -y git openssl

 

2. Easy-RSA 설치

cd /opt
sudo git clone https://github.com/OpenVPN/easy-rsa.git
cd easy-rsa/easyrsa3

 

3. PKI 초기화

./easyrsa init-pki

 

4. CA 생성

./easyrsa build-ca

# 또는 비대화식:
./easyrsa --batch build-ca nopass

 

5. Server & Client 인증서 발급

-- server certificate --
./easyrsa gen-req server-name nopass
./easyrsa sign-req server server-name

-- client certificate --
./easyrsa gen-req client-name nopass
./easyrsa sign-req client client-name

 

이렇게 하나의 루트 CA를 생성하고, Server & Client용 인증서 및 키 를 두개 생성하고

ACM에 등록하여 사용할 수 있다.

 

간과할 수 있어서 짚고 넘어가자면, ACM을 왜 사용할까?

  • AWS가 인증기관(CA) 역할을 하여 무료로 SSL/TLS 인증서를 발급해준다
  • 사설 인증서 관리를 위해 사용.

즉, VPC 내부에 접근하기 위해 SSL 프로토콜을 사용 → 인증을 통해 VPN 연결


02. AWS Client VPN Endpoint 생성

생성하기 이전에 앞서 cvpn에서 사용할 security group을 먼저 생성한 다음에, cvpn에 그 SG를 적용시키는 것을 권장합니다.

 

1. 세부 정보 설정

  • 이름은 본인들의 규칙에 따라 자유롭게 작성 후, Description도 작성하는 것을 권장합니다.
  • Endpoint IP address type은 IPv6는 사용하지 않기 때문에 IPv4로 선택.
  • 클라이언트 IPv4 CIDR : 인증에 성공후 VPN 터널 진입 시 할당받는 IP Range 입니다.

2. 인증 정보 및 로깅 설정

보안 때문에 일부 가린 점 양해 부탁드립니다.

  • Easy-rsa에서 생성한 CA 인증서 및 키를 가지고 발급받은 ACM 인증서를 선택
    • 물론 아까 생성한 2개의 ACM 인증서 중 Client용, Server용을 잘 선택하여 적용.
  • 운영환경에서는 로그 및 모니터링이 중요하기 때문에, CloudWatch 까지 같이 사용하자.

3. 연결 핸들러 설정

  • VPN연결 시 Lambda 함수를 실행하는 핸들러를 설정이 가능합니다.
  • 보안 강화를 위해 Lambda 함수를 호출하여 사용이 가능하며, 예시는 아래와 같습니다.

DynamoDB

NoSQL 같은 완전 관리형 Database Service를 사용하여 테이블에 '접근을 허용할 IP를 추가'

 

Lambda 함수

CVPN 연결 시도 시 DynamoDB의 테이블을 불러와서 요청 보낸 IP가 테이블 항목에 있으면 Allow,

만약에 항목에 없다면 Deny 시키는 함수를 생성하여 보안을 강화할 수도 있다.

 

  • 코드는 아래와 같이 공유드리며, python3 런타임을 사용중입니다.
import ipaddress, boto3

def is_public_ip_allowed(public_ip):
    allowed_ips = get_allow_ipset()
    is_allowed = False
    for allowed_ip in allowed_ips:
        if ipaddress.ip_address(public_ip) in ipaddress.ip_network(allowed_ip['ip_cidr']):
            is_allowed = True
            break
    return is_allowed

def get_allow_ipset():
    ddbr = boto3.resource('dynamodb', region_name='ap-northeast-2')
    tab = ddbr.Table('np-com-ddb-cvpn-allow-ipset')
    return tab.scan()['Items']
    
def lambda_handler(event, context):
    public_ip = event['public-ip']
    allow = False
    error_msg = "Your IP is not allowed to establish a connection. Please contact your administrator."
    if is_public_ip_allowed(public_ip):
        allow = True
    return {
        "allow": allow,
        "error-msg-on-failed-posture-compliance": error_msg,
        "posture-compliance-statuses": [],
        "schema-version": "v1"
    }

 

4. 파라미터 설정

  • 분할 터널 활성화 : 처음에 설명드린 고급 기능중 하나, Split Tunnel을 활성화 시키는 옵션이다.
  • CVPN을 생성하기 전 먼저 SG를 생성 후에 적용시키는 것을 권장드렸습니다.
  • VPN 포트는 기본적으로 443입니다. (1194번도 사용 가능합니다)
    • https (443) : TCP 기반 + 연결 안정성 높음 + 기업 네트웍에서 443은 웬만해서 허용
    • OpenVPN default port (1194) : UDP 기반 + 낮은 지연, 빠른 속도 + 일부 방화벽 차단 가능성.
  • 보안을 위해서 세션 제한 시간을 설정하고, 제한 시간을 넘을 시에 연결 해제를 활성화를 권장합니다.

03. VPN 내부로 접근해볼까?

1. Client VPN Endpoint → Client Downloads

  • 다운로드를 하면 'AWS Client VPN' 이라는 프로그램이 다운로드가 됩니다.

 

 

2. Client VPN Endpoint → 클라이언트 구성 다운로드

  • .ovpn 구성 파일이 다운로드 되며, 이 구성파일을 통하여 VPN 내부로 접근이 가능합니다.

 

3. 프로그램 실행 후 Profile 등록

  • AWS VPN Client File → Manage Profile 실행
  • Manage Profile에서 'Add Profile' → 구성 파일 선택 후 추가.

 

4. 구성 된 Profile로 VPN 내부 연결 시도.

 


3-1. Traffic Flow 요약

👉 Client

  • .ovpn 구성 파일을 사용하여 vpn 연결 시도
  • .ovpn 구성 파일을 담고 있는 CA (cert, root ca)인증서, Key 정보를 이용하여 상호 인증

👉 AWS Client VPN Endpoint

  • Lambda 함수를 호출하여 Client의 Public IP 주소가 허용된 IP 목록에 있는지 확인
  • Lambda 함수는 DynamoDB 테이블에 저장된 IP 목록을 조회하여 결정.
    • 목록에 IP가 없다면 연결 자체를 Deny.
  • 허용된 Public IP가 테이블에 있다면 Client의 연결 요청을 받아서 인증서 검증 후 터널을 생성.
  • Client에게 VPC 내부에서 사용할 Private IP를 할당해준다 (지정한 CIDR Range 내에서)