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

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:

# Debian / Ubuntu
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.

.env.example

Copy .env.example to .env and fill in the values. Generate a credential hash with:

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

list-devices

List all registered devices (admin).

wg-api-client list-devices
wg-api-client --output-format json list-devices

get-device

Get details for a single device (admin).

wg-api-client get-device DEVICE_ID

delete-device

Delete a device (admin). Supports --dry-run.

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

delete-all-devices

Delete all devices (admin). Requires --confirm or interactive confirmation. Supports --dry-run.

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

create-cluster

Create a new cluster (admin).

wg-api-client create-cluster production
wg-api-client --output-format json create-cluster staging

list-clusters

List all clusters (admin).

wg-api-client list-clusters

get-cluster

Get cluster details (admin).

wg-api-client get-cluster CLUSTER_ID

delete-cluster

Delete a cluster and all its devices (admin). Supports --dry-run.

wg-api-client delete-cluster CLUSTER_ID --dry-run
wg-api-client delete-cluster CLUSTER_ID

get-controller

Get the controller device for a cluster (admin).

wg-api-client get-controller CLUSTER_ID

list-cluster-devices

List all devices in a cluster (admin).

wg-api-client list-cluster-devices CLUSTER_ID

get-uxu

Get the UXU device (admin).

wg-api-client get-uxu

add-credential

Add a new API credential (admin).

wg-api-client add-credential \
  --hashed-credential HASH \
  --role admin

--role accepts user (default) or admin.

health

Check API server health. Does not require authentication.

wg-api-client health
wg-api-client --output-format json health

version

Get API server version.

wg-api-client version

completion

Generate shell completion scripts.

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

# zsh
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
    )

Factory from environment

from wg_api_client import WireGuardAPI

api = WireGuardAPI.from_env()

Reads WG_API_URL (required), WG_API_CREDENTIAL, and WG_API_CA_CERT from the environment.

Context manager

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

The session is closed automatically on exit.

Cluster operations

success, data = api.create_cluster("production")
cluster_id = data["id"]

success, clusters = api.list_clusters()
success, devices = api.list_cluster_devices(cluster_id)
success, controller = api.get_cluster_controller(cluster_id)
success, message = api.delete_cluster(cluster_id)

Admin operations

success, devices = api.list_devices()
success, device = api.get_device("device-id")
success, message = api.delete_device("device-id")
success, uxu = api.get_uxu_device()
success, message = api.add_credential("sha256-hash", "admin")

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 Returns Pagination Auth Description
health_check() InfoResponse no none Check server health
get_version() InfoResponse no none Get server version
authenticate() MessageResponse no cred Login, obtain JWT
refresh_auth_token() MessageResponse no token Refresh JWT
ensure_authenticated() bool no auto Auto-refresh if needed
request_wireguard_config(device_id, role, public_key, cluster_id) DeviceResponse no JWT Register device, get config
list_devices(limit, offset) ListResponse yes admin List all devices
get_device(device_id) DeviceResponse no admin Get device details
delete_device(device_id) MessageResponse no admin Delete a device
delete_all_devices() MessageResponse no admin Delete all devices
create_cluster(name) ClusterResponse no admin Create a cluster
list_clusters(limit, offset) ListResponse yes admin List clusters
get_cluster(cluster_id) ClusterResponse no admin Get cluster details
delete_cluster(cluster_id) MessageResponse no admin Delete cluster + devices
get_cluster_controller(cluster_id) DeviceResponse no admin Get cluster controller
list_cluster_devices(cluster_id, limit, offset) ListResponse yes admin List devices in cluster
get_uxu_device() DeviceResponse no admin Get UXU device
add_credential(hashed_credential, role) MessageResponse no admin Add API credential
from_env() WireGuardAPI -- -- Class method: create from env vars
close() None -- -- Close HTTP session

WireGuardHelper

Method Description
generate_keypair() Generate a WireGuard private/public key pair. Returns (private_key, public_key).
create_client_config(config_data, output_file, additional_allowed_ips, table, listen_port, private_key) Write a WireGuard config file with 0600 permissions. Validates IP format, key length, endpoint format, and path traversal.

ConfigManager

Method Description
ConfigManager(config_file) Constructor. Default path: ~/.wg_api_config.
load_config() Load config from file.
save_config() Save config to file with 0600 permissions.
get_api_url() / set_api_url(url) Read/write API URL.
get_hashed_credential() / set_hashed_credential(c) Read/write credential.
get_token() / set_token(token) Read/write JWT token.
get_refresh_token() / set_refresh_token(token) Read/write refresh token.
get_token_expires_at() / set_token_expires_at(ts) Read/write token expiry timestamp.

Exception hierarchy

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

All exceptions accept message and original_error parameters. The base WireGuardAPIError stores the original exception as original_error.

Type aliases

Defined in wg_api_client.types:

Alias Definition Used by
InfoResponse Tuple[bool, Dict[str, Any]] health_check, get_version
MessageResponse Tuple[bool, str] authenticate, delete_device, add_credential, etc.
DeviceResponse Tuple[bool, Dict[str, Any]] request_wireguard_config, get_device, etc.
ListResponse Tuple[bool, List[Dict[str, Any]]] list_devices, list_clusters, list_cluster_devices
ClusterResponse Tuple[bool, Dict[str, Any]] create_cluster, get_cluster

Security

  • No hardcoded credentials or API URLs.
  • Credentials accepted via environment variable (not visible in process listings when using env vars).
  • TLS verification enabled by default; custom CA bundle supported via --ca-cert or WG_API_CA_CERT.
  • Config and key files written atomically with 0600 permissions.
  • Private keys passed explicitly through the call chain, not stored as class-level state.
  • API response data (IP addresses, public keys, endpoints) validated before writing config files.
  • URL path parameters are percent-encoded.
  • SSL errors are classified into specific, actionable messages.
  • Retry with exponential backoff on transient HTTP errors (502, 503, 504).
  • Output path validated against directory traversal.

Development

Install dev dependencies:

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/
flake8 wg_api_client/ tests/ --max-line-length 120
bandit -r wg_api_client/ -c pyproject.toml

CI runs lint, tests (Python 3.9--3.12), build verification, and publishes to PyPI on version tags.

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.2.1.tar.gz (32.5 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.2.1-py3-none-any.whl (32.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: wg_api_client-0.2.1.tar.gz
  • Upload date:
  • Size: 32.5 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.2.1.tar.gz
Algorithm Hash digest
SHA256 0ba74ea8c7990ce7e87f4560c438fd358e98cae94ecca2be64817aa12822308c
MD5 63377ef3f9acfa8c852b8c80962de164
BLAKE2b-256 7f777983781aad76ca2357434cd18e08f3abbf500867ab81e87b5f6eac63e261

See more details on using hashes here.

File details

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

File metadata

  • Download URL: wg_api_client-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 32.9 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.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d250e58aa6cb24c94aa75f7f80d01b3a6373637e508f6f95504df09f0982a74a
MD5 04b67874d3d763f14d29e5118f4f75c8
BLAKE2b-256 662bde5304bf7bd4ca3209e5493905d2908cc3c49d93796bf883a7292dd44111

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