Profile picture

[Linux] VPN 오픈소스 소프트웨어 OpenVPN을 사용하여 VPN 서버 구축하기

JaehyoJJAng2024년 12월 01일

개요

24시간 돌아가는 Proxmox 운영 서버에 eve-ng 네트워크 랩 서버가 동작하고 있다.

이전까지는 네트워크 관련 실습을 하고 싶을 때마다 집에서 데스크탑 또는 노트북으로 lab 서버에 접근을 해서 사용 중이었는데

이번에 장기간 숙소(?) 비슷한 곳에서 생활을 하게 되어, 외부에서 eve-ng lab 환경에 접근할 수 있는 end-point 진입점이 필요하게 되었다.

이를 오픈소스 소프트웨어인 OpenVPN을 사용하여 외부에서 집의 lab 서버로 접근하는 방법을 기록해보려고 한다.


VPN 서비스 아키텍쳐

image

위 그림은 OpenVPN으로 구성한 VPN 서비스 구성도이다.

단순히 나의 상황에 맞게 구축한 것이기에, 꼭 위와 같은 구조로 VPN 서버가 구축될 필요는 없다.

아래에 내용들을 참고해서 구축하고자 하는 환경에 맞게 재구성하는걸 권장한다.



VPN 서버

  • VPN 서비스를 구동시킬 서버이다.

CA(Certificate Authority) 서버

  • VPN 서버에서 사용할 인증서를 발급할 인증기관 서버이다.
  • VPN 서버와 통합하여 운영하여도 상관 없으나, 보안상 분리하는 것을 권장하고 있다.

포트포워딩

  • 공유기 랜포트 하단에 VPN 서버와 CA 서버가 동시에 존재한다.
  • 외부에서 공유기 포트포워딩을 통해 VPN 서버로 접근할 수 있다.

인프라용 사설 IP

  • 이 IP를 통해 내부망에서 해당 서버에 SSH 등을 통해 접근하여 서버 구축 작업을 진행하였다.
  • 파란색 선으로 표시된 네트워크이다. (해당 네트워크는 인터넷이 가능해야함.)

라우팅 구성

  • 인프라용 사설 IP 대역과 VPN 서비스를 통해 접근하려고 하는 사설 IP 대역(빨간색 네트워크)이 서로 통신할 수 있도록 라우팅이 구성되어 있어야 한다.

VPN 서비스 구축하기

1. CA 서버 구성

1-1. Easy-RSA 설치


Easy-RSA는 아래에 언급하게 될 공개 키 인프라(PKI) 를 관리하는 데 사용되는 도구이다.

PKI는 공개 키 암호화 시스템을 구현하는 데 필요한 모든 요소를 포함하는 보안 프레임워크로서, 인증서와 개인 키를 생성하고 관리하는 데 사용된다.


SSH로 CA 서버에 접근하여 root 유저가 아닌 일반 유저로 로그인한 후, Easy-RSA를 설치하자.

wget -O easy-rsa.tgz https://github.com/OpenVPN/easy-rsa/releases/download/v3.2.1/EasyRSA-3.2.1.tgz

여기서 설치된 easy-rsa 패키지의 버전은 3.2.1이다.


1-2. PKI(Public Key Infrastructure) 준비

이번 단계에서는 PKI를 생성한다.

PKI란 암호화와 디지털 인증을 통해 보안 기능을 제공하는 시스템으로 공개 키와 개인 키를 사용하여

서버와 클라이언트 간의 통신을 암호화하여 안전한 통신을 보장한다.


root 사용자가 아닌 일반 사용자로 CA를 관리해야 하므로 아래의 명령어에서 sudo를 사용하지 않도록 주의하자.


# 홈 디렉토리에 easy-rsa 디렉토리 생성
mkdir ~/easy-rsa


# 이전 단계에서 설치한 Easy-RSA 패키지 파일들을 가리키는 심볼릭 링크 생성
# Easy-RSA 패키지의 새로운 버전이나 업데이트가 있을 때 PKI 스크립트에 자동으로 반영 되는 편리함이 있어 심볼릭 링크를 사용하였음
ln -s /usr/share/easy-rsa/* ~/easy-rsa/

# 권한 수정
chmod 777 ~/easy-rsa

# PKI 초기화
cd easy-rsa
./easyrsa init-pki

아래와 같이 출력되면 성공이다.
image
위 작업을 완료하면 CA를 만드는데 필요한 모든 파일이 포함된 디렉토리가 생기는 것을 확인할 수 있다.

다음 단계에서는 CA의 개인 키와 공개 인증서를 생성한다.


1-3. CA(Certificate Authority, 인증 기관) 생성

CA의 개인 키와 공개 인증서를 생성하기 전에 vars라는 파일을 ~/easy-rsa 경로에 생성하고 기본 값을 채워넣어야 한다.

cd ~/easy-rsa
vim 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      "example@example.com"
set_var EASYRSA_REQ_OU         "MyTeam"
set_var EASYRSA_ALGO           "ec"
set_var EASYRSA_DIGEST         "sha512"

vars 파일에 아래 두 줄의 변수 값이 ec, sha512를 제외한 나머지 값들은 사용자가 원하는 값으로 변경하면 된다.


그리고 다시 ./easy-rsabuild-ca 옵션을 사용하여 CA의 루트 인증서와 개인 키를 생성해주자.

여기서 루트 인증서란 CA의 최상위 인증서로, CA가 다른 인증서를 발급하고 검증하는 데 사용된다.

./easyrsa build-ca nopass
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. Your new CA certificate is at:
* /home/proxyuser/easy-rsa/pki/ca.crt

CN(Common Name)은 편의상 엔터를 입력하여 기본 이름이 되도록 한다.


참고: 만약 CA와 상호작용(인증서 서명 또는 취소) 시에 암호를 입력하지 않고 싶다면 `nopass` 옵션을 사용하면 된다.

./easyrsa build-ca nopass

위 과정을 완료하고 나면 ~/easy-rsa/pki/ca.crt~/easy-rsa/pki/private/ca.key 두 개의 파일이 생성된다.


ca.crt

  • ca.crt 파일은 CA의 공개 인증서 파일이다.
  • 사용자, 서버 및 클라이언트는 이 인증서를 사용하여 상호 간의 신뢰 관계를 확인하고 통신 중에 데이터 무결성과 보안을 보장한다.

ca.key

  • ca.key 파일은 CA가 서버 및 클라이언트의 인증서에 서명하는 데 사용하는 개인 키이다.
  • 이 파일은 안전한 위치에 보관되어야 하고, 만약 이 파일이 탈취당했다면 CA 서버를 빠르게 파기해야 한다.

위 과정을 모두 완료했다면 CA 서버 구성이 끝이 난거다.

이제 VPN 서버 구성에 들어가보자.



2. VPN 서버 구성

다음으로 VPN 서버를 구축해보자.

OpenVPN은 SSL/TLS 기술을 사용하여 VPN 서비스를 구현한다.

CA 서버를 구축한 이유와 VPN 서버를 구축하는 과정에서 수행하게 되는 여러 작업들을 이해하기 위해서는 SSL/TLS 프로토콜에 대한 이해가 필요하다.

간략하게 SSL/TLS 프로토콜이 어떻게 동작하는지 알아보고 가자.


1. 핸드셰이크

  • 클라이언트가 서버로 연결을 요청하면, 서버는 클라이언트에게 인증서를 제공한다. 이 인증서는 신원을 확인하는데 사용된다.
  • 클라이언트는 인증서를 확인한 후에 서버와 암호화 통신에 사용할 임시 세션 키를 교환한다.

2. 데이터 암호화 및 복호화

  • 핸드셰이크 단계에서 교환된 세션 키를 사용하여 데이터를 암호화하여 전송한다.
  • 서버는 수신된 데이터를 해당 세션 키를 사용하여 복호화한다.

3. 상호 인증

  • SSL/TLS는 클라이언트와 서버 간의 상호 인증을 수행한다


2-1. OpenVPN과 Easy-RSA 설치

sudo apt update
sudo apt install openvpn

easy-rsa는 Easy-RSA 설치를 참고하여 설치하도록 하자.



다음으로 root 유저가 아닌 상태로 easy-rsa 디렉토리를 생성한다.

아래에 나오는 내용은 앞서 수행한 CA 서버 구축 과정과 흡사하다.

ln -s /usr/share/easy-rsa/* ~/easy-rsa/
chmod 777 ~/easy-rsa

2-2. OpenVPN을 위한 PKI 생성

OpenVPN 서버의 개인 키와 인증서를 생성하기 전에 서버 및 클라이언트의 인증서 요청을 관리할 PKI 디렉토리를 생성해야 한다.

이를 위해서는 역시, 몇 가지 기본 값이 저장되어 있는 vars 파일을 생성해줘야 한다.


~/easy-rsa 디렉토리로 이동하여 아래의 내용이 담긴 vars 파일을 만들자.

cd ~/easy-rsa
vim vars

set_var EASYRSA_ALGO "ec"
set_var EASYRSA_DIGEST "sha512"

OpenVPN 서버는 CA(인증기관)이 아니기 때문에 vars 파일에 단 두줄만 있으면 된다.


다음으로는 easyrsa 스크립트를 실행하여 PKI 디렉토리를 생성한다.

./easyrsa init-pki

인증서 및 유효성 검사에 대해서는 CA 서버의 CA가 전적으로 책임지고 있으니, 여기서는 CA를 생성할 필요가 없다(=./easyrsa build-ca nopass)


다만, VPN 서버에 PKI를 생성한 이유는 이곳에 인증서 서명 요청(Certificate Signing Request, CSR) 및 공개 인증서를 저장하기 위함이다.



2-3. OpenVPN 서버 인증서 서명 요청(CSR) 및 개인 키 생성

이제 VPN 서버에서 개인 키와 인증서 서명 요청(CSR)을 생성하기 위한 준비가 끝났다.

특히, 인증서 서명 요청은 앞서 구축한 CA 서버로 전송하여 서명된 인증서(Required Certificate)를 만드는데 사용된다.

이렇게 만들어진 서명된 인증서를 다시 OpenVPN 서버로 전송한 후에 사용할 수 있도록 설치하면 된다.


먼저 ~/easy-rsa 디렉토리로 이동 후 easyrsa 스크립트를 gen-req 옵션을 사용하여 실행할 것이다.

이를 통해 CSR이 생성되는데, 이떄 CN(Common Name)을 지정해 주어야 한다.

우선 명령어를 보고 설명을 이어나가겠다.

# easyrsa 스크립트를 gen-req 옵션과 함께 실행, CN으로 "server"를 사용했고 nopass 옵션을 선택
./easyrsa gen-req 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 디렉토리에 복사할 때이다.

또한, /etc/openvpn/server.con 파일에서 설정해 주어야 하는 crtkey 파일의 이름 역시 변경된 이름으로 지정해야 한다.



위 과정을 통해 CSR인 server.req와 개인 키인 server.key가 생성되었다.

이 중 server.key 파일을 /etc/openvpn/server 디렉토리로 복사한다.

sudo cp -R ~/easy-rsa/pki/private/server.key /etc/openvpn/server/

2-4. OpenVPN 서버의 CSR에 대한 서명

이번 단계에서는, 앞서 생성한 OpenVPN 서버의 CSR을 CA 서버로 전송하여 서명된 인증서(Required Certificate)를 발급한다.

VPN 연결을 요청할 클라이언트가 CA에 대한 정보를 가지고 있고 이를 신뢰한다면, CA가 인증한 OpenVPN 서버 역시 신뢰할 수 있게된다.



OpenVPN 서버에서 생성된 CSR을 SCP 명령을 통해 CA 서버에 전송하도록 하자.

scp ~/easy-rsa/pki/reqs/server.req ca_server_usr@ca_server_ip:/tmp



주의: 이후 과정은 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가 두 번 나와서 헷갈릴 수도 있는데

첫번째 server는 해당 서명 요청에 대한 type을 선언해 주는 것으로 serverclient 두 가지 타입이 존재한다.

현재는 서버 요청용이므로 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/proxyuser/easy-rsa/pki/issued/server.crt

Confirm request details 에는 yes를 입력한다.

그러면 ~/easy-rsa/pki/issued 디렉토리에 server.crt 라는 인증서가 생성된다.

이 인증서에는 공개 키와 CA 서버의 서명이 포함되어 있다.

이를 통해 해당 CA 서버를 신뢰하는 클라이언트는 해당 CA 서버의 서명을 포함하고 있는 인증서를 통해 VPN 서버 역시 신뢰하게 된다.


이제 발급된 인증서인 server.crt와 CA 서버의 인증서인 ca.crt를 VPN 서버로 전송하면 된다.

# 이번에는 VPN 서버로 해당 파일들을 전송하므로 VPN 사용자 이름 및 서버 IP를 기입
scp ~/easy-rsa/pki/issued/server.crt vpn_server_user@vpn_server_ip:/tmp
scp ~/easy-rsa/pki/ca.crt vpn_server_user@vpn_server_ip:/tmp


주의: 다시 VPN 서버로 돌아와 아래 작업을 진행한다.

sudo cp /tmp/{server.crt,ca.crt} /etc/openvpn/server/

2-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

2-6. 클라이언트용 인증서와 키 쌍 생성

원래는 클라이언트 시스템에서 CSR과 개인 키를 생성하고 서명을 위해 CA 서버로 보내는 것이 더 올바른 방법이다.

하지만 현재 내 상황을 고려했을 때에는 VPN 서버에서 인증서 요청을 생성하고 배포하는 것이 더 적합하다는 판단이 들었다.

따라서 VPN 서버에서 클라이언트용 CSR을 생성하고 서명받는 절차에 대해서 설명할거다.


이 내용은 앞서 작업했던 내용과 거의 비슷한 방식으로 진행된다.


클라이언트 인증서 및 키 파일을 저장하기 위한 디렉토리를 생성하고, 해당 디렉토리 사용 권한을 제한한다.

mkdir -p ~/client-configs/keys
chmod 700 -R ~/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/vpnserver/easy-rsa/pki/reqs/client1.req
key: /home/vpnserver/easy-rsa/pki/private/client1.key
# client1.req라는 인증서 서명 요청 파일과 client1.key라는 개인 키가 생성 됨

클라이언트의 개인 키인 client1.key~/client-configs/keys 디렉토리로 복사 후 클라이언트의 CSR을 CA 서버로 전송한다.

cp pki/private/client1.key ~/client-configs/keys/
scp pki/reqs/client1.req ca_server_user@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 디렉토리로 복사한 후 디렉토리와 그 내부 파일에 대한 사용 권한을 지정한다.

이제 인증서와 관련된 부분은 대부분 마무리 되었다.


2-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 파일을 vim 텍스트 편집기를 사용하여 편집하자.

sudo vim /etc/openvpn/server/server.conf

첫번쨰로, HMAC 섹션을 찾자.

여기에 tls-auth 필드가 기본적으로 활성화되어 있는데 줄의 맨 앞에 ;을 입력하여 비활성화 시켜주자.

그리고 아래에 새로 tls-crypt ta.key를 입력한다.

이는 앞서 생성했던 사전 공유 비밀 키인 ta.key를 사용하게 하는 옵션이다.

;tls-auth ta.key 0 #';'를 입력하여 옵션 비활성화
tls-crypt ta.key   # 새로 입력된 부분

image


다음으로 cipher 필드를 찾자. HMAC 섹션 근처 아래에 위치하고 있다.

기존에 활성화되어 있던 cipher AES-256-CBC를 주석처리 하고 그 아랫줄에 아래 내용을 입력하자.

;cipher AES-256-CBC
cipher AES-256-GCM
auth SHA256

image
auth SHA256은 HMAC(Hash-based Message Authentication Code)에서 해시 함수로 사용되는 알고리즘 중 하나이며, 앞서 설정한 ta.key와 결합하여 사용되며 메시지 및 데이터의 무결성을 검증한다.


다음으로는 DH(Deffie-Hellman) 매개변수를 지정하는 과정으로 2-2. OpenVPN을 위한 PKI 생성 단계에서 vars 파일에 입력한 set_var EASYRSA_ALGO "ec"과 연관이 있다.


사실 이 값은 Elliptic Curve Cryptography(ECC, 타원 곡선 암호화)를 사용하도록 모든 인증서를 구성하게 하는 것으로,

Diffie-Hellman의 시드 파일은 필요가 없다.

따라서 dh2048.pem 파일이나 dh.pem 같은 파일은 필요가 없게 되므로 dh dh2048.pem 필드를 주석처리하여 비활성화하고

그 아래에 dh none을 입력한다.

;dh dh2048.pem
dh none

image


다은은 OpenVPN 실행 권한에 관련된 설정이다.

이를 설정하는 이유는 보안상의 이유로 OpenVPN 프로세스가 시스템에서 최소한의 권한만 가지고 접근하도록 하기 위함이다.

user nobody
group nogroup

image
여기까지하면 기본적인 설정은 모두 마무리가 되었다.

필자는 여기서 몇 가지를 추가로 더 설정할 예정이다. 이는 필요에 따라 선택적으로 적용하면 된다.



우선 DNS에 대한 설정으로 DNS 섹션을 찾아 아래와 같이 입력한다.

이렇게 하면 VPN 클라이언트가 VPN 서버로부터 부여받은 IP 주소 정보에 DNS 서버 정보를 추가할 수 있게된다.

push "dhcp-option DNS Your_DNS_Server's_IP_Address"
#Your_DNS_Server's_IP_Address에 DNS 서버의 IP 주소 입력
#예) push "dhcp-option DNS 172.16.0.1"

image

이러한 설정을 하는 이유는 내부망에 위치한 DNS 서버를 이용하기 위함이다.

OpenVPN의 기본 설정으로는 VPN 클라이언트에게 사설 IP는 할당해주지만,

DNS 서버에 대한 정보는 전달하지 않기 때문에 내부 DNS를 참조하지 못하는 문제가 발생한다.

이를 위 설정으로 해결이 가능하다.



다음으로는 접근하고자 하는 네트워크에 대한 라우팅 허용이다.

이를 설정해주지 않으면 내부 네트워크에 접근할 수가 없다.

아래와 같은 내용의 섹션을 찾아보자.

push "route IP_Subnet NetMask"
#예) push "route 192.168.0.0 255.255.0.0"

image

만약 VPN을 통해 접근하고자 하는 네트워크의 서브넷이 192.168.10.0/24, 192.168.20.0/24라면 위와 같이 설정해주면 된다.

추가로 더 접근을 허용해주고 싶은 네트워크가 있다면 아래에 같은 형식으로 추가하면 된다.


2-8. OpenVPN 서버의 네트워킹 구성 조정

기본적으로 Ubuntu는 들어온 트래픽을 자신을 통해 다른 곳으로 전달하지 않는다.

라우터의 역할을 하지 않기 때문이다.

하지만 VPN 서버의 역할을 하기 위해서는 클라이언트들의 요청을 다른 곳으로 전달하는 기능이 필요하다.

따라서 /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 Address, via 192.168.0.1)이다.

예를 들어 VPN 서버가 위치한 사설 네트워크,

즉 사설 IP 주소 subnet이 192.168.219.0/24이고 게이트웨이가 192.168.219.1이라고 가정해보자.

VPN 클라이언트는 이 네트워크를 지나 172.16.0.0/16 네트워크 subnet으로 접근하려고 해도

우선은 거쳐야 하는 게이트웨이가 바로 VPN 서버의 사설 네트워크 subnet의 게이트웨이가 된다.

그래서 위 예제에 같은 게이트웨이 IP 주소를 사용하고 있는 것이다.

더욱이, 다음 단계에서 설정할 부분이지만

VPN 클라이언트들은 NAT를 통해 VPN 서버의 사설 IP 주소를 사용하여 통신을 할 것이기 때문에,

위와 같이 게이트웨이 IP 주소를 설정하게 되는 것이다.


요약하면 VPN 서버가 다른 네트워크 subnet에 접근하기 위해서 거쳐야 하는 게이트웨이 IP 주소를 설정해 준다고 보면 된다.


두 번째로 생각해야 할 부분은 바로 라우팅 경로에 대한 metric 값이다.

metric 값은 낮을수록 우선순위를 가지는데 이것이 잘못 설정되면 트래픽이 가야 할 방향을 찾지 못하고 엉뚱한 곳으로 전송되어 VPN 서비스가 제대로 이루어지지 않게 된다.

단 해당 포스팅에서는 수동으로 라우팅 경로를 설정했고,

이때의 메트릭 값은 0이므로 최고의 우선순위를 가지게 된다. 따라서 트래픽이 엉뚱하게 전송되는 현상은 일어나지 않는다.


참고로 우분투에서 라우팅의 메트릭 값 수정 방법은 다음과 같다.

# 변경하려는 라우팅을 먼저 제거 
# 이 예제에서는 디폴트 라우팅에 대한 메트릭을 수정함.
sudo ip route del default via 192.168.219.1 dev ens18
sudo ip route add default via 192.168.219.1 dev ens18 metric 0

2-9. 방화벽 설정

우선 방화벽을 통해 NAT 설정을 활성화하자.

이 실습에서는 VPN 서버의 ens18 인터페이스가 내부 네트워크를 바라보고 있고,

이를 통해 VPN 클라이언트가 내부 네트워크에 접근한다.

따라서 해당 인터페이스에 NAT 설정을 활성화해보도록 하겠다.


/etc/ufw/before.rules 파일을 열어서 다음과 같이 수정하자.

# START OPENVPN RULES
-A POSTROUTING -s 10.8.0.0/24 -o "Your_dev_Name" -j MASQUERADE
#예) -A POSTROUTING -s 10.8.0.0/24 -o ens160 -j MASQUERADE
# END OPENVPN RULES

여기서 Interface Name에는 NAT를 수행할 네트워크 인터페이스의 이름을 넣는다. 여기서는 ens18이 되겠다.


다음은 /etc/default/ufw 파일을 편집해주자.

방화벽에서도 패킷 전달을 허용해줘야 한다.

DEFAULT_FORWARD_POLICY="ACCEPT" # DROP -> ACCEPT

마지막으로 방화벽에서 1194/udp에 대한 트래픽을 허용해주도록 설정한다.

앞서 server.conf의 설정에서 OpenVPN이 사용하는 포트와 프로토콜을 변경했다면 이 값 역시 변경된 값으로 맞춰줘야 한다.

sudo ufw allow 1194/udp

변경된 rule이 적용되도록 방화벽 재시작하자.

sudo ufw disable
sudo ufw enable

2-10. OpenVPN 재시작

OpenVPN은 systemd 서비스로 실행되며, systemctl 명령어로 관리할 수 있다.

sudo systemctl enable --now openvpn-server@server.service

2-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

복사한 base.conf 파일을 텍스트 편집기로 열어서 다음과 같은 내용을 설정해주자.

vim ~/client-configs/base.conf

# 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 파일을 수정해주면 된다.


이제 클라이언트용 .ovpn 파일 생성을 위한 스크립트를 작성하자.

vim ~/client-configs/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

스크립트 설명

  • 스크립트 파일을 실행하면 base.conf 파일의 사본을 만든다.
  • 그리고 앞서 클라이언트에 대해 생성한 모든 인증서와 키 파일을 수집하여 그 내용을 추출한 다음에 base.conf의 사본 파일에 해당 내용을 추가한다.
  • 마지막으로 해당 내용을 새로운 클라이언트 구성 파일인 .ovpn으로 내보낸다.

단, 새로운 클라이언트를 추가할 때마다 새로운 키와 인증서를 생성한 후 해당 스크립트를 실행해야 한다.

그리고 새로운 키와 인증서를 생성할 때마다 CN 역시 일치하도록 하여야 하는 것도 잊으면 안된다.


2-12. 클라이언트 구성 파일(.ovpn) 생성

cd ~/client-configs
bash config.sh client1

스크립트를 실행하고 나면 .ovpn 파일이 생성된다.


3. 클라이언트(맥북)에서 OpenVPN에 접속해보기

1. OpenVPN 클라이언트 설치

Mac에서는 OpenVPN 접속을 위해 일반적으로 OpenVPN GUI 클라이언트가 필요하다.

이번 실습에서는 Tunnelblick 이라는 오픈소스 OpenVPN 클라이언트를 맥북에 설치하여 접속해보려고 한다.


2. OpenVPN 설정 파일 준비 (.ovpn 파일)

위에서 생성했던 .ovpn 파일을 맥북으로 업로드하고 접속해보겠다.
image

클라이언트(맥북)에서 VPN 서버의 내부망(192.168.219.0/24)으로 진입이 된 것을 확인할 수 있다.


Loading script...