본문 바로가기

컴퓨터/보안

stunnel + OpenVPN 구축하기 (Ubuntu 20.04 서버)

 

  요새 오라클 클라우드에 VPN 구축하는 재미에 들려서 또다른 VPN을 찾다보니 OpenVPN을 SSL로 터널링하는 방식이 있었다. 그냥 OpenVPN만 사용하는 것보다 SSL로 한번 더 감싸주기 때문에 중국 같이 감시와 통제가 심한 나라에서 VPN을 탐지되지 않게 접속할 수 있는 방식이라고 한다.

  아래 블로그에 아주 자세히 나와있어서 대부분 참고를 했으며, 일부 설정이나 옵션은 필요한 것은 찾아서 추가했다.

 

jayden-chua.medium.com/stunnel-openvpn-server-on-ubuntu-18-04-1837eaf2077d

 

Stunnel + OpenVPN Server on Ubuntu 18.04

My documented journey as I go through the entire process of setting up Stunnel + OpenVPN on Ubuntu 18.04.

jayden-chua.medium.com

 

1. OpenVPN, stunnel 설치

$ sudo -s 
$ apt install openvpn stunnel4

 

2. EasyRSA 설치

  EasyRSA는 PKI CA 생성 및 관리를 간편하게 해주는 도구다. 아래 명령으로 EasyRSA를 다운받고 압축을 푼다.

$ cd /opt
$ wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.4/EasyRSA-3.0.4.tgz --no-check-certificate
$ tar xvf EasyRSA-3.0.4.tgz
$ rm -rf EasyRSA-3.0.4.tgz
$ mv EasyRSA-3.0.4 easyrsa_3_0_4

 

  EasyRSA 설정을 위한 초기 변수가 들어있는 vars 파일을 복사하고 원하는 값으로 세팅한다.

$ cd /opt/easyrsa_3_0_4
$ cp vars.example vars
$ nano vars

 

set_var EASYRSA_REQ_COUNTRY     "KR"
set_var EASYRSA_REQ_PROVINCE    "Seoul"
set_var EASYRSA_REQ_CITY        "Seoul"
set_var EASYRSA_REQ_ORG "ORG"
set_var EASYRSA_REQ_EMAIL       "me@exam.com"
set_var EASYRSA_REQ_OU          "My Organizational Unit"

 

  초기화 명령 시 에러 발생하는 것을 막기 위해 openssl-easyrsa.cnf 파일을 열어서 RANDFILE 부분 앞에 #을 추가해 주석 처리한다.

$ nano openssl-easyrsa.cnf

 

# RANDFILE        = $dir/.rand            # private random number file

 

  이후 아래 명령으로 초기화를 진행한다.

$ ./easyrsa init-pki

 

  정상적으로 실행되면 아래와 같은 메시지가 나온다.

Note: using Easy-RSA configuration from: ./vars
init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /opt/easyrsa_3_0_4/pki

 

3. Certificate Authority 생성

  CA 생성을 위해 아래 명령을 실행하면 Common Name을 입력하라는 메시지가 뜨는데 그냥 엔터를 눌러 진행하면 기본값인 "Easy-RSA CA"로 세팅된다.

$ ./easyrsa build-ca nopass

 

4. 서버 키 및 서버 인증서 생성

  서버 키를 생성을 위해 아래 명령을 실행하면 Common Name을 입력하라는 메시지가 뜨는데 그냥 엔터를 눌러 진행하면 "server"로 세팅된다.

$ ./easyrsa gen-req server nopass

 

  명령이 정상적으로 실행되면 아래와 같이 서버 키와 인증서 요청 파일이 생성된다.

Keypair and certificate request completed. Your files are:
req: /opt/easyrsa_3_0_4/pki/reqs/server.req
key: /opt/easyrsa_3_0_4/pki/private/server.key

 

  인증서 서명을 위해 아래 명령을 실행한다. 첫번째 server는 서명요청 타입을 의미하고, 두 번째 "server"는 위에서 세팅한 서버 이름을 뜻한다. 따라서 위에서 "server"가 아닌 다른 이름으로 세팅을 했다면, 두 번째 "server"를 세팅한 이름으로 바꿔준다.

$ ./easyrsa sign-req server server

 

  아래와 같이 확인 메시지가 뜨면 yes를 입력해주고, 정상적으로 실행되면 자체 서명된 서버 인증서가 생성된다.

Type the word 'yes' to continue, or any other input to abort.
  Confirm request details: yes
  
  ....중략....
  
  Certificate created at: /opt/easyrsa_3_0_4/pki/issued/server.crt

 

5. Diffie-Hellman 키, HMAC 생성

  아래 명령으로 Diffie-Hellman 키를 생성한다.

$ ./easyrsa gen-dh

 

  아래와 같은 결과 화면과 함께 Diffie-Hellman 키가 생성된다.

Note: using Easy-RSA configuration from: ./vars
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
...........................+..........................................++*++*++*++*

DH parameters of size 2048 created at /opt/easyrsa_3_0_4/pki/dh.pem

 

  그리고 VPN 인증을 위한 HMAC을 생성한다.

$ openvpn --genkey --secret ta.key

 

6. 인증서 및 키 복사

  위에서 생성한 인증서와 키를 OpenVPN에서 사용할 수 있도록 복사한다.

$ mkdir /etc/openvpn/server/keys
$ cd /opt/easyrsa_3_0_4
$ cp pki/ca.crt /etc/openvpn/server/keys/
$ cp pki/private/server.key /etc/openvpn/server/keys/
$ cp pki/issued/server.crt /etc/openvpn/server/keys/
$ cp pki/dh.pem /etc/openvpn/server/keys/
$ cp ta.key /etc/openvpn/server/keys/

 

7. IP 포워딩 설정

  패킷 포워딩을 위해 sysctl.conf 파일에서 net.ipv4.ip_forward=1 의 주석을 해제한다.

$ nano /etc/sysctl.conf

 

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

 

  아래 명령어를 통해 변경된 세팅을 로드한다.

$ sysctl -p

 

8. NAT 설정

  VPN 대역에서 인터넷망을 사용할 수 있도록 공인 IP와 매핑시켜주고 iptables 규칙을 저장한다. [인터넷인터페이스]에는 인터넷이 가능한 인터페이스를 적어준다. 나의 경우는 ens3이었다.

$ iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o [인터넷인터페이스] -j MASQUERADE
$ netfilter-persistent save

 

9. OpenVPN 서버 설정

  아래 명령어로 OpenVPN 설정 파일을 열어 설정해준다.

$ nano /etc/openvpn/server.conf

 

  port : OpenVPN 포트 번호 

  duplicate-cn : 이 설정을 해주면 동일한 클라이언트 인증서로 여러 기기에서 접속 가능하다.

  max-clients : 최대 클라이언트 수

  server 10.8.0.0 255.255.255.0 : VPN 클라이언트가 접속 시 이 대역을 IP주소를 할당받는다.

 

cipher AES-256-CBC
auth SHA256
port 1194
proto tcp
dev tun
tun-mtu 1500
tun-mtu-extra 32
mssfix 1410
duplicate-cn
max-clients 10
client-to-client
tls-auth /etc/openvpn/server/keys/ta.key 0
key-direction 0
ca /etc/openvpn/server/keys/ca.crt
cert /etc/openvpn/server/keys/server.crt
key /etc/openvpn/server/keys/server.key
dh /etc/openvpn/server/keys/dh.pem

server 10.8.0.0 255.255.255.0
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
keepalive 10 60
reneg-sec 0
persist-tun
status /var/log/openvpn.log
verb 3
socket-flags TCP_NODELAY
push "socket-flags TCP_NODELAY"

 

  이후 OpenVPN 서버를 재시작한다.

$ service openvpn restart

 

10. OpenVPN 클라이언트 키 및 클라이언트 인증서 생성 

  EasyRSA를 이용해 클라이언트 키를 생성한다. 아래 명령어를 실행하면 Common Name을 묻는데, 사용자명을 입력해도 되고 그냥 엔터를 누르면 "client"로 지정된다.

$ cd /opt/easyrsa_3_0_4/
$ ./easyrsa gen-req client nopass

 

  클라이언트 인증서를 생성한다. 4번 서버 인증서 생성 때와 마찬가지로 두 번째 인자 "client"는 위에서 지정한 사용자명이다.

$ ./easyrsa sign-req client client

 

  이제 인증서와 키를 클라이언트에서 사용하기 위해 SCP 등을 이용해 복사한다.

  먼저 /tmp 디렉터리에 인증서와 키를 복사하고, 현재 root 권한으로 명령어를 실행하고 있으므로 SCP로 접속할 계정 소유로 파일의 소유권을 변경해준다. 나는 ubuntu 계정만 원격 접속이 가능하게 사용중이라 ubuntu 계정 소유로 변경해주었다.

$ cp /opt/easyrsa_3_0_4/{ta.key,pki/{ca.crt,private/client.key,issued/client.crt}} /tmp/
$ chown ubuntu /tmp/{ca.crt,client.key,client.crt,ta.key}

 

  이후 클라이언트 역할을 할 윈도우에서 명령 프롬프트를 열어 아래 명령을 실행하여 인증서와 키를 다운로드 폴더로 가져온다.

c:\> scp -i [비밀키경로] ubuntu@[서버주소]:/tmp/{ca.crt,client.key,client.crt,ta.key} %userprofile%/Downloads/

 

  이제 서버에 /tmp 디렉터리에 옮겨둔 인증서와 키를 삭제한다.

$ rm -f /tmp/{ca.crt,client.key,client.crt,ta.key}

 

11. stunnel 서버 설정

  먼저 stunnel에서 사용할 인증서와 키를 생성해야 한다. 아래 명령어로 stunnel.pem과 stunnel.p12 파일이 생성되는데, 각각 윈도우 클라이언트와 안드로이드 클라이언트에서 사용한다.

$ cd /etc/stunnel/ 
$ openssl genrsa -out key.pem 2048 
$ openssl req -new -x509 -key key.pem -out cert.pem -days 3650 
$ cat key.pem cert.pem >> stunnel.pem 
$ openssl pkcs12 -export -out stunnel.p12 -inkey key.pem -in cert.pem

 

  이제 stunnel 서버 설정 파일인 stunnel.conf 파일을 연다.

$ nano /etc/stunnel/stunnel.conf

 

  아래 내용을 붙여넣고 저장한다. connect에 지정하는 포트 번호는 9번 OpenVPN 서버 설정 시 설정한 포트와 동일하게 설정해야 한다.

chroot = /var/lib/stunnel4
pid = /stunnel4.pid
setuid = stunnel4
setgid = stunnel4
socket = l:TCP_NODELAY=1

[openvpn]
accept = 443
connect = localhost:1194
cert = /etc/stunnel/stunnel.pem

 

  Ubuntu 서버가 재부팅되더라도 stunnel 서버가 자동 시작하도록 하기 위해 systemd에 서비스로 등록하는 작업이 필요하다. 아래 명령으로 stunnel.service를 연다.

$ nano /lib/systemd/system/stunnel.service

 

  아래 내용을 추가하고 저장한다.

[Unit]
Description=SSL tunnel for openvpn
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target
Alias=stunnel.target

[Service]
Type=forking
ExecStart=/usr/bin/stunnel /etc/stunnel/stunnel.conf
ExecStop=/usr/bin/pkill stunnel
WorkingDirectory=/etc/stunnel

TimeoutSec=600

Restart=always
PrivateTmp=false

 

  서비스를 활성화하고 시작한다.

$ systemctl enable stunnel.service
$ systemctl start stunnel.service

 

12. 클라이언트 파일 다운로드

  11번에서 생성한 stunnel.pem 파일과 stunnel.p12 파일을 클라이언트로 복사한다.

$ cp /etc/stunnel/stunnel.{pem,p12} /tmp
$ chown ubuntu /tmp/stunnel.{pem,p12}

 

  이후 클라이언트 역할을 할 윈도우에서 명령 프롬프트를 열어 아래 명령을 실행하여 다운로드 폴더로 가져온다.

c:\> scp -i [비밀키경로] ubuntu@[서버주소]:/tmp/stunnel.{pem,p12} %userprofile%/Downloads/

 

  이제 서버에 /tmp 디렉터리에 옮겨둔 파일을 삭제한다.

$ rm -f /tmp/stunnel.{pem,p12}

 

  여기까지 Ubuntu 20.04 서버에서 stunnel + OpenVPN 설정이 끝났다.

  윈도우와 안드로이드에서 stunnel + OpenVPN 클라이언트로 접속하는 방법은 다음 포스팅에서 이어서 진행하겠다.

 

13. 방화벽에서 443 포트 허용

  마지막으로 클라이언트에서 stunnel을 통해 서버의 443 포트로 접속해야하므로 방화벽에서 443 포트 인바운드를 허용해줘야 한다. 나는 오라클 클라우드 방화벽을 쓰고 있어서 아래와 같이 Security List에 Ingress Rule을 추가해주었다.

 

 

참고자료

Stunnel + OpenVPN Server on Ubuntu 18.04