Ubuntu 18.04에서 StrongSwan을 사용하여 IKEv2 VPN 서버 구축하기

cadenzah·2021년 1월 1일
0
post-thumbnail

일러두기

  • 본 글은 How to Set Up an IKEv2 VPN Server with StrongSwan on Ubuntu 18.04을 번역한 것으로, 본문 내용을 따라하는 과정에서 발생한 문제는 저의 책임이 아닙니다.
  • 원문에는 Ubuntu 버전 별 튜토리얼이 존재하며, Ubuntu 20.04의 튜토리얼도 존재합니다. 다만 관련 후기 등의 정보를 볼 수 있는 본문 댓글이 더 많은 점, 추가적인 최신 자료를 검색하기 용이한 점 등의 이유로 18.04 버전의 구축을 선택했습니다.
  • 역자의 추가 설명이 필요한 경우 따로 표기한 단락에 작성합니다.

들어가기

가상 사설 네트워크(VPN)을 사용하면 여러분이 카페 또는 컨퍼런스장, 공항과 같이 신뢰할 수 없는 네트워크 상으로 오고 가는 트래픽을 안전하게 암호화할 수 있습니다.

IKEv2(Internet Key Exchange v2)는 서버와 클라이언트 간의 직접 IPSec 터널링을 만들어주는 프로토콜입니다. IKEv2 VPN 구현에서 IPSec은 네트워크 트래픽의 암호화를 제공합니다. IKEv2는 일부 OS 플랫폼에서(OS X 10.11+, iOS 9.1+, Windows 10) 추가적인 어플리케이션 없이도 네이티브하게 지원되며, 클라이언트에서 발생하는 문제들을 상당히 잘 해결해줍니다.

이 튜토리얼에서는 Ubuntu 18.04 서버에 StrongSwan을 사용한 IKEv2 VPN 서버를 구축하고, 다양한 OS의 클라이언트 - Windows, macOS, Ubuntu, iOS, Android 등에서 접속하는 방법을 알아봅니다.

시작하기 전에

이 튜토리얼을 완료하려면 다음의 준비 사항이 필요합니다.

저는 Raspberry Pi 4 (2GB)에 Ubuntu 18.04 Server를 설치하여 튜토리얼을 진행할 예정입니다.

1. StrongSwan 설치

우선 StrongSwan을 설치하겠습니다. StrongSwan은 VPN 서버 구성에 사용할 오픈 소스 IPSec 데몬입니다. 또한 공개 키 관련 환경 요소를 설치하여 인증 기관(CA)을 생성하고, 이를 통하여 인증서를 제공할 수 있는 환경을 구성하겠습니다.

IKEv2 기반 VPN 서버는 비대칭 암호화를 기반으로 작동합니다. 이에 대해 잘 모르는 분은 아주 간단하고 쉽게 설명한 영상이 있으니 이를 참고하시기 바랍니다.

서버의 로컬 패키시 캐시를 업데이트하고, 다음 소프트웨어를 설치합니다.

$ sudo apt update
$ sudo apt install strongswan strongswan-pki

이제 모든 요소들이 설치되었으므로, 인증서를 생성하는 단계로 넘어가겠습니다.

(역자주) APT 업데이트 과정에서 문제 발생시

아래와 같은 오류가 발생하면서 apt update가 정상 실행되지 않는 경우가 있습니다.

E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?

이 경우, apt 관련 프로세스를 모두 종료시킨 뒤 다시 apt를 실행하면 해결됩니다.

$ sudo killall apt apt-get

만약 프로세스가 종료되지 않으면, 강제로 종료시킵니다.

$ sudo rm /var/lib/apt/lists/lock
$ sudo rm /var/cache/apt/archives/lock
$ sudo rm /var/lib/dpkg/lock*

이렇게 프로세스를 모두 종료시킨 후, 아래 명령어를 실행합니다.

$ sudo dpkg --configure -a
$ sudo apt update

이렇게 하면 apt update가 정상 실행됩니다.

2. 인증 기관(CA) 생성하기

클라이언트에서 IKEv2 서버를 식별하려면 인증서가 필요합니다. 이 인증서를 생성할 수 있도록 strongswan-pki 패키지에서는 인증 기관(CA)서버 인증서를 생성할 수 있는 유틸리티를 제공합니다.

우선, 앞으로 작업할 파일들을 보관할 디렉토리들을 생성하겠습니다. 디렉토리 구조는 /etc/ipsec.d에 정의된 것과 일부 유사한데, 이후 과정에서 생성되는 파일들을 해당 위치에 옮길 예정입니다. 앞으로 생성할 파일들이 다른 사용자에게 노출되지 않도록 권한을 잠그도록 하겠습니다.

$ mkdir -p ~/pki/{cacerts,certs,private}
$ chmod 700 ~/pki

이제 파일들을 보관할 디렉토리들을 마련했으니, 루트 키를 생성하겠습니다. 이 키는 4096비트 RSA 키로, 루트 CA 서명에 사용됩니다.

아래 명령어를 실행하여 루트 키를 생성하겠습니다.

$ ipsec pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/ca-key.pem

이제 루트 키가 생성되었으니, 이 키를 사용하여 루트 인증서를 서명하고 루트 CA를 생성하겠습니다.

$ ipsec pki --self --ca --lifetime 3650 --in ~/pki/private/ca-key.pem \
$   --type rsa --dn "CN=VPN root CA" --outform pem > ~/pki/cacerts/ca-cert.pem

여기서 구분자(DN) 값은 원하는 것으로 변경할 수 있습니다. 여기서 Common Name(CN)은 단순 설명을 위한 값으로, 현재 환경의 어떤 값과 일치해야 한다거나 하는 제약은 딱히 없습니다.

여기까지 마치면 루트 CA가 생성되어서 잘 동작하게 됩니다. 이제 VPN 서버에서 사용할 인증서를 생성하겠습니다.

3. VPN 서버의 인증서 생성하기

이제 VPN 서버를 위한 인증서와 키를 생성하겠습니다. 이 CA 인증서를 사용하면 클라이언트는 VPN 서버가 인증되었는지 여부를 확인할 수 있게 됩니다.

우선 아래 명령어를 사용하여 VPN 서버를 위한 개인 키를 생성하겠습니다.

$ ipsec pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/server-key.pem

이제 직전 단계에서 생성된 CA의 루트 키를 사용하여 VPN 서버용 인증서를 생성하고 서명하겠습니다. 아래 명령어를 실행하시되, Common Name(CN)과 Subject Alternate Name(SAN) 필드를 여러분이 사용하는 VPN 서버의 도메인 이름 또는 IP 주소로 변경해주시면 됩니다.

$ ipsec pki --pub --in ~/pki/private/server-key.pem --type rsa \
$   | ipsec pki --issue --lifetime 1825 \
$      --cacert ~/pki/cacerts/ca-cert.pem \
$      --cakey ~/pki/private/ca-key.pem \
$      --dn "CN=서버의_도메인_또는_IP" --san "서버의_도메인_또는_IP" \
$      --flag serverAuth --flag ikeIntermediate --outform pem \
$   > ~/pki/certs/server-cert.pem 

역자 주) VPN 서버의 개인 키로부터 공개 키를 생성하고, 이를 포함하는 인증서를 생성하는데 이 떄 앞서 우리가 만든 루트 CA와 루트 키를 사용하여 서명하고 있습니다.

여기까지 마치면 StrongSwan에서 필요로 하는 모든 TLS/SSL 파일들이 생성된 것입니다. 이제 아래 명령어를 실행하여, 이 파일들을 모두 /etc/ipsec.d 디렉토리 아래로 이동시키겠습니다.

$ sudo cp -r ~/pki/* /etc/ipsec.d/

이번 단계에서는 클라이언트와 서버 간에 안전한 통신이 이루어지는 데에 사용되는 인증서 쌍을 생성했습니다. 또한, 이 인증서들을 CA 키(루트 키)를 사용하여 서명하여, 클라이언트가 CA 인증서를 사용하여 VPN 서버의 인증 여부를 확인할 수 있도록 하였습니다. 이제 모든 인증서가 마련되었으니, 어플리케이션을 설정해보겠습니다.

4. StrongSwan 설정하기

StrongSwan은 예시 구문으로 이루어진 디폴트 구성 파일을 가지고 있지만, 여기서 필요한 대부분의 구성은 직접 작성해주어야 합니다. 작업에 앞서 혹시 모르니, 원본 파일을 백업해두도록 하겠습니다.

$ sudo mv /etc/ipsec.conf{,.original}

빈 설정 파일을 생성하고, 파일을 텍스트 편집기로 열겠습니다.

$ sudo vi /etc/ipsec.conf

우선, StrongSwan이 대몬의 상태를 로그로 남겨서 디버깅을 용이하게 하고, 중복 연결을 허용하겠습니다. 아래 라인을 추가합니다.

config setup
    charondebug="ike 1, knl 1, cfg 0"
    uniqueids=no

다음으로, VPN을 위한 설정 부분을 작성하겠습니다. IKEv2 VPN 터널을 생성하고, StrongSwan이 처음 실행될 때 해당 설정을 자동으로 불러오도록 하겠습니다. 아래 라인을 파일에 추가합니다.

# ......
conn ikev2-vpn
    auto=add
    compress=no
    type=tunnel
    keyexchange=ikev2
    fragmentation=yes
    forceencaps=yes

또한, 클라이언트의 연결이 갑자기 끊긴 경우에 연결이 정리되지 않고 "누수된" 경우에 이를 정리하도록 하겠습니다. 아래 라인을 추가합니다.

# ......
conn ikev2-vpn
    # ....
    dpdaction=clear
    dpddelay=300s
    rekey=no

다음으로, 서버 측(좌변) IPSec 인자를 설정합니다. 아래 라인을 추가합니다.

# ......
conn ikev2-vpn
    # ....
    left=%any
    leftid=@서버의_도메인_또는_IP
    leftcert=server-cert.pem
    leftsendcert=always
    leftsubnet=0.0.0.0/0

주의: 서버 ID를 설정할 때, VPN 서버가 도메인으로 식별될 때에만 해당 값에 @ 문자를 붙여야 합니다.

leftid=@vpn.example.com

만약 VPN 서버가 IP 주소로 식별된다면, 그때는 @ 없이 IP 주소만 적어줍니다.

leftid=203.0.113.7 # 예시 IP입니다

다음으로, 클라이언트 측(우변) IPSec 인자 - 사설 IP 주소 범위 또는 DNS 서버 등 - 을 설정합니다.

# ......
conn ikev2-vpn
    # ....
    right=%any
    rightid=%any
    rightauth=eap-mschapv2
    rightsourceip=10.10.10.0/24
    rightdns=8.8.8.8,8.8.4.4
    rightsendcert=never

마지막으로, VPN 서버 연결시 클라이언트에게 사용자 인증을 요청하도록 설정합니다.

# ......
conn ikev2-vpn
    # ....
    eap_identity=%identity

설정 파일의 최종 모습은 아래와 같습니다.

# /etc/ipsec.conf
config setup
    charondebug="ike 1, knl 1, cfg 0"
    uniqueids=no

conn ikev2-vpn
    auto=add
    compress=no
    type=tunnel
    keyexchange=ikev2
    fragmentation=yes
    forceencaps=yes
    dpdaction=clear
    dpddelay=300s
    rekey=no
    left=%any
    leftid=@서버의_도메인_또는_IP
    leftcert=server-cert.pem
    leftsendcert=always
    leftsubnet=0.0.0.0/0
    right=%any
    rightid=%any
    rightauth=eap-mschapv2
    rightsourceip=10.10.10.0/24
    rightdns=8.8.8.8,8.8.4.4
    rightsendcert=never
    eap_identity=%identity

파일을 저장한 뒤 닫습니다.

여기까지 마치면 VPN 실행을 위한 인자를 모두 설정하였으니, 사용자들이 VPN 서버 연결시 사용할 수 있는 계정을 생성하겠습니다.

5. VPN 인증 설정하기

우리의 VPN 서버는 이제 클라이언트 연결을 맞이할 준비가 되었습니다. 하지만 아직 사용자 인증 관련 설정을 아무 것도 하지 않은 상태입니다. 이를 위하여 ipsec.secrets이라는 특별한 설정 파일을 작성해야 합니다.

  • StrongSwan이 서버 인증서를 위한 서버용 개인 키를 어디서 찾을 수 있는지 그 디렉토리를 알려줘야 합니다. 그래야 사용자의 인증 요청(=로그인)을 처리할 수 있습니다.
  • VPN 서버에 연결이 헝요된 사용자 목록을 구성해야 합니다.

아래 명령을 실행하여 ipsec.secrets 파일을 수정하겠습니다.

$ sudo vi /etc/ipsec.secrets

우선, StrongSwan에게 서버 개인 키의 위치를 알려줍니다.

# /etc/ipsec.secrets
: RSA "server-key.pem"

다음으로, 사용자 인증 정보를 정의합니다. 사용하고 싶은 ID 및 패스워드를 적어주면 됩니다.

# /etc/ipsec.secrets
$USERNAME : EAP "$PASSWORD" # $로 시작하는 부분을 원하는 내용으로 대체하면 됩니다

파일을 저장한 뒤 닫습니다. 이제 VPN 인자와 관련된 모든 작업이 끝났으니, VPN 서비스를 재시작하여 지금까지 작성한 설정들이 반영되도록 하겠습니다.

$ sudo systemctl restart strongswan

이제 VPN 서버에는 서버 옵션과 사용자 인증 정보가 모두 설정된 상태입니다. 이제 가장 중요한 부분, 방화벽 관련 설정을 수행할 차례입니다.

6. 방화벽 및 커널 IP 포워딩 설정하기

StrongSwan 설정을 완료했다면, 이제 VPN 트래픽을 포워딩 및 허용할 수 있도록 방화벽을 설정해야 합니다.

앞서 시작하기 전에에서 제공된 튜토리얼을 따라오셨다면, 기본 설정의 UFW 방화벽이 활성화된 상태일 것입니다. UFW가 설정되지 않은 상태라면, 기본 설정을 생성하고 이를 활성화할 수 있습니다.

$ sudo ufw allow OpenSSH
$ sudo ufw enable

이제 표준 IPSec 포트인 500 및 4500번 포트를 통하여 UDP 트래픽이 지나다닐 수 있도록 아래 명령을 통하여 규칙을 추가합니다.

sudo ufw allow 500,4500/udp

다음으로, IPSec 패킷을 라우팅 및 포워딩하는 데에 필요한 로우레벨 정책을 추가하기 위하여 UFW의 설정 파일을 열어야 합니다. 그 전에, 현재 VPN 서버에서 어떤 네트워크 인터페이스를 사용하여 인터넷에 접속하고 있는지를 알아야 합니다. 디폴트 라우트와 관련된 인터페이스가 무엇인지 질의하여 확인할 수 있습니다.

$ ip route | grep default

공개 인터페이스에는 "dev"가 들어있습니다. 예를 들어, 아래 결과는 eth0라는 이름의 인터페이스에 대한 것입니다.

# Output
default via 203.0.113.7 dev eth0 proto static

공개 네트워크 인터페이스를 가지고 있다면, /etc/ufw/before.rules 파일을 열어봅니다.

$ sudo vi /etc/ufw/before.rules

*filter 라인 바로 위, 파일 최상단 근처에, 아래의 설정 내용을 추가합니다.

*nat
-A POSTROUTING -s 10.10.10.0/24 -o eth0 -m policy --pol ipsec --dir out -j ACCEPT
-A POSTROUTING -s 10.10.10.0/24 -o eth0 -j MASQUERADE
COMMIT

*mangle
-A FORWARD --match policy --pol ipsec --dir in -s 10.10.10.0/24 -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360
COMMIT

*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]

위 설정 내용에서 eth0 부분을 여러분이 ip route를 실행했을 때 얻어낸 인터페이스 이름으로 대체해야 합니다. *nat 라인의 내용들은 VPN을 사용하는 클라이언트와 인터넷 간의 트래픽을 방화벽이 올바르게 라우팅 및 조작할 수 있도록 해주는 규칙입니다. *mangle 라인의 내용들은 최대 패킷 세그먼트 크기를 조정하여 특정 VPN 클라이언트에서 발생할 수 있는 문제를 예방해줍니다.

다읍으로, *filter 라인의 블록 다음 위치에 아래와 같이 설정을 추가합니다.

# ......
*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]

-A ufw-before-forward --match policy --pol ipsec --dir in --proto esp -s 10.10.10.0/24 -j ACCEPT
-A ufw-before-forward --match policy --pol ipsec --dir out --proto esp -d 10.10.10.0/24 -j ACCEPT

이 라인들은 방화벽으로 하여금 ESP(Encapsulating Security Payload; 보안 페이로드 캡슐화) 트래픽을 포워딩하도록 하여, VPN 클라이언트가 정상적으로 접속할 수 있도록 해줍니다. VPN 패킷은 신뢰할 수 없는 네트워크 상에서 이동하므로, ESP를 사용하면 추가적인 보안성을 더할 수 있습니다.

여기까지 완료되었으면, 파일을 저장하고 닫습니다.

방화벽을 재시작하기 전에, 네트워크 커널 인자를 수정하여 인터페이스 간에 라우팅을 허용하도록 설정합니다. UFW의 커널 인자 설정 파일을 열겠습니다.

$ sudo vi /etc/ufw/sysctl.conf

아래의 내용들을 설정하겠습니다.

  • 우선, IPv4 패킷 포워딩을 활성화합니다.
  • MTU Path 발견을 비활성화하여 패킷 파편화 문제를 방지합니다.
  • ICMP 리다이렉션의 송수신을 비활성화하여 Man-in-the-middle 공격을 방지합니다.

아래의 라인들을 추가하여 위의 설정 사항들을 반영합니다.

. . .

# Enable forwarding
# Uncomment the following line
net/ipv4/ip_forward=1

. . .

# Do not accept ICMP redirects (prevent MITM attacks)
# Ensure the following line is set
net/ipv4/conf/all/accept_redirects=0

# Do not send ICMP redirects (we are not a router)
# Add the following lines
net/ipv4/conf/all/send_redirects=0
net/ipv4/ip_no_pmtu_disc=1

여기까지 완료되었으면 파일을 저장합니다. UFW가 다시 시작하면 위의 설정 사항이 반영됩니다. 이 모든 변경 사항을 반영하기 위하여 방화벽을 껐다 켜겠습니다.

$ sudo ufw disable
$ sudo ufw enable

위 과정을 수행하겠냐는 확인 프롬프트가 출력될 것입니다. Y를 입력하여 새로운 설정으로 방화벽을 활성화합니다.

7. VPN 연결을 Windows, iOS, macOS 등에서 테스트하기

이제 모든 것이 준비되었으니, 잘 작동하나 테스트해볼 시간입니다. 우선, 앞서 생성한 CA 인증서를 복사하여 VPN 서버에 접속할 클라이언트에 설치해야 합니다. 가장 간단한 방법은 VPN 서버에 접속하여 인증서 파일의 내용을 출력하는 것입니다.

$ cat /etc/ipsec.d/cacerts/ca-cert.pem

출력된 내용은 아래와 비슷합니다.

-----BEGIN CERTIFICATE-----
MIIFQjCCAyqgAwIBAgIIFkQGvkH4ej0wDQYJKoZIhvcNAQEMBQAwPzELMAkGA1UE

. . .

EwbVLOXcNduWK2TPbk/+82GRMtjftran6hKbpKGghBVDPVFGFT6Z0OfubpkQ9RsQ
BayqOb/Q
-----END CERTIFICATE-----

이 출력 결과를 그대로 여러분의 컴퓨터에 복사하여 ca-cert.pem 등의 이름을 붙여 별도 파일로 저장합니다. 파일 확장자는 .pem이어야 합니다.

이 인증서 파일을 다운받았다면, 이제 VPN 연결을 시도해볼 수 있습니다.

Windows에서 연결하기

TBD

macOS에서 연결하기

다음 단계에 따라 인증서를 가져옵니다.

  1. 인증서 파일을 더블 클릭합니다. 키체인 접근 창이 열리면서 "키체인 접근이 시스템 키체인을 수정하려고 합니다. 이를 허용하려면 암호를 입력하십시오." 라는 대화 창이 열립니다.
  2. 암호를 입력하고 키체인 수정하기를 클릭합니다.
  3. 인증서 파일을 더블 클릭합니다. 그러면 신뢰 수준을 지정할 수 있는 작은 속성 창이 열립니다. IP 보안(IPec)항상 신뢰로 설정하면 다시 한번 암호 입력 창이 열립니다. 이 설정은 비밀번호를 입력한 후 자동으로 저장됩니다.

이제 이 인증서가 중요하고 신뢰할 수 있다고 설정되었으니, 다음 단계를 통해 VPN 연결을 구성합니다.

  1. 시스템 환경설정으로 이동한 후 네트워크를 선택합니다.
  2. 좌측 네트워크 목록의 아래에 있는 + 버튼을 클릭합니다.
  3. 열리는 팝업에서 인터페이스VPN으로 설정하고, VPN 유형IKEv2로 설정한 다음 연결 이름을 지정합니다.
  4. 서버 주소원격 ID 필드에 VPN 서버의 도메인 이름 또는 IP 주소를 입력합니다. 로컬 ID 필드는 비워둡니다.
  5. 인증 설정을 클릭하고 사용자 이름을 선택한 다음, 5단계에서 추가한 사용자 ID와 암호를 입력합니다. 확인을 클릭합니다.

마지막으로 연결을 클릭하여 VPN에 연결합니다. 정상적으로 VPN에 연결될 것입니다.

iOS에서 연결하기

TBD

Android에서 연결하기

TBD

마무리

이 튜토리얼에서는 IKEv2 프로토콜을 사용하는 VPN 서버를 만들었습니다. 이제 여러분의 온라인 활동이 언제 어디서나 안전함을 보장받을 수 있게 되었습니다!

사용자를 새로 추가하거나 제거하려면, 5단계를 반복하면 됩니다. 라인 한 줄이 한 명의 사용자에 해당하니, 사용자를 추가/제거하는 것은 파일을 수정하는 간단한 작업입니다.

댓글

TBD

1개의 댓글

comment-user-thumbnail
2022년 5월 30일

안녕하세요? 자세한 설명 감사드립니다! ^^;

Win10이나 Android에 적용하기 위해 cat /etc/ipsec.d/cacerts/ca-cert.pem 의 내용을 복사해서
ca-cert.cer 로 저장하는게 맞겠지요?
그다음에 이 인증서를 Win10하고 Android에 설치 후
위에 알려주신대로 서버 도메인과 접속 id, pwd 대로 VPN 계정 만들었는데 접속이 안되네요 ㅠ

윈도우에선 IKE인증 자격 증명을 받아들일 수 없습니다
안드로이드에선 Failed to establish VPN : Verifying server authentication failed.
라고 뜹니다.

어디가 잘못 된 걸까요? ^^;

답글 달기