V článku o zprovoznění L2TP jsem zmiňoval, že osobně považuji IKEv2, za nejlepší současnou volbu pro VPN. Je tomu tak z několika z několika důvodů:
- je v základu podporovaná na Windows (7+), OSX (10.11+), Linuxu, IOS (9+), Blackberry 10, jen na Androidu je potřeba doinstalovat aplikaci StrongSwan
- nativně podporuje NAT Traversal
- podporuje rozšíření MOBIKE (udrží VPN spojení i při přechodu mezi různými sítěmi - to je užitečné především u mobilních zařízení)
- v případě použití důvěryhodné certifikační autority není potřeba řešit sdílené klíče nebo instalaci certifikátů - uživatel potřebuje jen jméno a heslo
Pro její použití jsou potřeba SSL certifikáty, což může být komplikace. Naštěstí dnes už existuje certifikační autorita Let's Encrypt (dále v textu zkráceně LE), která dovolí proces s certifikáty zautomatizovat a je zajištěna důvěryhodnost CA na straně klienta. Pokud chceme vystavit LE certifikát, tak je ovšem potřeba mít nejprve k dispozici doménové jméno, pro které jej budeme vystavovat. Tento fakt komplikuje automatický deployment na virtuální servery - dopředu nevíme jakou IP adresu server dostane, takže si dopředu ani nemůžeme připravit příslušný DNS záznam. Pro přípravu instalačního skriptu jsem proto využil službu sslip.io (lze použít i obdobné služby nip.io nebo xip.io), která mapuje všechny IP adresy na své doménové jméno - např. IP adresa 8.8.8.8 je dostupná pod jménem 8.8.8.8.sslip.io.
Automatická instalace je opět realizována pomocí cloud-init skriptu pro RedHat/Centos 7/8, do kterého stačí doplnit jen několik vlastních hodnot.
#cloud-config
packages:
- firewalld
write_files:
- path: /etc/strongswan/ipsec.conf
content: |
conn IKEv2-EAP
keyexchange=ikev2
leftid=%any
leftcert=fullchain.pem
leftsubnet=0.0.0.0/0
right=%any
rightsourceip=10.0.1.0/24
rightdns=8.8.8.8
dpdaction=clear
dpddelay=30s
dpdtimeout=1800s
fragmentation=yes
auto=add
rekey=no
leftsendcert=always
rightauth=eap-mschapv2
eap_identity=%identity
ike=aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024!
esp=aes128gcm16-ecp256,aes256gcm16-ecp384,aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024,aes128gcm16,aes256gcm16,aes128-sha256,aes128-sha1,aes256-sha384,aes256-sha256,aes256-sha1!
- path: /etc/strongswan/ipsec.secrets
content: |
: RSA privkey.pem
{jmeno} : EAP "{heslo}"
- path: /etc/sysctl.conf
content: |
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.eth0.rp_filter = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
- path: /etc/cron.daily/update.sh
content: |
#!/bin/bash
/usr/bin/yum -y update
/usr/bin/certbot renew -q
- path: /usr/local/bin/register-le-cert.sh
content: |
#!/bin/bash
MAIL={mail}
DOMAIN=
if [ -z "$DOMAIN" ]
then
IP=$(curl -s https://tools.lynt.cz/ip.php?raw)
certbot certonly --standalone -n -m $MAIL -d $IP.sslip.io --agree-tos
ln -s /etc/letsencrypt/live/$IP.sslip.io/fullchain.pem /etc/strongswan/ipsec.d/certs/fullchain.pem
ln -s /etc/letsencrypt/live/$IP.sslip.io/privkey.pem /etc/strongswan/ipsec.d/private/privkey.pem
sed -i "s/leftid=.*/leftid=$IP.sslip.io/g" /etc/strongswan/ipsec.conf
else
certbot certonly --standalone -n -m $MAIL -d $DOMAIN --agree-tos
ln -s /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/strongswan/ipsec.d/certs/fullchain.pem
ln -s /etc/letsencrypt/live/$DOMAIN/privkey.pem /etc/strongswan/ipsec.d/private/privkey.pem
sed -i "s/leftid=.*/leftid=$DOMAIN/g" /etc/strongswan/ipsec.conf
fi
- path: /etc/systemd/system/vpn.service
content: |
[Unit]
Description=strongSwan IPsec IKEv1/IKEv2 daemon
After=network-online.target
[Service]
ExecStart=/usr/sbin/strongswan start --nofork
StandardOutput=syslog
Restart=on-abnormal
[Install]
WantedBy=multi-user.target
runcmd:
- RELEASE=$(rpm -E %{rhel}) && rpm -i https://dl.fedoraproject.org/pub/epel/epel-release-latest-$RELEASE.noarch.rpm
- yum install wget certbot strongswan -y
- sysctl -p /etc/sysctl.conf
- chmod a+x /etc/cron.daily/update.sh
- chmod a+x /usr/local/bin/register-le-cert.sh
- wget https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem -O /etc/strongswan/ipsec.d/cacerts/lets-encrypt-x3-cross-signed.pem
- register-le-cert.sh
- firewall-offline-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="{myip}" accept'
- firewall-offline-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.1.0/24" accept'
- firewall-offline-cmd --zone=public --add-port=500/udp
- firewall-offline-cmd --zone=public --add-port=4500/udp
- firewall-offline-cmd --zone=public --add-port=443/tcp
- firewall-offline-cmd --zone=public --add-port=80/tcp
- firewall-offline-cmd --remove-service=ssh
- firewall-offline-cmd --zone=public --add-masquerade
- firewall-offline-cmd --zone=public --add-interface=eth0
- systemctl start vpn firewalld
- systemctl enable vpn firewalld
Ve skriptu je třeba upravit následující čtyři hodnoty:
{jmeno} - uživatelské jméno do VPN
{heslo} - heslo do VPN
{ip} - vaše IP adresa pro přístup k SSH (pro samotné zprovoznění není potřeba, bude se hodit až pro budoucí správu)
{mail} - vaše e-mailová adresa pro registraci LE certifikátu
V cloud-init skriptu si pomáhám vytvořením a následným spuštěním bash skriptu, který z naší služby zjistí veřejnou IP adresu virtuálu a podle ní registruje LE certifikát. Dále pak podle domény upraví konfiguraci IPsec (to je nutné pro podporu IOS).
Detailní postup jak spustit stroj s cloud-init skriptem v Amazon AWS naleznete v článku se zprovozněním L2TP, jak to samé udělat na Digital Ocean (v linku je referral, díky kterému získáte 100$ na testy) zase v článku s nastavením Squid Proxy.
Dále jsem se rozhodl cloud-init skripty přepsat i do běžného bash skriptu, díky kterému můžete VPN nainstalovat na již existující stroj. Hodí se i v případě, že poskytovatel nepodporuje cloud-init, ale umí po startu virtuálu vykonat skript.
To je příklad poskytovatele Vultr.com (tímto referral odkazem získáte startovací kredit 50$). Vultr s cloud-init skripty experimentoval, ale zdá se, že je nakonec produkčně nenasadil. Výhodou poskytovatele Vultr je poměrně široká nabídka datacenter, kde naleznete i například Austrálii nebo Japonsko.
Skript je k dispozici mém GitHubu (naleznete zde i do bashe přepsané cloud-init skripty z předchozích dílů).
Postup vytvoření virtuálního na Vultr.com je následující:
1. je potřeba vytvořit startovací skript (je to možné provést i během tvorby nového stroje) - pojmenoval jsem ho IKEv2. Ve skriptu je potřeba doplnit v záhlaví vlastní hodnoty - jméno a heslo do VPN, vaši IP adresu pro správu a e-mailovou adresu pro registraci SSL certifikátu.
2. Vytvořit si virtuální stroj s Centos 7/8, minimální instance je dostatečná:
3. Vybrat vytvořený startovací skript:
Po několika minutách (stáhnou a nainstalovat závislosti pro LE chvilku trvá) bude stroj připraven. Stačí pak již nakonfigurovat klienta podobným způsobem jako v případě L2TP, pouze se vybere IKEv2 a nezadává se sdílené heslo. Jako server je třeba zadat adresu .sslip.io.
V mém případě by to tedy bylo 45.32.153.0.sslip.io. Skript počítá i s tím, že budete chtít použít vlastní doménu - stačí ji vyplnit do proměnné DOMAIN. Doména však musí být již nasměrována na IP adresu severu, jinak se nepodaří registrace LE certifikátu. Pro toto použití je optimální postup nejprve nainstalovat čistý virtuál, na přidělenou IP nasměrovat DNS záznam a následně z příkazové řádky spustit instalační skript.
Nastavení klienta ve Windows 10 vypadá následovně:
Nebo můžete jednoduše použít PowerShell příkaz:
Add-VpnConnection -Name "TEST - IKEv2" -ServerAddress {ip_serveru}.sslip.io -TunnelType IKEv2 -RememberCredential
Nastavení na MacOS:
Nastavení na iOS:
Nastavení na Androidu pomocí StrongSwan:
S tímto návodem tady již zvládnete připravit server s moderním typem VPN IKEv2 s certifikáty od certifikační autority Let's Encrypt. A to jak na službách podporujících cloud-init skripty, tak na službách podporujících spuštění obecného bash skriptu. S tímto skriptem dokážete nakonfigurovat i předem nainstalovaný stroj, na jehož IP je nasměrován DNS záznam.
Vše si můžete vyzkoušet v trial verzi Amazon AWS, na Digital Ocean s 100$ kreditem, nebo na Vultr.com s kreditem 50$.
V minulých návodech jsme nastavovali:
Your script has been very useful to make to get my VPN working. Thank you
BUT: I can't access to my server through SSH anymore because my connection has a dynamic IP.
What was the aim of "- firewall-offline-cmd --zone=public --remove-service-from-zone=ssh". It broke my server....
I'm glad my script helped you.
The purpose of this line is to deny public access to ssh (it is allowed from your ip via the rich rule). If you have dynamic ip please remove the rich rule and the rule removes ssh service from the zone.
You can put the following command to the remote console to allow ssh again:
firewall-cmd --zone=public --add-service=ssh --pernament
In case of dynamic IP I recommend you to change ssh listen port from 22 to anything else, e.g. 7022.
firewall-cmd --zone=public --add-port=7022/tcp --permanent
/etc/ssh/sshd_config - Port 7022
systemctl restart sshd
It is security by obscurity, but it prevents dumb bots from bruteforcing at least. Another solution is to use VPN itself to the ssh access.