라즈베리파이로 홈 VPN 구축하기

무모한 모험의 시작

이번 8월 말에 GDG Campus Korea의 Organizer로서 한국, 중국, 일본, 대만, 홍콩의 Community Organizer들이 모두 모이는 자리인 Northeast Asia Community Summit에 참여하게 되었습니다.

이번 Summit은 중국 상해 에서 열리기 되서 여러가지를 준비해야합니다. 아쉽게도 중국은 무비자로 갈 수 있는 나라가 아니기에 비자를 발급받고, 제공되는 숙소까지 가기 위한 노잣돈과 비상금 환전도 하고, 가서 휴대폰을 사용하기 위해 선불 유심도 구매했습니다. 그러나 제일 중요한 것은… 바로 VPN이더군요.

잘 알려져있듯이, 중국은 공안당국의 인터넷 검열은 심합니다. 실제로 이를 해외에서는 만리장성에 빗대어 Great Firewall이라고 부르며, Facebook, Google, Github1 등 해외 사이트들이 차단되어있습니다. 물론 구입해갈 선불 유심은 하루 300MB를 제공해주지만, 속도에 한계가 있고 맘편히 인터넷을 쓰려면 호텔 와이파이를 사용하는 것이 좋겠죠.

지난 번에 중국 다녀왔을 때 이 만리장성 때문에 불편한 점을 알았기에, 이번에는 안정적인 VPN 서비스를 찾고 있었습니다. 그러던 중 3월 정도에 뽐뿌로 예약구매를 했던 라즈베리파이 3 B+ 모델이 눈에 들어왔습니다.

허각이 부릅니다. 나를 잊지 말아요.

허각이 부릅니다. 나를 잊지 말아요.

애석하게도 이 녀석 덕분에 인턴하면서 회사에 구축했던 VPN이 생각나버렸습니다. 이 죽일 놈의 직업병 마침 제 방에는 KT 기가인터넷 허브(4포트)도 있으니 중국에서 과연 쓸만할지 궁금해졌네요. 그래서 결국엔 불장난을 시작해버렸습니다.

재료를 준비하자

제일 먼저 하드웨어적인 측면에서 준비를 시작했습니다. 라즈베리파이는 있고, 라즈베리파이를 연결할 랜선과 허브, 그리고 USB 전원이면 끝입니다. 아, 물론 실제로 쓰려면 각종 설정들을 진행해줘야겠죠.

제일 먼저 SD카드에 Raspbian OS을 올려줍니다. 이전에 윈도우를 사용할 때는 Rufus라는 툴을 애용했었는데, 이제는 Etcher라는 툴이 더 많이 쓰이는 것 같아 이걸로 Flashing을 했습니다.

etcher-flash

OS를 올렸으니 이제 보안 설정을 할 차례입니다.2 사실 공유기에 꽂아서 쓰면 대부분의 보안문제가 해결되겠지만, 공유기가 오래된거라 기가비트를 지원하지 않습니다. 따라서 속도면에서 장점을 많이 못 얻을 것 같아 허브에 직접 연결해서 인터넷에 직접 접속하려고 했습니다. 그러다보니 아무 대비를 하지 않으면 보안 위협에 노출되기에, 이를 막기 위해 5가지를 해야한다고 생각했습니다.

  • VNC 사용 중단하기
  • Root Login 막기
  • Password Login 막기
  • Public Key Login으로 나만 들어갈 수 있게 하기
  • SSH 접속 포트 바꾸기

먼저 VNC를 사용 중단하는 것은, Raspbian에 VNC이 기본적으로 지원되기 때문입니다. 이렇기 때문에 공격에 취약해질 수 있는 접촉면을 미리 없애기 위해 VNC를 사용 중단하는 것이며, sudo raspi-config 명령어를 통해 끌 수 있습니다.

남은 4개는 SSH 접속과 관련된 설정으로, /etc/ssh/sshd_config 의 내용을 변경하고, SSH 관련 명령을 실행하면 됩니다. sshd_config 파일은 SSH Daemon에 대한 설정이 정의되어 있는 파일로, 원격접속 관련한 보안 설정도 여기서 합니다.3 아까 언급됐던 4가지 설정들에 대한 이유를 쓰자면

  • 원격에서 바로 Root Login하는 것을 막아, 상대적으로 쉽게 Root Login을 하지 못하도록
  • 비밀번호를 추측하는 것으로 접속하지 못하도록 아예 원천 봉쇄
  • 대신 신뢰된 컴퓨터에서만 접속할 수 있도록 Public Key Login 설정
  • 마지막으로, 잘 알려져있는 포트를 사용하지 않게해서 SSH 접속 경로를 (상대적으로) 찾기 어렵게 하기 위해

라고 보시면 됩니다. sshd_config에서 각 항목에 해당하는 옵션들을 조절해주면 되는데, 그 전에 신뢰된 기기에서만 로그인을 허용하도록 하기 위해 기기의 Public Key를 먼저 복사해둘 겁니다. 자신의 컴퓨터의 Publick Key는 보통 ~/ssh/id_rsa.pub 4에 저장되어 있습니다. 이 Public Key를 Pi에서 아래와 같이 실행해 추가해주면 됩니다.

# Pi가 현재 SSH 접속은 가능한 상태에서 신뢰된 기기에서 이렇게 실행해줍니다.
$  scp ~/.ssh/id_rsa.pub pi@{Pi의 IP 주소}:~
pi@{Pi의 IP 주소}'s password:
id_rsa.pub                100%  402     9.6KB/s   00:00

다시 Pi에 연결한 키보드와 마우스를 잡아서 필요한 보안 설정들을 진행합니다. /etc/ssh/sshd_config에서 아래의 부분들을 변경해주면 됩니다.

# /etc/ssh/sshd_config

Port 12345
# 기본포트 22 이외에 사용자 정의 포트를 사용하시면 됩니다.
...
ChallengeResponseAuthentication no
...
PasswordAuthentication no
...
UsePAM no
...
PermitRootLog no

이제 각 계정단에서 설정을 해줄 차례입니다. 먼저 Pi를 설치했을 때 기본으로 설정되어 있는 Pi 사용자는 비밀번호를 복잡하게 변경하고, 실제 접속할 계정을 따로 만들 것입니다. (처음 설정하면서 사진 찍는 것을 깜박해서 일반 Debian OS에서 설정하는 것으로 스크린샷을 대체합니다 ㅠㅠ)

먼저 adduser {사용자 이름}으로 새로운 계정을 만들어줍니다. 이 때의 계정은 sudoer로 설정하지 않는다는 점을 기억해둬야합니다.

adduser

그리고 신뢰된 컴퓨터만이 접속할 수 있도록 Pi를 접속하고 싶은 컴퓨터의 SSH Public Key를 Pi에 저장해야합니다. 자신의 컴퓨터의 Publick Key는 보통 ~/ssh/id_rsa.pub 4에 저장되어 있습니다. 이 Public Key를 Pi에서 아래와 같이 실행해 추가해주면 됩니다.

pi@raspberry:~$ su pivpn
pivpn's password:
pivpn@lkay9495-32398:~$ touch ~pivpn/.ssh/authorized_keys
pivpn@lkay9495-32398:~$ cat ~/id_rsa >> ~/pivpn/.ssh/authorized_keys

이렇게 추가해주고, 해당 컴퓨터에서 다시 SSH 로그인을 시도하면 Public Key로 로그인을 시도되는 것을 확인할 수 있습니다.

SSH 성공!

참고로, 새로 만든 pivpn 계정은 sudoer (sudo 권한을 가진 계정들)에 추가하지 않았는데, 이는

Duck DNS로 Dynamic DNS 설정하기

이제 VPN 서버를 열어둘 IP를 확인하는 것이 필요합니다. 이건 식은죽 먹기긴하지만, 이 VPN 서버가 가정용 인터넷을 사용하는 것이 한가지 걸림돌이 됩니다. 보통 서버를 구축한다면 고정 IP를 사용하지만, 보통의 가정용 인터넷에서는 인터넷 사업자(KT, SKT 등 ISP들)들이 임의의 IP를 유동적으로 줍니다. 따라서 언제 어떻게 VPN 서버에 연결된 IP가 바뀔지 모르기 때문에 이에 대한 대비를 하는 것이 필요합니다.

Dynamic DNS(혹은 DDNS) 이용하면 특정 도메인 주소에 대한 A Record를 최신화할 수 있어 유동 IP로 인한 문제를 어느정도 해결할 수 있습니다. 대표적인 예로, iptime 공유기의 경우 자체적으로 Dynamic DNS 기능을 제공하고 있어, 외부에서도 IP주소를 매번 확인할 필요없이 도메인 주소를 통해 공유기와 연결된 각종 기기에 연결할 수 있습니다.5 Dynamic DNS를 설정할 수 있는 방법과 서비스들이 많이 있지만, 여기서는 Duck DNS를 이용해보겠습니다.

오리 꽥꽥

오리 꽥꽥

메인 페이지에서 SNS 계정을 이용해 가입 후 로그인 하면 각 계정에 대한 API Token을 부여받고, Dynamic DNS로 사용할 subdomain 이름을 지정합니다. Duck DNS에서 제공하는 직관적인 API로 IP 주소 Update를 쉽게 할 수 있습니다. 가령 shell에서는 아래와 같이 요청할 수 있습니다.

# 예를 들어 mydomain.duckdns.org에 대해서 IP를 Update한다면
curl "https://www.duckdns.org/update?domains=mydomain&token=12345678-abcd-4567-efgh-000000000000&ip="

이와 같이 요청해서 받는 응답은 두 가지 경우가 있습니다.

# 성공적으로 Update되었을 경우
OK
# Update에 실패했을 경우
KO

이렇기 때문에 Linux 계열 OS에서는 crontab을 활용해 주기적으로 IP를 업데이트할 수 있습니다. 그리고 그에 대한 방법도 여기서 아주 친절히 알려줍니다. 명시된 방법대로 설정을 해주고 기다리게 되면 메인 페이지에서 결과를 확인할 수 있습니다.

API Token, Subdomain, IP는 가렸습니다.

API Token, Subdomain, IP는 가렸습니다.

이렇게 DDNS를 설정하면 설정한 도메인 네임으로 어디서든 라즈베리파이에 접근할 수 있습니다. 물론, SSH의 경우 위에서 언급했던 것처럼 포트번호를 바꿨으니 접속시 올바른 포트 번호를 설정해줘야합니다.

VPN 개통!

이제 VPN 서버 프로그램을 설치할 수 있는 준비가 되었습니다. 여기서는 OpenVPN 기반의 PiVPN을 이용해 설정을 해볼 것입니다. 사실 PiVPN은 OpenVPN 서버를 쉽게 운영할 수 있도록 Script 형식으로 만들어진 프로그램입니다. 따라서 실제 VPN 서버에 연결할 때는 OpenVPN Client들(예, Windows의 경우 OpenVPN GUI, Mac의 경우 Tunnelblick)을 이용해야합니다.

pivpn-step-1

공식홈페이지에 나와있는 것처럼 명령어 한 줄 실행하면 나머지 설치는 이렇게 친절한 Installer가 도와주긴하지만, 네트워크에 대한 배경지식이 있어야 설정할 수 있습니다. 여기서는 주요 부분에 대해서만 설명할 것이며, 상세한 방법은 여기(영문)에서 확인하시기 바랍니다.

Static IP??

pivpn-static-ip

위에서 언급했던 것처럼 VPN 서버이기 때문에 외부에서 접속을 하기 위해서는 공인 IP로 설정이 되어있어야합니다. 이는 위에서 Dynamic DNS를 통해 설정했기 때문에 문제가 없습니다. 다만, Raspberry Pi에서는 PiVPN이 극도로 친절해서 시스템의 IP 설정을 DHCP 에서 수동 IP 로 바꿔버립니다. 이는 나중에 허브를 통한 인터넷 접속을 어렵게 하기 때문에 다시 바꿔줘야합니다. 아래의 수정은 PiVPN 설치가 모두 끝난 후에 하셔야합니다. 6

# 수정은 /etc/network/interface 파일을 하는 것입니다.
# PiVPN 설치 직후 이런 부분이 있을 것입니다.
iface eth0 inet static
        address 10.1.1.125
        netmask 255.0.0.0
        gateway 10.1.1.1
        
# DHCP를 이용하도록 윗 부분을 이렇게 바꿉니다!
iface eth0 inet dhcp
User?? 누구로 해야하지??

pivpn-user

그 다음에는 PiVPN의 권한을 가지고 있을 사용자를 고르는 것입니다. (라즈베리파이에서 실행할 경우, pi 사용자와 {새로운 사용자} 이 2개가 목록에 뜰 것입니다.) 아까 언급했던 것처럼 PiVPN은 OpenVPN의 핵심기능들을 편하게 사용할 수 있도록 일련의 Script로 만들어진 프로그램이기 때문에 openvpn 명령어를 대신 사용해줍니다. 그러나 이 과정에서 권한 문제가 복잡해질 수 있기 때문에 기본 계정인 pi 사용자를 선택할 것을 권장합니다.

UDP? TCP?

pivpn-protocol

VPN 연결에서 사용할 프로토콜을 선택하는 것입니다. 안내문에 나와있는 것처럼 TCP는 정확히 왜 필요한지 알 때만 선택하라 고 되어있는 것처럼 UDP를 선택하시면 됩니다. 이는 두 Protocol의 특성 차이가 있기 때문입니다.

  • UDP는 Packet Loss에 둔감함
  • TCP는 Packet Loss에 굉장히 예민하며, 단순한 통신이라고 하더라도 Server-Client 간에 많은 Request와 Response를 요구함

따라서 TCP를 선택하게 될 경우 VPN 성능 저하로 이어질 수 있기 때문에, 필요한 경우가 아니면 VPN에 대한 프로토콜은 상대적으로 느슨한 UDP를 사용하는 것이 좋습니다.7

Port 번호?

pivpn-port-no

VPN 연결에 사용할 Port 번호를 설정하는 것입니다. 보통 OpenVPN은 기본적으로 1194번 포트를 사용합니다8. 그러나 이 역시 SSH 설정에서 했던 것처럼, 흔한 Port 번호를 사용하지 않고 무작위의 Port 번호를 사용해서 조금이나마 공격에 노출될 가능성을 줄이는 것이 좋습니다.

Public IP? DNS Entry?

첫번째 단계에서 언급했던 것처럼 우리의 VPN 서버는 Dynamic DNS를 통해 IP가 지속적으로 업데이트되므로, DNS Entry를 이용해 접속할 수 있도록 할 것입니다. 이 선택은 VPN 사용자에게 Key를 생성할 때 접속할 서버의 주소를 명시해주기 위합입니다. 주소는 duckdns에서 설정한 도메인 주소를 입력하시면 됩니다.

위의 것들 이외에는 기본으로 선택되어 있는 것을 하시면 됩니다.

똑똑똑 잘 들리나여

이제 PiVPN에서 사용자를 추가하고 잘 연결되는지 테스트해볼 겁니다. 빈 화면에 pivpn만 쳐보면 지원하는 명령들을 확인할 수 있습니다.

pi@raspberry:~# pivpn
::: Control all PiVPN specific functions!
:::
::: Usage: pivpn <command> [option]
:::
::: Commands:
:::  -a, add [nopass]     Create a client ovpn profile, optional nopass
:::  -c, clients          List any connected clients to the server
:::  -d, debug            Start a debugging session if having trouble
:::  -l, list             List all valid and revoked certificates
:::  -r, revoke           Revoke a client ovpn profile
:::  -h, help             Show this help dialog
:::  -u, uninstall        Uninstall PiVPN from your system!

그렇다면 이제 사용자를 추가해서 VPN 프로파일을 받아볼 것입니다.9

pi@raspberry:~# pivpn add
Enter a Name for the Client:  testMobile
Enter the password for the client:
Enter the password again to verify:
spawn ./easyrsa build-client-full test

Note: using Easy-RSA configuration from: ./vars
Generating a 2048 bit RSA private key
...............................+++
# 중략
========================================================
Done! test.ovpn successfully created!
testMobile.ovpn was copied to:
  /home/pi/ovpns
for easy transfer. Please use this profile only on one
device and create additional profiles for other devices.
========================================================

명령문에서 언급하는 것처럼 /home/pi/ovpns에서 해당 사용자가 쓸 수 있는 프로파일이 저장되어있습니다. 이 .ovpn 파일을 다운받고 VPN Cient 프로그램에 추가해주면 VPN 서버에 접속할 수 있습니다. Mac OS의 Tunnelblick 을 설치하고 다운받은 .ovpn 파일을 더블클릭하면 아래와 같이 Tunnelblick 에 프로파일이 추가됩니다.

추가 후 연결하면, 성공적으로 연결되었으며, 공인 IP가 바뀐 것을 알 수 있습니다.

VPN 연결 전에는 이랬던 IP가

VPN 연결 전에는 이랬던 IP가

이렇게 바뀌는 것을 확인할 수 있습니다.

이렇게 바뀌는 것을 확인할 수 있습니다.

결론

저는 이번에 중국을 가기 때문에 대비책으로 VPN 설정을 해놨지만, 방화벽이 설정된 서버를 사용할 경우에 이렇게 VPN 서버를 설정해놓으시면 편합니다. 이동이 잦을 경우, 기기가 연결되어있는 공인 IP 주소가 바뀌기 마련인데, 그럴 때마다 방화벽 설정을 바꿔줘야하지만, VPN을 이용하게 되면 그런 설정을 덜 해도 되기 때문에 덜 번거로울 것입니다.

중국에서의 실사용기와 후기는 중국 갔다온 후 공유하겠습니다. 나름 씨잘데기 없는 기대를 가지고 있는데 잘 됐으면 좋겠네요. 😀

P.S. 본 글에서 소개한 방법을 행동으로 옮겨서 발생하는 책임은 본인에게 있음을 기억하세요. 저도 중국에서 정말 필요한 때 아니면 되도록 사용을 자제할 예정입니다.


  1. 2017년도에 중국을 방문했을 때는 북경에서는 간헐적으로 됐지만, 상해에서는 아예 안 되는 등 지역마다 편차가 존재합니다. 지역별로 원하는 사이트가 작동되는지는 이 사이트에서 확인해보실 수 있습니다. ↩︎

  2. 아직 Pi가 원격접속이 설정되어있지 않기 때문에 Pi에 직접 키보드와 모니트를 연결해서 설정해야합니다. 만약 Pi 사용법이 익숙하지 않으면 Raspberry Pi 재단의 공식문서를 확인하세요, ↩︎

  3. Debian 공식문서에서 확인하기. 예시 파일은 이거를 확인해보시면 됩니다. ↩︎

  4. Linux/Mac OS X 기준입니다. Windows의 경우에는 이 방법 을 이용해서 생성하시면 됩니다. 단, Private Key는 유출되지 않게 조심! ↩︎ ↩︎

  5. 물론 Port Forwarding 등 추가작업이 필요합니다만, 현재 ISP에 의해 할당된 공인 IP의 변경사항을 자동으로 업데이트 가능하기 때문에 여기선 언급하지 않습니다. Port Fowarding에 대한 정보가 필요하시면 여기로! ↩︎

  6. 참고 : https://linuxconfig.org/how-to-setup-a-static-ip-address-on-debian-linux ↩︎

  7. 참고 : https://security.stackexchange.com/questions/27806/whats-the-difference-between-vpn-over-tcp-vs-udp ↩︎

  8. 참고: https://wiki.wireshark.org/OpenVPN ↩︎

  9. OpenVPN은 동일 프로파일로 서로 다른 기기에서 중복으로 접속하는 것을 막고 있습니다. 따라서 기기마다 프로파일을 생성하는 것을 권장하고 있으며, 저는 프로파일 이름 뒤에 기기 종류를 명시하는 방법을 취하고 있습니다. ↩︎