Skip to main content

WireGuard Configuration API Client

Project description

wg-api-client

Python client library and CLI for the WireGuard Configuration Distribution API. Version 0.3.0.

Installation

Requires Python 3.9 or later.

pip install wg-api-client

From source:

git clone https://github.com/tiiuae/wg-api-client-lib.git
cd wg-api-client-lib
pip install -e .

Key generation requires wireguard-tools:

sudo apt install -y wireguard-tools

Runtime dependency: requests >=2.25.0, <3.0.0.

Configuration

Settings are read from environment variables, CLI flags, or a config file. No credentials or URLs are hardcoded.

Environment variables

Variable Required Description
WG_API_URL yes API base URL (e.g. https://host:8080/api/v1)
WG_API_CREDENTIAL yes SHA-256 hashed credential
WG_API_CA_CERT no Path to CA certificate bundle for TLS

Config file

Stored at ~/.wg_api_config (permissions 0600). Created on first successful auth. Uses INI format with [General] and [Auth] sections.

Generate a credential hash:

echo -n "your-secret" | sha256sum | awk '{print $1}'

CLI Usage

wg-api-client [global flags] <command> [command flags]

Global Flags

Flag Env variable Description
--api-url URL WG_API_URL API base URL
--hashed-credential HASH WG_API_CREDENTIAL Hashed credential
--ca-cert PATH WG_API_CA_CERT CA certificate bundle
--config-file PATH Config file (default: ~/.wg_api_config)
--output-format {text,json} Output format (default: text)

Commands

auth

Authenticate and store the JWT token in the config file.

wg-api-client auth

get-config

Register a device and write a WireGuard configuration file.

wg-api-client get-config \
  --cluster-id CLUSTER_ID \
  --role node \
  --output wg.conf
Flag Description
--cluster-id Cluster to join (required)
--role Device role: node, controller, or uxu (default: node)
--device-id Custom device ID (auto-generated from hardware if omitted)
--public-key WireGuard public key (generated if omitted)
--output Output file path (default: wg.conf)
--allowed-ips Additional allowed IP ranges (repeatable)
--table Routing table for the WireGuard interface
--listen-port Listen port for the WireGuard interface

register-preauth

Register a device using a pre-authorized key (no JWT needed).

wg-api-client register-preauth \
  --preauth-key KEY \
  --output wg.conf

The preauth key determines the cluster and role automatically. Device ID and keys are generated if not provided.

rotate-key

Rotate a device's WireGuard public key.

wg-api-client rotate-key DEVICE_ID --new-public-key KEY

Generates a new key pair if --new-public-key is not provided.

list-devices

List all registered devices (admin). Supports --status filter.

wg-api-client list-devices
wg-api-client list-devices --status active
wg-api-client list-devices --status pending

get-device / delete-device

wg-api-client get-device DEVICE_ID
wg-api-client delete-device DEVICE_ID --dry-run
wg-api-client delete-device DEVICE_ID

delete-all-devices

wg-api-client delete-all-devices --confirm

bulk-register

Bulk register devices from a JSON file (admin).

wg-api-client bulk-register devices.json

JSON file format:

[
  {"device_id": "node-01", "role": "node", "public_key": "...", "cluster_id": "..."},
  {"device_id": "node-02", "role": "node", "public_key": "...", "cluster_id": "..."}
]

Cluster Management

wg-api-client create-cluster production
wg-api-client list-clusters
wg-api-client get-cluster CLUSTER_ID
wg-api-client delete-cluster CLUSTER_ID
wg-api-client get-controller CLUSTER_ID
wg-api-client list-cluster-devices CLUSTER_ID
wg-api-client get-uxu

Pre-Auth Key Management

wg-api-client create-preauth-key \
  --cluster-id CLUSTER_ID \
  --role node \
  --reusable

wg-api-client list-preauth-keys
wg-api-client delete-preauth-key KEY_ID
Flag Description
--cluster-id Cluster for the key (required)
--role Device role: node, controller, uxu
--reusable Allow multiple uses
--expires-in Expiry in hours

Credential Management

wg-api-client add-credential \
  --hashed-credential HASH \
  --role user \
  --allowed-device-roles controller node

--allowed-device-roles restricts which device roles this credential can register. Omit for no restriction.

health / version

wg-api-client health
wg-api-client version

completion

eval "$(wg-api-client completion bash)"
eval "$(wg-api-client completion zsh)"

Device Roles

Role Description Default
node Spoke device, can only reach controller yes
controller Hub device, one per cluster no
uxu Operator device, global access, unique no

Python Library

Basic usage

from wg_api_client import WireGuardAPI, WireGuardHelper
from wg_api_client.unique_id import get_unique_device_id

api = WireGuardAPI(
    api_url="https://vpn.example.com/api/v1",
    hashed_credential="your-sha256-hash",
)

success, message = api.authenticate()

private_key, public_key = WireGuardHelper.generate_keypair()
device_id = get_unique_device_id()

success, config_data = api.request_wireguard_config(
    device_id=device_id,
    role="node",
    public_key=public_key,
    cluster_id="your-cluster-id",
)

if success:
    WireGuardHelper.create_client_config(
        config_data, "wg.conf", private_key=private_key
    )

Register with pre-auth key

api = WireGuardAPI(api_url="https://vpn.example.com/api/v1")

success, config_data = api.request_config_with_preauth(
    device_id="drone-01",
    public_key=public_key,
    preauth_key="your-preauth-key",
)

No credential or authentication needed. The preauth key determines the cluster and role.

Key rotation

success, data = api.rotate_key("drone-01", new_public_key)

Bulk registration

devices = [
    {"device_id": "n1", "role": "node", "public_key": k1, "cluster_id": cid},
    {"device_id": "n2", "role": "node", "public_key": k2, "cluster_id": cid},
]
success, results = api.bulk_register(devices)

Pre-auth key management

success, key_data = api.create_preauth_key(
    cluster_id="...", role="node", reusable=True
)
preauth_key = key_data["key"]  # shown only once

success, keys = api.list_preauth_keys()
success, msg = api.delete_preauth_key(key_id)

Scoped credentials

success, cred = api.add_credential(
    "sha256-hash", "user",
    allowed_device_roles=["controller"],
)

Factory from environment

api = WireGuardAPI.from_env()

Reads WG_API_URL (required), WG_API_CREDENTIAL, and WG_API_CA_CERT.

Context manager

with WireGuardAPI.from_env() as api:
    api.authenticate()
    success, devices = api.list_devices(status="active")

API Reference

WireGuardAPI

Constructor parameters:

Parameter Type Default Description
api_url str (required) Base URL for the API
hashed_credential str None Pre-hashed credential
token str None Existing JWT token
verify bool | str True TLS verify flag or CA bundle path
timeout int 10 Request timeout in seconds
max_retries int 3 Retries on 502/503/504
backoff_factor float 0.5 Exponential backoff factor

Methods:

Method Auth Description
health_check() none Check server health
get_version() none Get server version
authenticate() cred Login, obtain JWT
refresh_auth_token() token Refresh JWT
ensure_authenticated() auto Auto-refresh if needed
request_wireguard_config(device_id, role, public_key, cluster_id) JWT Register device
request_config_with_preauth(device_id, public_key, preauth_key) preauth Register with preauth key
rotate_key(device_id, new_public_key) JWT Rotate device key
bulk_register(devices) admin Bulk register devices
list_devices(limit, offset, status) admin List devices
get_device(device_id) admin Get device details
delete_device(device_id) admin Delete a device
delete_all_devices() admin Delete all devices
create_cluster(name) admin Create a cluster
list_clusters(limit, offset) admin List clusters
get_cluster(cluster_id) admin Get cluster details
delete_cluster(cluster_id) admin Delete cluster + devices
get_cluster_controller(cluster_id) admin Get cluster controller
list_cluster_devices(cluster_id, limit, offset) admin List devices in cluster
get_uxu_device() admin Get UXU device
add_credential(hash, role, allowed_device_roles) admin Add credential
create_preauth_key(cluster_id, role, reusable, expires_in_hours) admin Create preauth key
list_preauth_keys() admin List preauth keys
delete_preauth_key(key_id) admin Delete preauth key
from_env() -- Create from env vars
close() -- Close HTTP session

Exception Hierarchy

WireGuardAPIError
  +-- AuthenticationError
  +-- APIConnectionError
  +-- TLSError
  +-- APITimeoutError

All exceptions accept message and original_error parameters.

Security

  • No hardcoded credentials or API URLs.
  • TLS verification enabled by default; custom CA bundle supported.
  • Config and key files written with 0600 permissions.
  • Private keys passed explicitly, not stored as class state.
  • API response data validated before writing config files.
  • URL path parameters are percent-encoded.
  • SSL errors classified into actionable messages.
  • Retry with exponential backoff on transient HTTP errors.
  • Output path validated against directory traversal.

Development

pip install -r requirements-dev.txt
pip install -e .

Test

pytest -v

Lint

black --check wg_api_client/ tests/
isort --check wg_api_client/ tests/
ruff check .

License

Apache 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wg_api_client-0.3.0.tar.gz (35.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wg_api_client-0.3.0-py3-none-any.whl (37.2 kB view details)

Uploaded Python 3

File details

Details for the file wg_api_client-0.3.0.tar.gz.

File metadata

  • Download URL: wg_api_client-0.3.0.tar.gz
  • Upload date:
  • Size: 35.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for wg_api_client-0.3.0.tar.gz
Algorithm Hash digest
SHA256 56c1784edf0138e4100e36f7403d3616ef9d39396e16ba44d0cecb3d0d3b21af
MD5 417b236fc285f3df6741f9aade09c9b5
BLAKE2b-256 b84bd1f3bc70aca5ac9fffc2c9ea5c8755880c510248beb27b7932e36655a227

See more details on using hashes here.

File details

Details for the file wg_api_client-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: wg_api_client-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 37.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for wg_api_client-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5392fcbd7a4c5b5c68f05335807658b5514988135cf304e689f3093a227f790a
MD5 29fd9723d11293060e76f08f4f3c8940
BLAKE2b-256 86a78bb1531187af97c2a9a8a8b43079dd16a95892c3d09cfd07a6cad1a470db

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page