IKEv2 VPN v cloudu snadno a rychle

✍️ Vláďa Smitka
📅 02. 09. 2016

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

Cloud Init na GitHubu.

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ě:

Windows IKEv2 VPN

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:

Apple MacOS IKEv2 VPN

Nastavení na iOS:

IOS IKEv2 VPN

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:

Štítky: ,

2 comments on “IKEv2 VPN v cloudu snadno a rychle”

  1. 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....

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

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *


Lynt services s.r.o

Již 11 let vytváříme efektivnější kampaně, zrychlujeme weby a řešíme jejich bezpečnost. Kombinujeme marketing, vývoj a automatizaci.
poptávka služeb