Sign inSign up

jesusdf/openconnect

By jesusdf

Updated about 2 months ago

https://github.com/jesusdf/openconnect - Forked from aw1cks/openconnect

Image
0

1.8K

jesusdf/openconnect repository overview

OpenConnect Docker Container

Forked from https://github.com/aw1cks/openconnect to meet custom needs.

github gitlab

Why?

OpenConnect doesn't ship with any init scripts or systemd units. It's also not easy to non-interactively provide username, password and especially OTP. Additionally, running in a docker container gives some extra flexibility with routing.

Additionally, this fork allows split-tunneling, that is only routing traffic through the VPN for specific hostnames or subnets using vpn-splice.

Also, you can specify the tun device name, in case you are using multiple VPNs on the same machine.

Where can I download it?

The image is built by GitHub Actions for amd64 & arm64 and pushed to the following repositories:

How do I use it?

You can run the container using the specified arguments below.

Basic container command
docker run -d \
--cap-add NET_ADMIN \
-e TZ=Europe/Madrid \
-e TUN_DEVICE=tun127 \
-e URL=https://my.vpn.com \
-e USER=myuser \
-e AUTH_GROUP=mygroup \
-e PASS=mypassword \
-e SPLICE_ARGS="server1.vpn.com 192.168.100.0/24" \
-e OTP=123456 \
-e SEARCH_DOMAINS="my.corporate-domain.com subdomain.my.corporate-domain.com" \
-e EXTRA_ARGS="--no-dtls" \
-e SERVERCERT=auto \
-e MIN_SESSION_TIME=600 \
-e RECONNECT_DELAY=600 \
docker.io/jesusdf/openconnect'
All container arguments
VariableExplanationExample Value
TZTimezone informationEurope/Madrid
TUN_DEVICEName of the tun device to usetun127
URLURL of AnyConnect VPNhttps://my.vpn.com
USERUser to authenticate withmyuser
AUTH_GROUPAuthentication Group to use when connecting to VPN (optional)mygroup
PASSPassword to authenticate withmypassword
SPLICE_ARGSSpace separated list of hostnames or networks that should be routed through (or excluded of) the VPNserver1.vpn.com 192.168.100.0/24
OTPOTP/2FA code (optional)123456
SEARCH_DOMAINSSearch domains to use. DNS for these domains will be routed via the VPN's DNS servers (optional). Separate with a space for multiple domainsmy.corporate-domain.com subdomain.my.corporate-domain.com
EXTRA_ARGSAny additional arguments to be passed to the OpenConnect client (optional). Only use this if you need something specific--verbose
SERVERCERTServer certificate pin handling (optional). auto enables trust-on-first-use pinning (see below); or pass an explicit pin-sha256:... valueauto
MIN_SESSION_TIMEMinimum time required to not being threated as premature failure, in seconds (optional).600
RECONNECT_DELAYDelay time to wait until container shuts down after a premature failure, in seconds (optional).600

Notice that vpn-slice accepts several different kinds of routes and hostnames on the command line (via SPLICE_ARGS environment variable):

  • Hostnames alone (hostname1) as well as host-to-IP aliases (alias2=alias2.bigcorp.com=192.168.1.43). The former are first looked up using the VPN's DNS servers. Both are also added to the routing table, as well as to /etc/hosts (unless --no-host-names is specified). As in this example, multiple aliases can be specified for a single IP address.
  • Subnets to include (10.0.0.0/8) in the VPN routes as well as subnets to explicitly exclude (%10.123.0.0/24).

There are many command-line options to alter the behavior of vpn-slice; try vpn-slice --help to show them all.

Automatic server certificate pinning (SERVERCERT=auto)

Many private servers use self-signed certificates, which OpenConnect will not trust unless you pin them with --servercert pin-sha256:.... Maintaining that pin by hand is annoying, so SERVERCERT=auto makes the container manage it for you (trust-on-first-use):

  1. On first start, the container does a TLS-handshake-only probe (no credentials are sent, so no OTP is consumed) to discover the server's pin, then caches it in /vpn/servercert.pin and connects using it.
  2. On later starts it reuses the cached pin.
  3. If the cached pin ever stops matching (the server rotated its key), OpenConnect reports it; the container re-discovers the new pin, logs the change loudly, updates the cache and retries.

The cache lives inside the container filesystem: it survives restarts, and is re-discovered from scratch whenever the container is recreated (e.g. an image update).

The discovery probe is protocol-aware: any protocol-selecting flag you put in EXTRA_ARGS is honored while probing. For non-AnyConnect servers set it there, e.g. EXTRA_ARGS="--protocol=fortinet". As a safety net, if OpenConnect cannot report the pin the container falls back to computing it with openssl, which is protocol-agnostic.

Security note. pin-sha256 is a hash of the server's public key, not of the certificate, so a normal certificate renewal that reuses the same key does not change the pin. Auto-pinning only re-trusts on the very first connection (or when the key actually changes), which is a trust-on-first-use model: convenient, but it cannot detect a man-in-the-middle present at that first moment. If you need strict protection, pass an explicit SERVERCERT=pin-sha256:... (or the --servercert flag via EXTRA_ARGS) obtained through a trusted channel instead.

Requirements
  • docker
  • sudo (and permissions to run ip and docker as root)
  • iproute2
  • jq

Building the container yourself

The following build args are used:

  • BUILD_DATE (RFC3339 timestamp)
  • COMMIT_SHA (commit hash from which image was built)
docker build \
  --build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
  --build-arg COMMIT_SHA="$(git rev-parse HEAD 2>/dev/null || echo 'null')" \
  -t openconnect .

Known issues

When running not in privileged mode, OpenConnect gives errors such as this:

Cannot open "/proc/sys/net/ipv4/route/flush"

This is normal and does not impact the operation of the VPN.

To suppress these errors, run with --privileged.

Tag summary

Content type

Image

Digest

sha256:5d2767ab7

Size

30.4 MB

Last updated

about 2 months ago

docker pull jesusdf/openconnect