Skip to content

Aeron/ikev2-strongswan-vpn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IKEv2 Strongswan VPN Docker Image

A compact Strongswan IKEv2 VPN container image based on bitnami/minideb base image.

By default, the minimum configuration is CNSA Suite compliant.

Usage

This image is available as docker.io/aeron/ikev2-strongswan-vpn and ghcr.io/Aeron/ikev2-strongswan-vpn. You can use them both interchangeably.

docker pull docker.io/aeron/ikev2-strongswan-vpn
# …or…
docker pull ghcr.io/aeron/ikev2-strongswan-vpn

Container Running

Run a container with the --privileged flag:

docker run -d --privileged --name ikev2-vpn --restart=unless-stopped \
    -p 500:500/udp \
    -p 4500:4500/udp \
    aeron/ikev2-strongswan-vpn:latest

Or, it is always possible to run it only with the NET_ADMIN capability:

docker run -d --name ikev2-vpn --restart=unless-stopped \
    --cap-add net_admin \
    -p 500:500/udp \
    -p 4500:4500/udp \
    aeron/ikev2-strongswan-vpn:latest

Note

In this case, related kernel parameters setup must be set before.

Logging Mode

The LOGGING_MODE environment variable could be convenient for setting a different logging level. It accepts the following values:

  • zero for almost silent logging;
  • less for only necessary info;
  • some for standard logging and errors.

Unset value behaves as some, yet adds debugging for cfg, ike, and net subsystems.

For finer tuning better to mount a custom /etc/strongswan.conf.

Entrypoint Options

The entrypoint script supports the following commands and parameters:

Usage: /entrypoint.sh [COMMAND [NAME]]

Commands:
  add-psk      Add a new PSK credential
  get-psk      Print a secret for a PSK credential
  del-psk      Delete a PSK credential
  set-psk-id   Enforce an ID usage for a PSK credential
  profile-psk  Print a PSK device management profile for macOS/iOS
               [requires: $HOST]
  start        Start the charon-systemd
               [default]

Parameters:
  NAME         A desired PSK credential name
               [default: "default"]

PSK Credentials

Management

To add, get, or delete a pre-shared key, use the following command pattern:

docker run -it --rm --volumes-from ikev2-vpn \
    aeron/ikev2-strongswan-vpn:latest \
    COMMAND [NAME]
# …or…
docker exec -it ikev2-vpn /entrypoint.sh COMMAND [NAME]

Supported commands and parameters are described above.

If you are running the image for the first time and only need a single default credential, then do this:

docker run -it --rm --volumes-from ikev2-vpn \
    aeron/ikev2-strongswan-vpn:latest \
    add-psk
docker run -it --rm --volumes-from ikev2-vpn \
    aeron/ikev2-strongswan-vpn:latest \
    get-psk
# …or…
docker exec -it ikev2-vpn /entrypoint.sh add-psk
docker exec -it ikev2-vpn /entrypoint.sh get-psk

It will create a new PSK credetial and display it. If you want a one-click solution instead, then check out the profile section.

Persistency

It is possible to save/restore pre-shared keys by mounting the /etc/swanctl/conf.d directory. For example:

docker run -d --name ikev2-vpn --restart=unless-stopped \
    --cap-add net_admin \
    -p 500:500/udp \
    -p 4500:4500/udp \
    -v /your/local/path:/etc/swanctl/conf.d:rw \
    aeron/ikev2-strongswan-vpn:latest

Simply replace the /your/local/path with a desired directory path.

Migration

There is an auto-migration support for prior-swanctl deployments.

If PSK credentials are still stored in /etc/ipsec.secrets, entrypoint script will try to migrate them to separate /etc/swanctl/conf.d/psk-*.conf files.

While existing /etc/ipsec.secrets will not be touched, it is better to manually remove it at some point. Before you decide to do so, ensure that both credential volumes are mounted at the same time. It might look like so:

docker run -d --name ikev2-vpn --restart=unless-stopped \
    --cap-add net_admin \
    -p 500:500/udp \
    -p 4500:4500/udp \
    -v /path/to/old/ipsec.secrets:/etc/ipsec.secrets:ro \
    -v /path/to/new/config/dir:/etc/swanctl/conf.d:rw \
    aeron/ikev2-strongswan-vpn:latest

It will guarantee you have a migrated configuration safely stored.

Important

Before removing an older configuration, verify that secrets in both configurations are the same.

Note

If you already migrated a configuration but do not want to remove or unmount /etc/ipsec.secrets yet, it is possible to disable auto-migration, by unsetting the IPSEC_AUTO_MIGRATE environment variable.

Important

The resulting /etc/swanctl/conf.d/psk-*.conf files will not include IKE-PSK ID fields because profiles compiled before version 23.0 never strictly addressed the remote ID field. So a client’s remote ID will be treated as %any.

Device Management Profile

To generate a .mobileconfig file for macOS/iOS, run the following:

docker run -it --rm --volumes-from ikev2-vpn \
    -e HOST=example.com \
    aeron/ikev2-strongswan-vpn:latest \
    profile-psk > ikev2-vpn.mobileconfig
# …or…
docker exec -it \
    -e HOST=example.com \
    ikev2-vpn \
    /entrypoint.sh profile-psk > ikev2-vpn.mobileconfig

Replace the example.com with the desired domain name; an IP address may be used instead as well. The HOST environment variable is required.

If there is a need to identify different clients, then LOCAL_ID value could be supplied:

docker run -it --rm --volumes-from ikev2-vpn \
    -e HOST=example.com \
    -e LOCAL_ID=john.example.com \
    aeron/ikev2-strongswan-vpn:latest \
    profile-psk > ikev2-vpn.mobileconfig
# …or…
docker exec -it \
    -e HOST=example.com \
    -e LOCAL_ID=john.example.com \
    ikev2-vpn \
    /entrypoint.sh profile-psk > ikev2-vpn.mobileconfig

Usually, the LOCAL_ID should be an IP address, FQDN, UserFQDN, or ASN1DN, but a simple name suits as well.

Important

The LOCAL_ID (or a combo of local and remote identifiers) must be unique for each simultaneous connection.

(Un)Installation

Copy the resulting ikev2-vpn.mobileconfig file on a macOS machine, then add it by double-clicking. Or transfer it on an iOS device via AirDrop. Also, it can be stored in iCloud Files and added from there.

To install it, search “Profile” in the device settings. It will display all profiles waiting for installation. Proceed from there: click on a profile, then click an “install” button, and authorize it. As a result, there must be a new VPN added with a familiar name.

To remove a VPN service, search “Profile” in a device settings, then delete a previously installed profile.

UUIDs Persistency

To avoid reproducing excessive profiles and VPN services on a device, profile/service UUIDs can be saved/restored by mounting volumes /profile.uuid and /service.uuid, like so:

docker run -it --rm --volumes-from ikev2-vpn \
    -e HOST=example.com \
    -v /path/to/profile.uuid:/profile.uuid \
    -v /path/to/service.uuid:/service.uuid \
    aeron/ikev2-strongswan-vpn:latest \
    profile-psk > ikev2-vpn.mobileconfig
# …or…
docker exec -it \
    -e HOST=example.com \
    -v /path/to/profile.uuid:/profile.uuid \
    -v /path/to/service.uuid:/service.uuid \
    ikev2-vpn \
    /entrypoint.sh profile-psk > ikev2-vpn.mobileconfig

It will generate new UUIDs once and re-use them next time.

Note

Such volumes also can be mounted for a main container somewhat permanently. Then there will be no need to specify it for the profile compilation.

Caveats

Kernel Parameters

If a container was never run in privileged mode and such an approach is undesirable, then run the following first:

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1
sysctl -w net.ipv6.conf.eth0.proxy_ndp=1

Or put a config in /etc/sysctl.d/ permanently, like so:

echo net.ipv4.ip_forward=1 | sudo tee /etc/sysctl.d/network-tune.conf
echo net.ipv6.conf.all.forwarding=1 | sudo tee /etc/sysctl.d/network-tune.conf
echo net.ipv6.conf.eth0.proxy_ndp=1 | sudo tee /etc/sysctl.d/network-tune.conf

Or use --sysctl options to specify it at runtime:

docker run -d --name ikev2-vpn --restart=unless-stopped \
    --cap-add net_admin \
    --sysctl net.ipv4.ip_forward=1 \
    --sysctl net.ipv6.conf.all.forwarding=1 \
    --sysctl net.ipv6.conf.eth0.proxy_ndp=1 \
    -p 500:500/udp \
    -p 4500:4500/udp \
    aeron/ikev2-strongswan-vpn:latest

Kernel Modules

Running container logs may contain something similar to this:

ip6tables-restore: unable to initialize table 'nat'

Probably, Docker does not load a proper kernel module for IPv6 NAT, so it will be necessary to run modprobe first:

sudo modprobe ip6table_nat

Or simply put a config in /lib/modules-load.d/ permanently, like so:

echo ip6table_nat | sudo tee /lib/modules-load.d/ip6table-nat.conf

IPv6 Support

Docker has IPv6 support out-of-the-box, but it needs to be enabled manually in daemon configuration and a network created afterward. More on this in the official Docker documentation.