SealSkin

vpn

VPN profiles, and the gateways that carry sessions' traffic through them.

A profile is what an administrator imported from a provider's config files: a template (an OpenVPN client config without its remote lines, or a WireGuard [Interface]), the credentials the template asks for, and an endpoint list with one entry per server the files named. A bundle of thousands of files from a provider is one template and a long endpoint list, because the files differ in the server alone; files whose template differs become profiles of their own. The record is shared (vpn_profiles.yml): every node reads the name, the endpoints, which of them are published to users, the connection cap, and who may use the profile. The template, the OpenVPN username and password, and the WireGuard preshared keys are the profile's secrets: with a store key they are sealed under the cluster key (filecrypt.wrap) before the record leaves the node, and without one they are kept as the users' files are.

A session that chose a profile and an endpoint starts on an internal Docker network of its own, which has no route out, beside a gateway container (vpn_image) that holds the one tunnel to the endpoint, forwards the sessions' traffic into it and nowhere else, and answers their DNS through it. The server's own container joins the network to reach the session, the session's /etc/resolv.conf names the gateway, and a one-shot helper from the same image, run in the session's network namespace, points its default route at the gateway. The session's image needs nothing for this, and a gateway that is down leaves its sessions with no path out. One gateway per profile and endpoint on a node carries every session that picked them, so a provider's device limit is spent once per endpoint in use, and max_tunnels caps the gateways of a profile on a node. A gateway starts with the first session that needs it and stops with the last; its rendered files live under node_state_path/vpn/<key> while it runs.

attributelogger
= logging.getLogger(__name__)
attributeKINDS
= ('wireguard', 'openvpn')
attributeMANAGED_LABEL
= 'sealskin.managed-by'
attributeMANAGED_VALUE
= 'sealskin-vpn'
attributeKEY_LABEL
= 'sealskin.vpn'
attributePROFILE_LABEL
= 'sealskin.vpn.profile'
attributeENDPOINT_LABEL
= 'sealskin.vpn.endpoint'
attributeGATEWAY_HOST
= 2
attributeHEALTHY_TIMEOUT
= 120
attributeORPHAN_GRACE
= 90
attributeREMOTE_STATE
= 'running'
attributeMAX_BUNDLE_BYTES
= 64 * 1024 * 1024
attributeMAX_FILE_BYTES
= 1024 * 1024
attributeMAX_FILES
= 20000
attributeCONFIG_SUFFIXES
= ('.ovpn', '.conf')