Post

AWS Client VPN으로 Private 리소스 접근을 표준화한 방법

멀티모듈 구조로 서비스를 운영하게 되면, 애플리케이션 배포 방식만 달라지는 것이 아니라 운영 접근 방식도 함께 정리해야 한다.
특히 여러 모바일 애플리케이션을 운영하면서, 서로 다른 성격의 서버와 운영 리소스를 함께 다뤄야 했다.
사용자 요청을 직접 처리하는 애플리케이션 서버도 있었고, 내부 ALB, RDS, Grafana 같은 운영용 리소스처럼 외부에 노출하지 않아야 하는 자원도 있었다.
운영 대상이 늘어날수록 접근 경로가 사람마다 달라지는 방식은 점점 부담이 되었고, 결국 접근 방식 자체를 표준화할 필요가 생겼다.

기존에는 내부 리소스 접근 방식이 환경과 사람에 따라 조금씩 달랐다.
이 상태에서는 온보딩과 오프보딩이 번거롭고, 보안 정책을 일관되게 적용하기도 어렵다.
장애 대응이 필요한 순간에도 “누가, 어떤 경로로, 어디까지 접근할 수 있는가”가 명확하지 않으면 운영 피로도가 빠르게 커진다.

이번 글에서는 AWS Client VPN을 도입해 Private 리소스 접근을 표준화한 경험을 정리해보려고 한다.
핵심은 단순히 VPN을 연결했다는 사실보다, 운영 접근을 반복 가능하고 통제 가능한 구조로 만든 것에 있다.

왜 Private 리소스 접근 방식을 표준화해야 했을까

모바일 애플리케이션이 여러 개로 늘어나고, 운영 환경 역시 점점 분리되기 시작하면서 내부 리소스에 접근해야 할 순간도 함께 늘어났다.
문제는 그 접근 방식이 제각각이었다는 점이다.

이 상태에서 생기는 문제는 대체로 비슷하다.

  • 내부 리소스 접근 경로가 사람마다 다르다
  • 접근 권한을 회수하거나 관리하기 어렵다
  • 보안 규칙이 문서화되지 않고 암묵지로 남는다
  • 장애 대응 시 누가 어디로 어떻게 들어가야 하는지 명확하지 않다

결국 필요한 것은 단순한 원격 접속 수단이 아니라,
내부망 접근 자체를 표준화하는 운영 방식이었다.

왜 AWS Client VPN을 선택했나

Private 리소스 접근을 위한 방법은 여러 가지가 있다.
이번에는 Bastion Host, AWS Systems Manager Session Manager, OpenVPN이나 WireGuard를 직접 운영하는 방식, 그리고 AWS Client VPN 같은 관리형 VPN 서비스를 함께 검토했다.

그 중 AWS Client VPN이 가장 적절하다고 판단했다.

첫째, 관리형 서비스라 운영 부담이 비교적 낮다.
직접 VPN 서버를 운영하면 인증서, 라우팅, 보안 업데이트, 가용성까지 신경 써야 하는 범위가 넓어진다.
반면 AWS Client VPN은 이 부담을 줄이면서도 필요한 제어 지점을 충분히 제공했다.

둘째, 인증서 기반 상호 인증(Mutual TLS)을 적용하기 좋았다.
사용자별 인증서 발급과 회수 절차를 분명하게 가져갈 수 있었고, 운영 접근 통제도 상대적으로 단순하게 설계할 수 있었다.

셋째, Terraform으로 관리하기 좋았다.
접근 인프라가 콘솔 수작업 위주로 남아 있으면 시간이 지날수록 운영 문맥이 흐려진다.
반대로 코드로 관리하면 변경 이력과 의도를 함께 남길 수 있다.

넷째, Split Tunnel 구성이 가능했다.
일반 인터넷 트래픽은 로컬 경로를 유지하고, 내부 리소스 접근에 필요한 경로만 VPN을 통해 전달하는 구조를 만들 수 있다는 점도 장점이었다.

우리가 구성한 구조

구성은 대략 아래와 같았다.

1
2
3
4
5
6
7
사용자 PC
 └─ AWS VPN Client (.ovpn + 클라이언트 인증서)
 └─ Client VPN Endpoint (split tunnel, UDP 443)
 └─ 운영용 VPC
    ├─ 피어링된 서비스 VPC
    ├─ 개발 환경 VPC
    └─ 내부 리소스(ALB, RDS, Grafana 등)

핵심은 운영 접근의 중심이 되는 VPC를 하나 두고, 사용자는 Client VPN Endpoint에 접속한 뒤 그 네트워크를 통해 필요한 내부 리소스에 접근하도록 만든 것이다.

여기서 중요한 점은 VPN을 단순 접속 수단으로만 보지 않고, 운영 접근의 진입점을 하나로 모으는 구조로 사용했다는 점이다.
이렇게 하면 접근 경로를 문서화하기 쉬워지고, 보안 정책도 한 방향으로 정리할 수 있다.

추가로 내부 리소스 접근을 위해 VPC 내부 DNS를 사용하도록 구성했다.
이 설정 덕분에 내부 ALB나 내부 도메인도 VPN 연결 이후 정상적으로 해석할 수 있었다.

인증 방식과 연결 정책

인증은 Mutual TLS 기반으로 구성했다.

구조는 단순하다.

1
2
3
CA
 ├─ Server Certificate → ACM 등록
 └─ Client Certificate → 사용자별 .ovpn에 포함

사용자는 개인별 .ovpn 파일을 사용해 연결한다.
이 파일 안에는 인증 정보가 포함되어 있으므로, 사실상 개인 자격 증명처럼 다뤄야 한다.

연결 정책은 다음과 같다.

  • UDP 443 사용
  • Split Tunnel 활성화
  • 내부 리소스에 필요한 대역만 라우팅
  • 일반 인터넷 트래픽은 로컬 경로 유지

이 방식의 장점은 분명했다.
VPN을 연결해도 일상적인 인터넷 사용이 크게 영향을 받지 않고, 운영 접근에 필요한 트래픽만 내부망으로 보내는 구조를 만들 수 있었다.

Terraform으로 운영 기반을 관리한 이유

이런 종류의 인프라는 처음엔 콘솔에서 빠르게 만들고 싶어진다.
하지만 사용자 추가, 네트워크 변경, 접근 대상 리소스 추가가 반복되기 시작하면 수동 작업은 빠르게 운영 부채가 된다.

그래서 Client VPN 관련 인프라는 Terraform으로 관리했다.

이 방식의 장점은 명확하다.

  • 어떤 의도로 이 구성이 만들어졌는지 남는다
  • 새로운 네트워크나 리소스 추가 시 변경 범위를 예측하기 쉽다
  • 운영자 교체 시 문맥이 이어지기 쉽다
  • 장애나 설정 차이 발생 시 비교 기준이 생긴다

특히 접근 인프라는 “한 번 만들어두고 끝”이 아니라
사람, 네트워크, 서비스 변화에 따라 계속 손이 가는 영역이라
코드로 남겨두는 편이 훨씬 안전했다.

사용자 온보딩은 어떻게 설계했나

접근 인프라는 결국 사람이 쓰는 것이기 때문에, 사용자 온보딩 절차가 중요하다.

내가 정리한 흐름은 비교적 단순했다.

  1. 사용자별 인증서 발급
  2. .ovpn 생성
  3. 사용자가 AWS VPN Client 혹은 Tunnelblick/OpenVPN GUI에 등록
  4. 내부 IP와 DNS 해석으로 연결 확인

관리자 입장에서는 사용자별 .ovpn 파일을 발급하고, 이를 안전하게 전달한 뒤 클라이언트 등록 절차를 안내하는 식으로 운영했다.

실제로 느낀 점은, VPN 인프라 그 자체보다
사용자 가이드 문서화가 운영 비용을 꽤 많이 줄여준다는 점이었다.
문서가 없으면 같은 질문이 반복되고, 연결 이슈도 매번 처음부터 설명해야 한다.

오프보딩과 권한 회수는 어떻게 했나

온보딩보다 더 중요한 것은 오프보딩이다.
접근 권한은 부여보다 회수가 더 중요하고, 이 절차가 불명확하면 보안은 쉽게 흐트러진다.

이번 구성에서는 인증서 폐기와 CRL(Certificate Revocation List) 업로드 방식으로 권한 회수 절차를 만들었다.

대략적인 흐름은 다음과 같다.

  1. 특정 사용자 인증서 폐기
  2. 새로운 CRL 생성
  3. AWS Client VPN Endpoint에 CRL 업로드

이 방식의 장점은 명확했다.

  • 사용자 단위 권한 회수 가능
  • 계정 공유 없이 인증서 단위로 관리 가능
  • 운영 정책을 문서화하기 좋음

다만 주의할 점도 있다.
CRL은 누적 관리가 중요하다.
새로운 폐기 건을 반영할 때 마지막 사용자만 추가하는 것이 아니라,
기존 폐기 이력을 포함한 목록 전체를 다시 생성해 업로드해야 한다.
이 부분은 실수하기 쉬운 운영 포인트였다.

실제로 자주 부딪힌 문제들

인프라 작업에서 진짜 중요한 건 “구성했다”보다 “어디서 자주 막히는가”라고 생각한다.
이번에도 몇 가지 반복적으로 확인하게 되는 포인트가 있었다.

1. VPN은 연결되는데 내부 서비스 접근이 안 되는 경우

가장 흔한 원인은 Security Group이었다.

VPN 연결이 성공했다고 해서 내부 리소스 접근이 자동으로 되는 것은 아니다.
대상 리소스의 Security Group에서 VPN 측 CIDR 대역을 허용해야 한다.

즉, 연결은 되는데 내부 ALB나 RDS, Grafana가 열리지 않는다면,
라우팅보다 먼저 보안 그룹 허용 범위를 확인하는 편이 빠르다.

2. 내부 도메인 해석이 안 되는 경우

연결은 되지만 내부 도메인이 풀리지 않으면 실제 체감상 VPN이 안 되는 것처럼 느껴진다.
이 경우 확인 포인트는 비교적 명확하다.

  • VPN 연결 후 DNS 서버가 예상대로 잡혔는가
  • VPC DNS를 사용하도록 구성되었는가
  • nslookup 결과가 내부 DNS를 바라보는가

실제로 이런 문제는 네트워크 연결 자체보다
연결 이후의 이름 해석 문제에서 많이 발생했다.

3. TLS handshake failed

사용자 입장에서는 꽤 막막한 에러다.
하지만 운영 입장에서는 주로 아래를 먼저 확인하면 된다.

  • .ovpn 파일이 최신인지
  • 인증서가 만료되지는 않았는지
  • 사용자가 오래된 프로파일을 들고 있지는 않은지
  • 네트워크에서 443/UDP 아웃바운드가 막혀 있지는 않은지

즉 이 에러는 대개 클라이언트 설정 또는 인증 정보 쪽에서 먼저 의심하는 것이 맞았다.

도입 이후 달라진 점

도입 이후 가장 크게 좋아진 것은 접근 방식의 표준화였다.

예전에는 내부 리소스 접근이 사람과 상황에 따라 조금씩 달랐다면,
이제는 적어도 운영 기준 경로를 하나의 구조로 정리할 수 있게 되었다.

그 결과 다음과 같은 변화가 있었다.

  • Private 리소스를 퍼블릭으로 노출하지 않고도 운영 가능
  • 온보딩 절차 단순화
  • 오프보딩 시 권한 회수 절차 명확화
  • 운영 접근 문서화 가능
  • 분리된 서비스 환경을 더 안전하게 관리 가능

특히 이런 작업은 겉으로 드러나는 기능 추가는 아니지만,
시간이 갈수록 운영 비용을 줄여주는 종류의 일이라는 점이 인상적이었다.

아쉬운 점과 다음 개선 포인트

현재 구조는 충분히 실용적이지만, 완성형이라고 보기는 어렵다.

다만 지금 단계에서 특정한 다음 구조를 미리 정해두기보다는, 실제 운영을 이어가면서 어떤 지점이 반복적으로 불편한지 확인하고 그에 맞춰 개선 포인트를 잡는 편이 더 현실적이라고 생각했다.

예를 들어 앞으로 운영하면서 이런 질문들이 자연스럽게 생길 수 있다.

  • 접근 권한을 더 세분화할 필요가 있는가
  • 인증서 라이프사이클을 더 자동화할 필요가 있는가
  • 연결 로그나 감사 로그 체계를 더 강화해야 하는가
  • 네트워크 규모가 커질 때 지금 구조가 계속 적절한가

즉, 지금 단계에서 중요한 것은 완벽한 미래 구조를 미리 정하는 것보다,
운영을 지속하면서 개선이 필요한 지점을 정확히 발견하는 일에 더 가깝다.

마무리

AWS Client VPN을 도입하면서 얻은 가장 큰 가치는
“VPN 하나 붙였다”가 아니라, Private 리소스 운영 접근을 표준화했다는 점이었다.

운영 인프라는 눈에 잘 띄지 않지만,
접근 방식이 정리되어 있지 않으면 보안과 생산성은 함께 흔들리기 쉽다.
반대로 접근 경로, 인증 방식, 사용자 가이드, 권한 회수 절차까지 하나의 운영 체계로 묶어두면
장애 대응도, 온보딩도, 보안 통제도 훨씬 덜 흔들린다.

비슷한 상황에 있다면 AWS Client VPN은 단순한 원격 접속 도구라기보다,
운영 접근을 구조화하는 수단으로 한 번쯤 검토해볼 만한 선택지라고 생각한다.

This post is licensed under CC BY 4.0 by the author.