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
0600permissions. - 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
56c1784edf0138e4100e36f7403d3616ef9d39396e16ba44d0cecb3d0d3b21af
|
|
| MD5 |
417b236fc285f3df6741f9aade09c9b5
|
|
| BLAKE2b-256 |
b84bd1f3bc70aca5ac9fffc2c9ea5c8755880c510248beb27b7932e36655a227
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5392fcbd7a4c5b5c68f05335807658b5514988135cf304e689f3093a227f790a
|
|
| MD5 |
29fd9723d11293060e76f08f4f3c8940
|
|
| BLAKE2b-256 |
86a78bb1531187af97c2a9a8a8b43079dd16a95892c3d09cfd07a6cad1a470db
|