AWS를 사용하여 infrastructure를 구성할때 널리 사용되는 보안 패턴중 하나가 중요 서버들을 private VPC에 구성하여 외부에서는 접속이 불가능 하도록 설정한후 bastion host를 통해서만 접속할수 있도록 하는것이다. Bastion host에 대해 간단히 설명하자면 내부 네트워크와 외부 네트워크 사이에 위치한 접속용 서버라고 생각하면 쉽다 (이보다 훨씬 복잡한 구조로 될 수도 있지만 아마 많은 스타트업 과 중견기업은 이정도 개념으로 사용하는 곳이 많을 것이다). 내부 서버들은 외부 접속은 모두 막고 bastion host를 통해서만 접속 가능하게 설정한후 bastion host는 접속이 허용된 유저들만 접속할수 있도록 설정함으로서 내부 서버가 직접적으로 외부에 노출되는 것을 막아준다.
AWS에서 bation host는 일반적인 EC2 인스탄스를 사용해서 ssh port forwarding 등을 설정하여 사용할수도 있지만 그보다는 VPN 서버를 사용하는게 더 효율적이고 편리하다. Open VPN은 무료이고 추가적인 하드웨어 가 필요없는 VPN 이여서 널리 쓰이는데, 단점은 설정하기가 어렵다는 거였다 (무료이다 보니 설정을 유저가 다 매뉴얼로 해줘야 한다). AWS에 Open VPN AS(Access Server) AMI가 있긴하다. 하지만 그 AMI를 사용하여 설치하면 쉽게 설치가 가능하기는 하지만 한번에 2명의 유저만 연결할수 있다. 2명 이상이 동시접속을 할려면 라이센스 비용을 지불해야 한다.
하지만 감사하게도 Kyle Manna 라는 개발자가 만든 Open VPN docker 이미지를 사용하면 5분안에 Open VPN을 설치하여 사용할수 있다!
Steps
1 - 먼저 EC2 인스탄스를 생성한다. t2.micro
인스턴스이면 충분하다.
2 - Docker를 인스톨 한다. Docker 인스톨 방법은 이곳을 참고한다.
3 - Open VPN 설정 파일들을 저장할 data directory를 OVPN_DATA
라는 environment variable에 지정해준다.
OVPN_DATA="/home/ubuntu/openvpn/"
4 - 위에 설정한 data directory를 아래 커맨드를 사용하여 openvpn docker 이미지를 실행시켜 생성하고 초기화 한다.
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://ovpn-host
- 위의 커맨드에서
ovpn-host
는 실제 도메인으로 지정하준다(예를 들어 vpn.example.com). - 커맨드를 실행하면 지정해준 data directory에 몇가지 설정 파일들이 생성이 되어 있을것이다.
5 - 아래 커맨드를 사용하여 openvpn CA certificate과 server key를 생성하도록 한다.
sudo docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki
- 커맨드를 실행후 passphrase를 입력하라고 나온다. 원하는 passpharase를 입력하면 된다.
- 그 후 comman name을 입력하라고 나오는데 그냥 엔터를 쳐서 default 값을 입력하면 된다.
pki
디렉토리가 생성이 되고 그 안에 openvpn CA certifcate과 server key가 생성이 된다.
6 - Open VPN 서버를 실행시킨다.
docker run -v $OVPN_DATA:/etc/openvpn -d -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn
-p
옵션을 사용하여 UDP 포트 mapping을 정확히 지정해주어야 한다. 위의 커맨드 경우 host의 1194 port를 docker 컨테이너의 1194 UDP 포트로 mapping 하였다.NET_ADMIN
설정을 해주어야만 docker container가 가상tun0
네트워크 인터페이스를 설정할수 있다.docker update --restart=always <docker container id>
커맨드를 실행시켜서 혹시나 docker 컨테이너가 실행이 중단되는 경우에도 곧바로 다시 restart가 되도록 설정해놓으면 편하다.
7 - 이제 클라이언트 설정을 생성할 차례다. 아래 커맨드를 실행시켜 클라이언트 설정을 생선한다.
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full vpn nopass
- 위의 커맨드에서는 클라이언트 이름을 vpn이라고 지정했지만 원하는데로 변경해도 된다.
8 - 클라이언트 설정 파일을 docker container에서 host 로컬 디렉토리 로 가져온다.
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient vpn > vpn.ovpn
9 - 마지막으로 클라이언트 설정 파일을 VPN으로 접속할 컴퓨터 (예를 들어 관리자나 개발자의 laptop)으로 가져오면 된다. 이제 Open VPN도 실행이 되고 있고 클라이언트도 다 설정이 됬으므로 접속하기만 하면 된다. 접속은 linux의 경우 openvpn
클라이언트 로 접속하면 되고 (openvpn --config vpn.ovpn
) mac의 경우 tunnelblick 을 사용해서 접속하면 된다. 어떠한 tool을 사용해서 접속하든 클라이언트 설정 파일이 필요하니 잘 보관하도록 하자.
Pro Tips
-
AWS에서 Open VPN 서버의 security group 설정을 신경써서 해주여야 한다 (Security group 설정이 잘못되어서 VPN에 접속이 안되는 경우, security group의 이슈인지 몰르고 open vpn 이슈라고 착각 하게 되는 경우 불필요한 시간을 허비할수도 있다). 아래의 프로토콜과 포트가 열려있는지 확인하도록 하자.
- Inboud 트래픽은 UDP / 1194 가 꼭 열려있어야 한다. 이때 트래픽 source를 anywhere로 하지말고 custom ip로 하도록 하자 (예를 들어 사무실 ip 주소에서만 접속 가능하도록 설정).
- 만일 VPN을 통해 내부 서버 접속 뿐만이 아니라 인터넷 접속도 가능하게 할려면 Outbound 트래픽도 그에 맞게 열어 주어야 한다. Outbound는 그냥 모든 TCP 포트를 열어주면 세세한 설정 할 필요 없이 VPN을 통해 인터넷 트래픽도 사용할수 있게 된다. 하지만 아무래도 보안의 취약점이 될 가능성이 있으므로 주의가 필요하다.