0. 들어가며
저는 VMware 솔루션을 다루는 엔지니어로, Tanzu라고 하는 Kubernetes 기반 솔루션을 담당하고 있습니다. 파트너사 엔지니어분들께 Tanzu에 대해 소개를 하고 교육하는 것이 저의 역할 중 하나이기에 관련 교육과정을 준비하면서 실제 솔루션을 체험해 볼 수 있는 Lab 환경을 구성하게 되었습니다.
Lab 환경은 사내에 구축되어 있고, 교육은 주로 파트너사를 방문하여 진행하기 때문에 외부에서 Lab환경에 접근할 수 있는 End-Point 진입점이 필요하게 되었습니다. 이를 오픈소스 소프트웨어인 OpenVPN을 사용하여 구현하기로 하였습니다.
해당 포스트는 제목에서 볼 수 있듯, Ubuntu 20.04에 OpenVPN을 사용하여 VPN 서비스를 구축한 경험을 정리한 것입니다. Linux 초심자이거나, 주니어 엔지니어들에게 좋은 자습서가 되기를 바랍니다.
1. VPN 서비스 Architecture
[그림 1]은 OpenVPN으로 구성한 VPN 서비스 Architecture의 모식도입니다. 항상 위와 같은 구조로 구축할 필요는 없습니다. 이는 저희 팀의 상황에 맞게 구성한 것이므로, 아래에 설명할 내용들을 참고하셔서 구축하고자 하는 환경에 맞게 재구성하실 수 있습니다.
- VPN 서버 : VPN 서비스를 구동시킬 서버입니다. 해당 포스트에서는 VMware vSphere 환경 위에 VM 형식으로 생성하였습니다. 스펙은 4 vCPU / 8GB Memory / 32GB Storage / 2 vNIC이고 OS로는 Ubuntu 20.04 Desktop을 사용하였습니다.
- CA 서버 : VPN 서버에서 사용할 인증서를 발급할 인증기관 서버입니다. 역시 VMware vSphere 환경 위에 VM 형식으로 생성하였습니다. VPN 서버와 통합하여 한대의 서버로 운영이 가능하나, 보안상 분리하는 것을 추천합니다. 스펙은 2 vCPU / 4GB Memory / 32GB Storage / 1 vNIC으로 구성하였습니다.
- 공인 IP : 외부에서 VPN 서버로 바로 접근할 수 있도록 공인 IP를 하나 사용했습니다. 원래 공인 IP를 바로 노출하는 것은 보안상 그다지 좋지는 않습니다. 다만, 이는 팀 내에서 충분히 논의 후 결정한 사항으로 해당 포스팅을 보고 구축하시는 분들은 다른 방식을 사용하셔도 좋습니다. (참고 : 이전에 근무했던 회사에서는 VPN 서버에 사설 IP를 할당하고 포트포워딩을 통해 접근하도록 구성했었습니다.)
- 인프라용 사설 IP : VPN Server와 CA Server에 각각 인프라용 사설 IP를 할당했습니다. 당연하게도, 이 IP를 통해 내부망에서 해당 서버에 SSH 등을 통해 접근하여 구축 작업을 진행하였습니다. 위 그림에 파란색 선으로 표시된 네트워크입니다. 해당 네트워크는 인터넷이 가능해야 합니다.
- 라우팅 구성 : 인프라용 사설 IP 대역(파란색 선으로 표시된 네트워크)과 VPN 서비스를 통해 접근하려고 하는 사설 IP 대역(빨간색 선으로 표시된 네트워크)이 서로 통신할 수 있도록 라우팅을 구성해 주어야 합니다. 위 그림에서는 VPN 서버에 바로 VPN 서비스를 통해 접근하려고 하는 사설 IP 대역이 붙어 있는 것으로 나오는데 이해를 돕기 위한 그림이며 실제 VPN 서버에 연결된 네트워크는 외부 공인 망(검은색 선)과 인프라용 IP 대역(파란색 선) 네트워크 밖에 없습니다. VPN 서비스를 통해 접근하려고 하는 사설 IP 대역(빨간색 선)의 경우 실제로는 내부 라우터를 통해 접근하고 있다는 것을 다시 알려드립니다.
2. VPN Service 구축하기
1) CA 서버 구성
VPN 서버를 구축하기 전에 우선 CA 서버를 구축해야 합니다. CA(Certificate Authority, 인증 기관) 서버란, 공개 키 기반 암호화 시스템에서 사용되는 인증서를 발급하고 관리하는 서버입니다. CA 서버에서 발급된 인증서는 암호화 통신에서 신뢰할 수 있는 신분 확인 수단이 됩니다. 인증서에는 공개 키와 해당 공개 키와 연결된 신원 정보가 포함되어 있습니다. 해당 포스팅에서는 사설 CA 서버를 구성하는 방법에 대해서 설명합니다.
Step 1. Easy-RSA 설치
Easy-RSA는 아래에 언급하게 될 공개 키 인프라(PKI)를 관리하는 데 사용되는 도구입니다. PKI는 공개 키 암호화 시스템을 구현하는 데 필요한 모든 요소를 포함하는 보안 프레임워크로서, 인증서와 개인 키를 생성하고 관리하는 데 사용됩니다. SSH 툴로 CA 서버에 root가 아닌 sudo 사용자로 로그인합니다.(참고 : 해당 실습에서는 Windows PC에서 MobaXterm이라는 SSH 툴을 사용하였습니다.)
sudo apt update
sudo apt install easy-rsa -y
위 두줄의 명령어를 통해 Easy-RSA 패키지를 설치를 완료했습니다. (참고 : 해당 포스팅에 사용된 Easy-RSA의 버전은 3.0.6-1입니다.)
Step 2. PKI(Public Key Infrastructure) 준비
이번 단계에서는 PKI를 생성합니다. PKI란 암호화와 디지털 인증을 통해 보안 기능을 제공하는 시스템으로 공개 키와 개인 키를 사용하여 서버와 클라이언트 간의 통신을 암호화하여 안전한 통신을 보장합니다.
# 참고 : root 사용자가 아닌 일반 사용자로 CA를 관리해야 하므로 아래의 명령어에서 sudo를 사용하지 않도록 해야 합니다.
mkdir ~/easy-rsa
#홈 디렉토리에 easy-rsa라는 새 디렉토리 생성
ln -s /usr/share/easy-rsa/* ~/easy-rsa/
#이전 단계에서 설치한 Easy-RSA 패키지 파일들을 가리키는 심볼릭 링크를 생성
#Easy-RSA 패키지의 새로운 버전이나 업데이트가 있을 때 PKI 스크립트에 자동으로
#반영 되는 편리함이 있어 심볼릭 링크를 사용
chmod 700 ~/easy-rsa
# ~/easy-rsa 디렉토리 소유자에게만 읽기, 쓰지, 실행 권한을 부여
cd ~/easy-rsa
./easyrsa init-pki
# PKI를 초기화
#아래와 같이 출력 됨을 확인
init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/sammy/easy-rsa/pki
위 작업을 완료하면 CA를 만드는데 필요한 모든 파일이 포함된 디렉터리가 생기는 것을 확인할 수 있습니다. 다음 단계에서는 CA의 개인 키와 공개 인증서를 생성합니다.
Step3. CA(Certificate Authority, 인증 기관) 생성
CA의 개인 키와 공개 인증서를 생성하기 전에 vars라는 파일을 생성하고 기본값을 채워 넣어야 합니다. 해당 실습에서는 텍스트 편집기로 vim을 사용하였습니다. 기존에 사용하던 다른 텍스트 편집기가 있다면 그것을 사용해도 무방합니다.
cd ~/easy-rsa
vim vars
# ~/easy-rsa/vars에 아래 내용을 입력
set_var EASYRSA_REQ_COUNTRY "KR"
set_var EASYRSA_REQ_PROVINCE "Seoul"
set_var EASYRSA_REQ_CITY "Seoul City"
set_var EASYRSA_REQ_ORG "My Organization"
set_var EASYRSA_REQ_EMAIL "myemail@example.com"
set_var EASYRSA_REQ_OU "MyTeam"
set_var EASYRSA_ALGO "ec"
set_var EASYRSA_DIGEST "sha512"
vars 파일에 아래 두 줄의 변수 값이 "ec"와 "sha512"를 제외한 나머지 값들은 원하는 것으로 바꾸어도 무방합니다. 내용을 모두 입력하고 저장 후 텍스트 편집기를 종료합니다.
그리고 다시 ./easy-rsa 명령어와 build-ca 옵션을 사용하여 CA의 루트 인증서와 개인 키가 생성됩니다. 여기서 루트 인증서란 CA의 최상위 인증서로, CA가 다른 인증서를 발급하고 검증하는 데 사용합니다.
./easyrsa build-ca
#아래 내용이 출력 됨
. . .
Enter New CA Key Passphrase:
Re-Enter New CA Key Passphrase:
. . .
Common Name (eg: your user, host, or server name) [Easy-RSA CA]: #enter키 입력
CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/home/"ca_server_user"/easy-rsa/pki/ca.crt
Enter New CA Key Passphrase란에 강력한 암호를 입력하고, 아래 Re-Enter New CA key Passphrase에도 같은 값을 입력합니다. 이 암호는 인증서 서명 또는 취소와 같이 CA와 상호작용해야 할 때 사용하는 것으로, 안전한 곳에 기록해 두어야 합니다. 그 아래 CN(Common Name)은 편의상 엔터를 입력하여 기본 이름이 되도록 합니다.
참고 : 만약 CA와 상호작용(인증서 서명 또는 취소) 시에 암호를 입력하지 않고 싶다면 nopass 옵션을 사용할 수 있습니다.
./easyrsa build-ca nopass
위 과정을 완료하고 나면 ~/easy-rsa/pki/ca.crt와 ~/easy-rsa/pki/private/ca.key 두 개의 파일이 생성됩니다.
- ca.crt 파일은 CA의 공개 인증서 파일입니다. 사용자, 서버 및 클라이언트는 이 인증서를 사용하여 상호 간의 신뢰 관계를 확인하고 통신 중에 데이터의 무결성과 보안을 보장합니다.
- ca.key 파일은 CA가 서버 및 클라이언트의 인증서에 서명하는 데 사용하는 개인 키입니다. 이 파일은 안전한 위치에 보관되어야 하며, 만약 이 파일을 탈취당했다면 CA 서버 자체를 파기해야 합니다.
해당 과정을 모두 완료하게 되면 CA 서버 구성이 끝납니다. 이제 VPN 서버 구성에 들어가겠습니다.
2) VPN 서버 구성
다음으로 VPN 서버를 구축하도록 하겠습니다. 해당 포스팅에서는 앞서 언급한 오픈소스 소프트웨어인 OpenVPN을 사용하여 VPN 서버를 구축하는 방법에 대해 설명하도록 하겠습니다. OepnVPN은 SSL/TLS 기술을 사용하여 VPN 서비스를 구현합니다.
CA 서버를 구축한 이유와, VPN 서버를 구축하는 과정에 수행하게 되는 여러 작업들을 이해하기 위해서는 SSL/TLS 프로토콜에 한 이해가 필요합니다. 간략하게 SSL/TLS 프로토콜이 어떻게 작동하는지 알아보고 가도록 하겠습니다.
1. 핸드셰이크(Handshake)
클라이언트가 서버로 연결을 요청하면, 서버는 클라이언트에게 인증서를 제공합니다. 이 인증서는 서버의 신원을 확인하는 데 사용됩니다. 클라이언트는 인증서를 확인한 후에 서버와 암호화 통신에 사용할 임시 세션 키를 교환합니다.
2. 데이터 암호화 및 복호화
핸드셰이크 단계에서 교환된 세션 키를 사용하여 데이터를 암호화하여 전송합니다. 서버는 수신된 데이터를 해당 세션 키를 사용하여 복호화합니다.
3. 상호 인증
SSL/TLS는 클라이언트와 서버 간의 상호 인증을 수행합니다. 클라이언트는 서버의 인증서를 검증하여 서버의 신원을 확인하고, 서버는 클라이언트의 인증서를 검증하여 클라이언트의 신원을 확인합니다.
이제 본격적으로 OpenVPN을 사용하여 VPN 서버를 구축해 보도록 하겠습니다.
Step.1 OpenVPN과 Easy-RSA 설치
우선 OpenVPN과 Easy-RSA를 설치합니다. Easy-RSA는 앞서 CA 서버를 구축하는 과정에서 한번 설치를 해 보았습니다. 다음 명령어를 통해 패키지들을 설치합니다.
sudo apt update
sudo apt install openvpn easy-rsa
다음으로 root 유저가 아닌 상태로 easy-rsa 디렉터리를 생성합니다. 아래에 나오게 될 Easy-RSA를 설정하는 작업은 앞서 수행한 CA 서버 구축 과정과 거의 흡사합니다.
ln -s /usr/share/easy-rsa/* ~/easy-rsa/
sudo chown "non-root user name" ~/easy-rsa
# 쌍따옴표 안의 non-root user name은 현재 서버에 로그인 되어 있는 사용자 이름으로 교체
# ex) sudo chown garlickim ~/easy-rsa
chmod 700 ~/easy-rsa
Step.2 OpenVPN을 위한 PKI 생성
OpenVPN 서버의 개인 키와 인증서를 생성하기 전에 서버 및 클라이언트의 인증서 요청을 관리할 PKI 디렉터리를 구축해야 합니다. 이를 위해서는 역시, 몇 가지 기본값이 저장되어 있는 vars 파일을 만들어야 합니다. ~/easy-rsa 디렉터리로 이동하여 vim 텍스트 편집기를 사용하여 vars 파일을 만듭니다.
cd ~/easy-rsa
vim vars
vars 파일에 아래 내용을 입력합니다.
set_var EASYRSA_ALGO "ec"
set_var EASYRSA_DIGEST "sha512"
OpenVPN 서버는 CA(인증기관)이 아니기 때문에 vars 파일에 위 두 줄만이 필요합니다. 다음으로 easyrsa 스크립트를 실행하여 PKI 디렉터리를 생성합니다. 역시 CA 서버 구축 시에 수행했던 절차와 비슷합니다.
./easyrsa init-pki
다만 CA를 생성할 필요는 없습니다.(./easyrsa build-ca 명령어를 실행할 필요가 없다는 뜻입니다.) 인증서 및 유효성 검사에 대해서는 CA 서버의 CA가 전적으로 책임지기 때문입니다. 다만 VPN 서버에 PKI를 생성한 이유는 이곳에 인증서 서명 요청(Certificate Signing Request, CSR) 및 공개 인증서를 저장하기 위함입니다.
잠깐! 지금까지의 과정을 돌아보면 OpenVPN 패키지 설치 후 계속 인증과 관련된 작업을 진행하고 있습니다. 다소 어렵고 지루할 수 있겠습니다. 이러한 작업을 하는 이유에 대해서 잘 모른다면 더욱 그렇게 느껴질 수 있을 것 같습니다. 다시 상기하는 차원에서 말씀드리자면, OpenVPN은 SSL/TLS 방식으로 구현되기 때문입니다. SSL/TLS 프로토콜은 인증서, 공개 키, 개인 키와 같은 요소를 필요로 하기 때문에 지금과 같은 작업을 수행하고 있는 것입니다. 그럼 다시 본론으로 들어가 보겠습니다.
Step.3 OpenVPN 서버 인증서 서명 요청(CSR) 및 개인 키 생성
이제 VPN 서버에서 개인 키와 인증서 서명 요청(CSR)을 생성하기 위한 준비가 끝났습니다. 특히, 인증서 서명 요청은 앞서 구축한 CA 서버로 전송하여 서명된 인증서(Required Certificate)를 만드는 데 사용됩니다. 이렇게 만들어진 서명된 인증서를 다시 OpenVPN 서버로 전송한 후에 사용할 수 있도록 설치하면 됩니다.
cd ~/easy-rsa
~/easy-rsa 디렉터리로 이동 후 easyrsa 스크립트를 gen-req 옵션을 사용하여 실행할 것입니다. 이를 통해 CSR이 생성되는데, 이때 CN(Common Name)을 지정해 주어야 합니다. 우선 명령어를 보고 설명을 이어 나가겠습니다.
./easyrsa gen-req server nopass
# easyrsa 스크립트를 gen-req 옵션과 함께 실행, CN으로 "server"를 사용했고 nopass 옵션을 선택
# 아래 내용이 출력 됨
Common Name (eg: your user, host, or server name) [server]: #enter키 입력
Keypair and certificate request completed. Your files are:
req: /home/"vpn_server_user"/easy-rsa/pki/reqs/server.req
key: /home/sammy/"vpn_server_user"/pki/private/server.key
# server.req라는 인증서 서명 요청 파일과 server.key라는 개인 키가 생성 됨
./easyrsa gen-req server nopass에서 우선 CN값으로 지정한 server에 대해서 살펴보겠습니다. 사실 CN값은 어떤 값으로 바꾸어도 상관은 없습니다. 다만 이 값이 어떤 인증서 서명 요청인지를 알 수 있는 단어를 선택하는 것이 좋습니다. 현재 단계에서는 VPN 서버의 CSR을 생성하는 과정에 있어 CN값으로 'server'라는 단어를 선택했습니다. VPN 서버의 이름을 'server'라고 부르기로 약속했다고 보면 됩니다. nopass 옵션을 사용한 이유는, 요청 파일 전송 시 암호로 보호되어 권한 문제가 발생하는 것을 방지하기 위함입니다.
참고 : server 이외의 다른 CN값을 사용하면 앞으로의 설치 과정 중 몇 개의 파일의 이름을 선택한 CN값으로 바꾸어 주어야 합니다. 예를 들면, 생성된 파일을 /etc/openvpn 디렉터리에 복사할 때입니다. 또한, /ect/openvpn/server.conf 파일에서 설정해 주어야 하는 crt나 key 파일의 이름 역시 올바르게 지정해야 합니다.
위 과정을 통해 CSR인 server.req와 개인 키인 server.key가 생성되었습니다. 이 중 server.key 파일을 /etc/openvpn/server 디렉터리로 복사합니다.
sudo cp ~/easy-rsa/pki/private/server.key /etc/openvpn/server/
# 생성된 개인 키 파일을 /etc/openvpn/server로 복사
Step.4 OpenVPN 서버의 CSR에 대한 서명
이번 단계에서는, 앞서 생성한 OpenVPN 서버의 CSR을 CA 서버로 전송하여 서명된 인증서(Required Certificate)를 발급합니다. VPN 연결을 요청할 클라이언트가 CA에 대한 정보를 가지고 있고 이를 신뢰한다면, CA가 인증한 OpenVPN 서버 역시 신뢰할 수 있습니다.
이러한 과정은 우리가 사용하는 웹 브라우저에서도 사용하는 방식으로 HTTPS 접속이 그렇습니다. 하나 예를 들어 보겠습니다. google.com에 접속했을 때, 이 사이트가 정말 구글의 메인 페이지인지 어떻게 신뢰할 수 있을까요?
[사진 1]에서 볼 수 있듯 주소창 왼쪽에 자물쇠가 잠긴 모양이라면 해당 페이지는 공인 CA 기관으로 부터 인증된 안심할 수 있는 페이지라는 것입니다. 웹 브라우저를 통해 사용자(클라이언트)가 특정 페이지를 요청하면 이러한 요청을 받은 서버는 인증서를 클라이언트에 전송하게 됩니다. 클라이언트의 웹 브라우저는 기본적으로 공인 CA 기관에 대한 정보를 가지고 있으며 서버로부터 전달받은 인증서를 CA 기관의 정보와 대조합니다. 대조한 결과가 올바르다면 해당 페이지를 신뢰하게 되고 올바르지 않다면 접속을 거부하거나, 신뢰할 수 없다는 경고를 띄우게 됩니다.
[사진 2]는 교육용으로 구축된 체험 센터의 실습자용 vCenter 웹 콘솔 페이지입니다. 로컬 환경에 구축되었기 때문에 공인 이 된 CA로부터 발급받지 않은 인증서를 전달하였기 때문에 크롬에서 위험한 페이지라고 알려주는 것을 볼 수 있습니다.
OpenVPN 서버에서 생성된 CSR을 SCP를 통해 CA 서버에 전송하도록 하겠습니다. 아래의 명령어로 전송해도 좋고, 만약 SSH 툴로 MobaXterm을 사용하고 계신다면 화면 왼쪽의 내비게이션 바의 네 번째 메뉴인 SSH Browser(SFTP)를 사용하여 드래그 앤 드롭으로 전송할 수 도 있습니다. (저는 MobaXterm을 사용하기 때문에 드래그 앤 드롭을 사용하였습니다.)
scp ~/easy-rsa/pki/reqs/server.req ca_server_user@your_ca_server_ip:/tmp
#ca_server_user를 CA 서버에 접속할 사용자 이름으로 교체
#your_ca_server_ip를 CA 서버의 IP나 FQDN으로 교체
주의 : 이후 과정은 CA 서버에서 진행하는 과정입니다. SSH 툴을 사용하여 CA 서버에 접속한 후 작업을 수행합니다.
cd ~/easy-rsa
./easyrsa import-req /tmp/server.req server
# 맨 뒤의 server는 server라는 이름으로 요청을 import 하겠다는 뜻
#아래 내용이 출력 됨
. . .
The request has been successfully imported with a short name of: server
You may now use this name to perform signing operations on this request.
해당 요청이 server라는 이름으로 import 되었다는 메시지와 해당 이름으로 서명을 진행할 수 있다고 알려줍니다. 이제 서명 작업을 진행하기 위해 easyrsa 스크립트를 sign-req 옵션과 함께 실행합니다.
./easyrsa sign-req server server
./easyrsa sign-req server server에 대해서 잠시 살펴보겠습니다. server라는 단어가 두 번 나와서 다소 헷갈릴 수 있는데 첫 번째 sever는 해당 서명 요청에 대한 type을 선언해 주는 것으로 server와 client 두 가지가 있습니다. 현재는 서버용 서명 요청이므로 server라 선언해 준 것입니다. 두 번째 server는 서명 요청을 import 하는데 정한 이름의 값을 의미합니다.
# 아래와 같이 출력 됨
You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.
Request subject, to be signed as a server certificate for 3650 days:
subject=
commonName = server
Type the word 'yes' to continue, or any other input to abort.
Confirm request details: yes
. . .
Certificate created at: /home/"ca_server_user"/easy-rsa/pki/issued/server.crt
중간에 무언가를 입력할 수 있도록 프롬프트가 뜨게 되는데 이때 yes를 입력합니다. 그러면 ~/easy-rsa/pki/issued 디렉터리에 server.crt라는 인증서가 생성됩니다. 이 인증서에는 VPN 서버의 공개 키와 CA 서버의 서명이 포함되어 있습니다. 이를 통해 해당 CA 서버를 신뢰하는 클라이언트는 해당 CA 서버의 서명을 포함하고 있는 인증서를 통해 VPN 서버도 역시 신뢰하게 됩니다.
이제 발급된 인증서인 server.crt와 CA 서버의 인증서인 ca.crt를 VPN 서버로 전송하면 됩니다.
scp pki/issued/server.crt vpn_server_user@your_vpn_server_ip:/tmp
scp pki/ca.crt vpn_server_user@your_vpn_server_ip:/tmp
#이번엔 VPN 서버로 해당 파일들을 전송하므로 vpn_server_user에 VPN 서버의 사용자 이름을 입력
주의 : 다시 VPN 서버로 돌아와 작업을 진행합니다.
sudo cp /tmp/{server.crt,ca.crt} /etc/openvpn/server
Step.5 OpenVPN의 Cryptographic material 구성
추가로 사전 공유 비밀 키(tls-crypt)를 생성합니다. 이 사전 공유 비밀 키는 VPN 서버와 Client가 최초에 연결될 때 TLS 인증서를 낙독화 하여 보안 수준을 향상하는 데 사용됩니다. 또한 VPN 서버로 전송되는 패킷의 빠른 처리에도 도움을 줍니다. VPN 서버로 전송된 패킷이 사전 공유 비밀 키를 사용하여 서명된 경우에만 VPN 서버가 패킷을 처리하도록 하고, 그렇지 않은 경우에는 패킷을 드롭하는 방식으로 작동하기 때문입니다.
이를 통해, 포트 스캔이나 DoS 공격에도 대처할 수 있도록 도움을 주며 외부에서 VPN 네트워크의 트래픽을 확인하는 것을 더욱 어렵게 합니다.
cd ~/easy-rsa
openvpn --genkey --secret ta.key
#openvpn 명령어를 통해 사전 공유키인 ta.key 생성
sudo cp ta.key /etc/openvpn/server
Step.6 클라이언트용 인증서와 키 쌍 생성
원래는 클라이언트 시스템에서 CSR과 개인키를 생성하고 서명을 위해 CA 서버로 보내는 것이 더 올바르겠지만, 체험 센터의 운영 방식을 고려했을 때에는 VPN 서버에서 인증서 요청을 생성하고 배포하는 것이 더 유리하다는 판단을 하였습니다. 따라서 해당 포스팅에서는 VPN 서버에서 클라이언트용 CSR을 생성하고 서명받는 절차에 대해 설명합니다. 앞서 VPN 서버에서 작업했던 내용과 거의 흡사한 방식으로 진행합니다.
클라이언트 인증서 및 키 파일을 저장하기 위한 디렉터리를 생성하고, 해당 디렉터리 사용 권한을 제한합니다.
mkdir -p ~/client-configs/keys
chmod -R 700 ~/client-configs
그리고 ~/easy-rsa 디렉터리로 이동하여 easyrsa 스크립트를 gen-req, nopass 옵션을 사용하여 실행합니다. CN(Common Name)은 client1로 입력합니다. 이때 CN은 고유한 값으로 설정되어야 합니다.
cd ~/easy-rsa
./easyrsa gen-req client1 nopass
# 아래 내용이 출력 됨
Common Name (eg: your user, host, or server name) [client1]: #enter키 입력
Keypair and certificate request completed. Your files are:
req: /home/"vpn_server_user"/easy-rsa/pki/reqs/client1.req
key: /home/"vpn_server_user"/easy-rsa/pki/private/client1.key
# client1.req라는 인증서 서명 요청 파일과 client1.key라는 개인 키가 생성 됨
cp pki/private/client1.key ~/client-configs/keys/
클라이언트의 개인키인 client1.key를 ~/client-configs/keys 디렉터리로 복사 후 클라이언트의 CSR을 CA 서버로 전송합니다. 역시 아래 명령어를 사용해도 좋고, MobaXterm의 GUI 기능을 활용해도 됩니다.
scp pki/reqs/client1.req ca_server_user@your_ca_server_ip:/tmp
주의 : 아래 작업은 CA 서버에서 진행됩니다.
cd ~/easy-rsa
./easyrsa import-req /tmp/client1.req client1
#client1.req를 서명하기 위해 import
./easyrsa sign-req client client1
#client type으로 서명 진행, CN은 client1
#아래 내용이 출력 됨
Type the word 'yes' to continue, or any other input to abort.
Confirm request details: yes #yes 입력
CA 서버에 접속하여 전송된 client1.req 파일을 import 하고 서명 요청 type을 client로 지정하고 서명을 진행합니다. 앞서 설명했었지만 다시 설명하면 ./easyrsa sign-req client client1에서 client는 CSR에 대한 서명 요청 type이 clinet 임을 의미합니다.
이렇게 생성된 client1.cert 파일을 다시 VPN 서버로 전송합니다.
scp pki/issued/client1.crt vpn_server_user@your_server_ip:/tmp
주의 : 다시 VPN 서버로 돌아와 진행합니다.
cp /tmp/client1.crt ~/client-configs/keys/
cp ~/easy-rsa/ta.key ~/client-configs/keys/
sudo cp /etc/openvpn/server/ca.crt ~/client-configs/keys/
sudo chown "vpn_server_user"."vpn_server_user" ~/client-configs/keys/*
#예) sudo chown garlickim.garlickim ~/client-configs/keys/*
전송된 인증서와 ta.key를 ~/client-configs/key 디렉터리로 복사한 후 디렉터리와 그 내부 파일에 대한 사용 권한을 지정합니다. 이제 인증서와 관련된 부분은 대부분 마무리되었습니다.
Step - 7 server.conf 파일 생성 및 편집을 통한 OpenVPN 설정
OpenVPN은 server.conf 파일의 여러 값들을 변경하여 운영 환경에 맞게 설정을 진행할 수 있습니다. 이 부분은 사실 오픈소스 소프트웨어의 장점이기도 하고 단점이기도 한 부분입니다. 이번 단계에서는 제가 설정한 것들을 기준으로 설명드리도록 하겠습니다.
우선, 샘플 server.conf 파일을 복사하는 것에서 시작합니다.
sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/server/
sudo gunzip /etc/openvpn/server/server.conf.gz
#server.conf.gz 파일을 /etc/openvpn/server/ 디렉터리로 복사 후 압축을 해제
압축이 해제된 server.conf 파일을 vim 텍스트 편집기를 사용하여 편집하도록 하겠습니다.
sudo vim /etc/openvpn/server/server.conf
파일을 열어서 살펴보면, 아주 많은 내용이 이미 입력되어 있는 것을 볼 수 있습니다. 하지만 걱정하실 필요는 없습니다. 대부분 주석처리가 된 설명이고 또 그 설명을 잘 읽어보면 어떤 설정을 할 수 있는지 알 수 있습니다.
첫 번 째로, HMAC 섹션을 찾습니다. 아마 파일의 좀 아래쪽에서 찾을 수 있을 겁니다. tls-auth 필드가 기본적으로 활성화되어 있을 텐데 줄의 맨 앞에 ;(세미콜론)을 입력하여 비활성화시킵니다. 그리고 그 아래에 새로 tls-crypt ta.key를 입력합니다. 이는 앞서 생성했던 사전 공유 비밀키인 ta.key를 사용하게 하는 옵션입니다.
# For extra security beyond that provided
# by SSL/TLS, create an "HMAC firewall"
# to help block DoS attacks and UDP port flooding.
#
# Generate with:
# openvpn --genkey --secret ta.key
#
# The server and each client must have
# a copy of this key.
# The second parameter should be '0'
# on the server and '1' on the clients.
;tls-auth ta.key 0 # This file is secret #';'를 입력하여 옵션 비활성화
tls-crypt ta.key #새로 입력
다음으로 cipher 필드를 찾습니다. 아마 HMAC 섹션 아래에 위치하고 있을 것입니다. 기존에 활성화되어 있던 cipher AES-256-CBC를 주석처리 하고 그 아랫줄에 cipher AES-256-GCM과 auth SHA256을 입력합니다.
# Select a cryptographic cipher.
# This config item must be copied to
# the client config file as well.
# Note that v2.4 client/server will automatically
# negotiate AES-256-GCM in TLS mode.
# See also the ncp-cipher option in the manpage
;cipher AES-256-CBC
cipher AES-256-GCM
auth SHA256
auth SHA256은 HMAC(Hash-based Message Authentication Code)에서 해시 함수로 사용되는 알고리즘 중 하나이며, 앞서 설정한 ta.key와 결합하여 사용되며 메시지 및 데이터의 무결성을 검증합니다.
다음 과정은 DH(Deffie-Hellman) 매개변수를 지정하는 과정으로 Step.2 OpenVPN을 위한 PKI 생성 단계에서 var파일에 입력한 set_var EASYRSA_ALGO "ec"과 연관이 있습니다. 사실 이 값은 Elliptic Curve Cryptography(ECC, 타원 곡선 암호화)를 사용하도록 모든 인증서를 구성하게 하는 것으로 Diffie-Hellman의 시드 파일은 필요가 없습니다. 따라서 dh2048.pem 파일이나 dh.pem 같은 파일은 필요가 없으므로 dh dh2048.pem 필드를 주석처리하여 비활성화하고 그 아래에 dh none을 입력합니다.
# Diffie hellman parameters.
# Generate your own with:
# openssl dhparam -out dh2048.pem 2048
;dh dh2048.pem
dh none
다음으로, OepnVPN 실행 권한에 관한 설정입니다. 이를 성정하는 이유는 보안상의 이유로 OepnVPN 프로세스가 시스템의 최소한의 리소스에 최소한의 권한만 가지고 접근하도록 하기 위함입니다.
# It's a good idea to reduce the OpenVPN
# daemon's privileges after initialization.
#
# You can uncomment this out on
# non-Windows systems.
user nobody
group nogroup
설명에서도 나오지만, OpenVPN 데몬의 초기화가 끝난 후 그 권한을 최소화하는 것이 보안상의 위협을 줄이는데 도움이 됩니다. 이렇게 하면 기본적은 설정은 모두 마무리가 되었습니다. 저는 여기서 몇 가지를 추가로 더 설정했는데 이는 필요에 따라 선택적으로 적용하면 됩니다.
우선 DNS에 대한 설정으로 DNS 섹션을 찾아 아래와 같이 입력합니다. 이렇게 하면 VPN 클라이언트가 VPN 서버로 부터 부여받은 IP주소 정보에 DNS 서버 정보를 추가할 수 있습니다.
# Certain Windows-specific network settings
# can be pushed to clients, such as DNS
# or WINS server addresses. CAVEAT:
# http://openvpn.net/faq.html#dhcpcaveats
# The addresses below refer to the public
# DNS servers provided by opendns.com.
push "dhcp-option DNS Your_DNS_Server's_IP_Address"
#Your_DNS_Server's_IP_Address에 DNS 서버의 IP 주소 입력
#예) push "dhcp-option DNS 192.168.0.2"
이러한 설정을 적용한 이유는 체험 센터 내부에 위치한 DNS 서버를 사용하기 위해서입니다. OpenVPN의 기본 설정으로는, VPN 클라이언트에게 사설 IP는 할당해 주지만 DNS 서버에 대한 정보는 전달하지 않기 때문에 내부의 DNS를 참조하지 못하는 문제가 발생합니다. 이를 위와 같은 설정을 통해 해결할 수 있습니다. 만약 구축하고자 하는 환경에 내부 DNS 서버를 참조해야 한다면 위와 같이 설정하시면 됩니다.
다음으로는 접근하고자 하는 체험 센터의 네트워크에 대한 라우팅에 대한 허용입니다. 이를 설정해주지 않으면 내부 네트워크에 접근할 수 없기 때문입니다. 아래와 같은 내용의 섹션을 찾습니다.
# Push routes to the client to allow it
# to reach other private subnets behind
# the server. Remember that these
# private subnets will also need
# to know to route the OpenVPN client
# address pool (10.8.0.0/255.255.255.0)
# back to the OpenVPN server.
push "route IP_Subnet NetMask"
#예) push "route 192.168.0.0 255.255.255.0"
만약 VPN을 통해 접근하고자 하는 네트워크 subnet이 192.168.0.0/24라면 push "route 192.168.0.0 255.255.255.0"을 입력하면 됩니다. 추가로 더 접근을 허용해주고 싶은 네트워크가 있다면 아래줄에 같은 형식으로 추가하면 됩니다.
이제 마지막입니다. 이 설정은 그다지 권장하지는 않지만, 제가 구축한 체험 센터 환경에서는 크게 상관이 없어 사용하는 설정으로 클라이언트들이 동일한 CN이나 인증서, 키를 사용하고 있더라도 VPN 서버에 대한 접속을 허용하는 설정입니다.
아래 필드를 찾아가 duplicate-cn의 주석을 제거하여 중복 옵션을 활성화합니다.
참고 : 실제 운영에는 권고하지 않는 설정입니다.
# Uncomment this directive if multiple clients
# might connect with the same certificate/key
# files or common names. This is recommended
# only for testing purposes. For production use,
# each client should have its own certificate/key
# pair.
#
# IF YOU HAVE NOT GENERATED INDIVIDUAL
# CERTIFICATE/KEY PAIRS FOR EACH CLIENT,
# EACH HAVING ITS OWN UNIQUE "COMMON NAME",
# UNCOMMENT THIS LINE OUT.
duplicate-cn
# 주석을 제거하여 옵션을 활성화
제가 구축한 체험 센터 환경은 사내의 중요한 네트워크와 완전히 격리된 상태인 데다 중요한 애플리케이션이나 워크로드가 구동되지 않고 있어서 어떤 문제가 발생하더라도 그 피해 범위가 제한적이라 위와 같은 옵션을 적용하였습니다. 실제 운영환경에서는 추천드리지 않는 옵션입니다.
이 외에도 여러 옵션들을 변경할 있습니다. VPN 서버의 접속 프로토콜을 UDP에서 TCP로 바꾼다거나 포트 번호를 1194에서 443으로 바꾸는 등의 옵션을 줄 수 있습니다. 각 섹션의 설명을 읽어보고 필요한 부분을 적용하여 사용할 수 있을 것으로 보입니다.
Step.8 OpenVPN 서버의 네트워킹 구성 조정
기본적으로 Ubuntu는 어떤 트래픽을 자신을 통해 다른 곳으로 전달하지 않습니다. Router가 아니기 때문이죠. 하지만 VPN 서버의 역할을 하기 위해선 클라이언트들의 요청을 다른 곳으로 전달하는 것을 허용해 주어야 합니다. vim 편집기를 통해 etc/sysctl.conf 파일을 편집합니다.
sudo vim /etc/sysctl.conf
#파일이 열리면 맨 아래에 다음을 입력하고 저장
net.ipv4.ip_forward = 1
#해당 설정값은 ipv4에 대한 트래픽 전달을 활성화 한다는 의미
변경 사항을 저장 후 파일에서 빠져나온 후 변경 된 값을 시스템이 읽을 수 있도록 명령을 합니다.
sudo sysctl -p
#아래와 같이 출력 됨
net.ipv4.ip_forward = 1
다음으로는 Routing 경로 설정과 라우팅 경로에 대한 메트릭 값에 대한 조정입니다. 먼저 라우팅 경로를 설정하도록 하겠습니다. VPN 클라이언트가 접근하고자 하는 네트워크 subnet에 대하여 라우팅 경로를 수동으로 지정해 주었습니다.
sudo ip route add "Destination_Subnet/prefix via Gateway_IP_Addres"
#에) sudo ip route add 192.168.0.0/24 via 192.168.0.1
#예) sudo ip route add 172.16.0.0/16 via 192.168.0.1
#위와 같은 형식으로 VPN 클라이언트가 접근하고자 하는 네트워크 subnet에 대해 Routing 경로 설정
여기서 중요한 것은 Gateway IP 주소입니다. 해당 포스팅에서 VPN 서버의 역할을 하는 VM은 두 개의 네트워크 어뎁터를 가지고 있습니다. 하나는 공인 IP를 부여받아 외부에서 클라이언트들이 접속할 수 있는 진입점이 되고, 나머지 하나는 사설 IP를 부여받아 내부를 바라보고 있습니다. 체험 센터의 네트워크 subnet들은 라우터를 통해 라우팅 되고 있기 때문에 VPN 서버가 바라보고 있는 게이트웨이를 통해서 접근할 수 있습니다.
예를 들어 VPN 서버가 위치한 사설 네트워크, 즉 사설 IP 주소의 subnet이 192.168.0.0/24이고 게이트웨이가 192.168.0.1이라고 합시다. VPN 클라이언트는 이 네트워크를 지나 172.16.0.0/16 네트워크 subnet으로 접근하려고 해도 우선은 거쳐야 하는 게이트웨이가 바로 VPN 서버의 사설 네트워크 subnet의 게이트웨이가 됩니다. 그래서 위 예제에 같은 게이트웨이 IP 주소를 사용하고 있는 것입니다. 더욱이, 다음 단계에서 설정할 예정이지만 VPN 클라이언트들은 NAT를 통해 VPN 서버의 사설 IP 주소를 사용하여 통신을 할 것이기 때문에 위와 같이 게이트웨이 IP 주소를 설정하게 되는 것입니다. 간단히 생각하면, 어쨌든 VPN 서버가 다른 네트워크 subnet에 접근하기 위해서 거쳐야 하는 게이트웨이 IP 주소를 설정해 준다고 보면 됩니다.
두 번째로 생각해야 할 부분은 바로 라우팅 경로에 대한 메트릭 값입니다. 메트릭값은 낮을수록 우선순위를 가지는데 이것이 잘못 설정되면 트래픽이 가야 할 방향을 찾지 못하고 엉뚱한 곳으로 전송되어 VPN 서비스가 제대로 이루어지지 않게 됩니다. 단 해당 포스팅에서는 수동으로 라우팅 경로를 설정했고, 이때의 메트릭 값은 0이므로 최고의 우선순위를 가지게 됩니다. 따라서 트래픽이 엉뚱하게 전송되는 현상은 일어나지 않습니다.
IP 주소나 네트워크 subnet의 노출을 막기 위해 구체적인 주소는 가렸습니다. 여기서 보실 것은 우선 오른쪽에 보라색 네모에 들어가 있는 내용입니다. Iface 열에 ens192 외 ens160이 보일 것입니다. ens192는 공인 IP 주소가 입력되어 있는 네트워크 인터페이스이고, ens160은 사설 IP 주소가 입력되어 있는 네트워크 인터페이스입니다. 해당 설정은 모두 수동으로 라우팅 경로를 설정한 것으로 메트릭 값이 0으로 네트워크 트래픽이 가장 우선적으로 처리됨을 알 수 있습니다.
또한 VPN 클라이언트가 접근하려고 하는 사설 IP 주소의 Subnet들은 모두 내부 네트워크를 바라보고 있는 ens160으로 라우팅 되고 있고, 공인 IP 대역으로의 라우팅은 ens192를 바라보고 있는 것을 볼 수 있습니다. 이를 통해 VPN 서버와 클라이언트가 사용하게 되는 네트워크에 대한 라우팅 경로와 메트릭 값의 설정은 완료되었습니다.
사실 이 부분은 저도 고생을 좀 한 부분입니다. 구축하고자 하는 환경의 네트워크 상태에 따라 적합설 라우팅 경로와 메트릭값 설정이 필요한 부분입니다.
Step.9 방화벽 설정
우선 방화벽을 통해 NAT 설정을 활성화합니다. 해당 포스팅에서는 네트워크 인터페이스 ens160이 내부 네트워크를 바라보고 있고 이를 통해 VPN 클라이언트가 내부 네트워크에 접근합니다. 따라서 해당 인터페이스에 NAT 설정을 활성화하도록 하겠습니다. vim 편집기를 통해 /etc/ufw/before.rules 파일 엽니다.
#
# rules.before
#
# Rules that should be run before the ufw command line added rules. Custom
# rules should be added to one of these chains:
# ufw-before-input
# ufw-before-output
# ufw-before-forward
#
#------------사이의 내용을 입력------------
# START OPENVPN RULES
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
# Allow traffic from OpenVPN client to eth0 (change to the interface you discovered!)
-A POSTROUTING -s 10.8.0.0/8 -o "Your_dev_Name" -j MASQUERADE
COMMIT
# END OPENVPN RULES
#------------사이의 내용을 입력------------
# Don't delete these required lines, otherwise there will be errors
*filter
. . .
# START OPENVPN RULES
# NAT table rules *nat :POSTROUTING ACCEPT [0:0]
# Allow traffic from OpenVPN client to eth0 (change to the interface you discovered!)
-A POSTROUTING -s 10.8.0.0/8 -o "Your_dev_Name" -j MASQUERADE
#예) -A POSTROUTING -s 10.8.0.0/8 -o ens160 -j MASQUERADE
COMMIT
# END OPENVPN RULES
위 내용을 복사해서 붙여 넣습니다. 단 "Your_dev_Name" 부분에는 NAT를 수행할 네트워크 인터페이스의 이름을 넣습니다. 해당 포스팅의 경우에는 ens160이 될 것입니다. 파일을 저장하고 닫습니다.
다음은 /etc/default/ufw 파일을 편집해 줍니다. 방화벽에서도 패킷의 전달을 허용해 주어야 합니다.
sudo nano /etc/default/ufw
#/etc/default/ufw 파일 내에서 아래 내용과 같이 편집
DEFAULT_FORWARD_POLICY="ACCEPT"
#DROP에서 ACCEPT로 변경
또한, 방화벽에서 1194 포트의 udp 프로토콜에 대한 트래픽을 허용해 줍니다. 앞서 server.conf 설정에서 OpenVPN이 사용하게 될 포트와 프로토콜을 바꾸었다면 이 값 역시 바뀌어야 합니다.
sudo ufw allow 1194/udp
마지막으로 앞서 설정한 룰이 적용되도록 방화벽을 재시작해 줍니다.
sudo ufw disable
sudo ufw enable
Step.10 OpenVPN 서비스 시작
OpenVPN은 systemd 서비스로 실행되며 systemctl 명령어를 통해 관리할 수 있습니다. 첫 번째로는 할 설정은 VPN 서버가 재시작되더라도 OpenVPN 서비스가 자동으로 실행될 수 있도록 하는 것입니다. 그리고 OpenVPN 서비스를 시작해 보겠습니다.
sudo systemctl -f enable openvpn-server@server.service
#VPN 서버가 재부팅 되어도 OpenVPN 서비스가 자동으로 실행 되도록 설정
sudo systemctl start openvpn-server@server.service
#OpenVPN 서비스 실행
OpenVPN 서비스가 잘 작동하고 있는지 확인해 보겠습니다.
sudo systemctl status openvpn-server@server.service
#아래와 같은 내용이 출력 됨
● openvpn-server@server.service - OpenVPN service for server
Loaded: loaded (/lib/systemd/system/openvpn-server@.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2023-06-29 07:34:01 KST; 4 weeks 0 days ago
Docs: man:openvpn(8)
https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
https://community.openvpn.net/openvpn/wiki/HOWTO
Main PID: 881 (openvpn)
Status: "Initialization Sequence Completed"
Tasks: 1 (limit: 9435)
Memory: 4.2M
CGroup: /system.slice/system-openvpn\x2dserver.slice/openvpn-server@server.service
└─881 /usr/sbin/openvpn --status /run/openvpn-server/status-server.log --status-version 2 --suppress-timesta>
Step.11 클라이언트용 OVPN 파일 생성을 위한 인프라 구성
이번에는 다소 복잡한 과정을 수행합니다. 한 클라이언트만 사용할 단일 파일을 작성하는 것이 아니라 필요에 따라서 고유한 클라이언트 구성 파일, 인증서 및 키를 생성할 수 있는 클라이언트 구성 인프라를 구축하는 프로세스이기 때문입니다. 이러한 설정을 통해 필요한 클라이언트 설정파일을 쉽게 만들고 관리할 수 있습니다. 마지막으로, 이를 통해 최정적으로 클라이언트가 VPN 접속에 사용할 설정을 담은 .ovpn 파일을 생성할 것입니다.
먼저, 이전에 생성한 client-configs 디렉터리 내에 클라이언트 구성 파일을 저장할 새로운 디렉터리를 생성하도록 하겠습니다.
mkdir -p ~/client-configs/files
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf
#client.conf 샘플 파일을 ~/client-configs 디렉터리에 base.conf 파일로 복사
복사한 base.conf 파일을 vim 텍스트 편집기로 열어서 몇 가지를 내용을 설정해 줍니다.
vim ~/client-configs/base.conf
#~/client-configs/base.conf 파일의 여러 값들을 설정
. . .
# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote "your_server_ip" 1194
. . .
#"your_server_ip"에 클라이언트가 접근할 수 있는 OpenVPN 서버의 IP 주소를 입력
#해당 포스팅에서는 공인 IP 주소를 사용
----------------------------------------------------------------------------------
proto udp
#server.conf에서 설정한 값과 같은 프로토콜을 선택
----------------------------------------------------------------------------------
# Downgrade privileges after initialization (non-Windows only)
user nobody
group nogroup
#주석 제거를 통해 옵션을 활성화
----------------------------------------------------------------------------------
# SSL/TLS parms.
# See the server config file for more
# description. It's best to use
# a separate .crt/.key file pair
# for each client. A single ca
# file can be used for all clients.
;ca ca.crt
;cert client.crt
;key client.key
#설정 파일 자체에 해당 파일을 추가할 것이므로 주석 처리하여 비활성화
----------------------------------------------------------------------------------
# If a tls-auth key is used on the server
# then every client must also have the key.
;tls-auth ta.key 1
#ta.key 파일 역시 클라이언트 설정 파일에 추가할 것이므로 주석 처리
----------------------------------------------------------------------------------
cipher AES-256-GCM
auth SHA256
#ciper와 auth에 대한 세팅이 server.conf 파일과 같도록 추가
----------------------------------------------------------------------------------
key-direction 1
#키 방향 지시값을 1로 설정
----------------------------------------------------------------------------------
; script-security 2
; up /etc/openvpn/update-resolv-conf
; down /etc/openvpn/update-resolv-conf
; script-security 2
; up /etc/openvpn/update-systemd-resolved
; down /etc/openvpn/update-systemd-resolved
; down-pre
; dhcp-option DOMAIN-ROUTE .
#위 내용을 base.conf 파일 맨 아래에 추가
#해당 내용은 Linux 기반의 VPN 클라이언트가 DNS해석을 처리하는 방법에 대한 설정으로 주석 처리된 상태로 입력
위 내용과 대조하여 base.conf 파일을 수정하여 설정을 완료하고 저장하고 빠져나옵니다. 마지막 주석처리 된 부분은 Linux 기반의 VPN 클라이언트를 위한 내용으로 만약 윈도우용 VPN 클라이언트만을 사용할 경우에는 따로 입력하지 않아도 됩니다. Linux의 경우에는 주석 처리된 부분을 수정하여 사용하게 됩니다.
이제 클라이언트용 .ovpn 파일 생성을 위한 스크립트를 작성합니다.
vim ~/client-configs/make_config.sh
#vim 편집기를 사용하여 make_config.sh라는 스크립트 파일을 생성
#파일 내부에 아래 내용을 복사하여 붙여 넣기
#!/bin/bash
# First argument: Client identifier
KEY_DIR=~/client-configs/keys
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf
cat ${BASE_CONFIG} \
<(echo -e '<ca>') \
${KEY_DIR}/ca.crt \
<(echo -e '</ca>\n<cert>') \
${KEY_DIR}/${1}.crt \
<(echo -e '</cert>\n<key>') \
${KEY_DIR}/${1}.key \
<(echo -e '</key>\n<tls-crypt>') \
${KEY_DIR}/ta.key \
<(echo -e '</tls-crypt>') \
> ${OUTPUT_DIR}/${1}.ovpn
이때, make_config.sh 파일 최 상단에 #!/bin/bash는 bash 쉘에서 스크립트를 실행함을 의미하는 행입니다. 파일을 저장하고 빠져나온 후 실행 파일로 변환시킵니다.
chmod 700 ~/client-configs/make_config.sh
이 스크립트 파일의 작동에 대해서 조금 설명을 드려야 할 것 같습니다. 스크립트 파일을 실행하면 먼저 base.conf 파일의 사본을 만듭니다. 그리고 앞서 클라이언트에 대해 생성한 모든 인증서와 키 파일을 수집하여 그 내용을 추출한 다음에 base.conf의 사본 파일에 해당 내용을 추가합니다. 그리고 마지막으로 해당 내용을 새로운 클라이언트 구성 파일인 .ovpn으로 내보냅니다. 이렇게 하여 새로운 클라이언트를 추가할 때마다 빠르게 클라이언트용 구성 파일을 생성하는 인프라를 구성했습니다.
단, 새로운 클라이언트를 추가할 때마다 새로운 키와 인증서를 생성한 후 해당 스크립트를 실행해야 합니다. 그리고 새로운 키와 인증서를 생성할 때마다 CN 역시 일치하도록 하여야 합니다. 해당 포스팅에서 클라이언트용 CN으로는 client1을 사용하고 있습니다.
Step.12 클라이언트 구성 파일(.opvn) 생성
드디어 VPN 접속을 위한 클라이언트용 구성 파일을 생성할 차례입니다. 명령어 두 줄이면 생성할 수 있습니다.
cd ~/client-configs
./make_config.sh client1
#이때 client1은 지금까지 사용한 CN
#이 CN을 다르게 하여 CSR과 crt, key 파일을 생성하고 스크립트를 실행하면 새로운 클라이언트 구성 파일을 생성할 수 있음
스크립트가 실행되고 나면 .opvn 파일이 생성됩니다.
ls ~/client-configs/files
#아래와 같이 출력 됨
client1.ovpn
이제 이 client1.ovpn 파일을 SCP나 MobaXterm 등을 사용하여 VPN 클라이언트로 전송해 주면 됩니다.
Step.13 Windows 클라이언트에서 OpenVPN에 접속해 보기
여기를 클릭하면 OpenVPN 클라이언트용 소프트웨어를 다운로드할 수 있습니다.
Community Downloads - Open Source VPN | OpenVPN
The OpenVPN community shares the open source OpenVPN. Download the latest version of the open source VPN release OpenVPN 2.6.3 for a secure network.
openvpn.net
일반적으로 Intel의 CPU를 사용하는 Windows 단말이라면 대부분 맨 위의 WIndows 64-bit MSI installer를 다운로드하여 설치하면 됩니다. 설치는 매우 간단합니다. 다운로드된 파일을 실행하고 Next만 눌러주면 됩니다. 설치가 완료되면 바탕화면에 OpenVPN GUI라는 이름의 아이콘이 생성됩니다. 그리고 앞서 전송받은 client1.ovpn 파일을 더블 클릭하면 구성 파일이 OpenVPN 클라이언트 소프트웨어 자동으로 import 됩니다. 그리고 바탕화면에 생성된 OpenVPN GUI를 실행하면 시작 표시줄에 컴퓨터 모니터와 같은 아이콘이 하나 생성됩니다.
빨간 네모를 친 아이콘을 우클릭 후 import 했던 client1을 사용해 접속을 시도하면 다음과 같은 창이 잠시 나왔다가 사라지는데, 자세히 살펴보면 앞서 설정했던 내용들을 확인할 수 있습니다. 접속이 성공하면 작업 표시줄의 OpenVPN 클라이언트 아이콘이 녹색으로 바뀝니다.
이상으로 OpenVPN 서버 설정과 클라이언트에서 접속하는 과정까지 VPN 서버 구축을 완료해 보았습니다. 내용이 길고 어려운 부분도 많았을 것으로 생각합니다. 또한, 구축하고자 하는 환경과 해당 포스팅에서 설명하는 환경이 서로 다른 경우가 더 많을 것입니다. 저도 처음 VPN을 구축할 때 여러 자료를 찾아보고 또 많은 시행착오도 겪었습니다. 어렵다 포기하지 마시고 천천히 읽어보고 그 내용을 이해한다면 구축이 그렇게 어렵지만은 않을 것 같습니다. 아무쪼록 해당 포스팅이 OpenVPN을 사용하고자 하는 엔지니어 분들께 도움이 되길 바랍니다.
이만 포스팅을 마치도록 하겠습니다. 감사합니다.
참고 페이지
1) VPN Server - How To Set Up and Configure an OpenVPN Server on Ubuntu 20.04
How To Set Up and Configure an OpenVPN Server on Ubuntu 20.04 | DigitalOcean
www.digitalocean.com
2) CA Server - How To Set Up and Configure a Certificate Authority (CA) On Ubuntu 20.04
How To Set Up and Configure a Certificate Authority (CA) On Ubuntu 20.04 | DigitalOcean
www.digitalocean.com
'System > System & Service' 카테고리의 다른 글
OPNsense로 방화벽 구축하기 [3편] (0) | 2025.03.08 |
---|---|
OPNsense로 방화벽 구축하기 [2편] (0) | 2025.02.25 |
OPNsense로 방화벽 구축하기 [1편] (0) | 2025.02.15 |
[Ubuntu 20.04] Tomcat 서버 구축 - 2편 (0) | 2023.08.12 |
[Ubuntu 20.04] Tomcat 서버 구축 - 1편 (0) | 2023.08.10 |