Wiresteward is a WireGuard peer manager with oauth2 authentication. It is comprised of two components: server and agent.
The design is for Wiresteward server to run on a remote machine in a private network, to which users will connect with WireGuard in order to access the private network.
The agent runs on the user's machine and is responsible for authenticating with the server and retrieving WireGuard configuration.
Both components will configure their local WireGuard devices and route tables as needed to enable access to a private network.
Download the latest binary from: https://github.com/utilitywarehouse/wiresteward/releases
If you're on macOS or Linux and have Homebrew installed, getting Wiresteward is as simple as running:
brew install utilitywarehouse/tap/wiresteward
The Wiresteward agent is responsible for:
- creating network tun devices
- fetching oauth tokens to pass server authentication
- registering WireGuard keys with the Wiresteward server and retrieving configuration
- configuring WireGuard peers
- configuring routes for the subnets allowed by the server
It is recommended that the agent is run as a Systemd (Linux) / launchd (macOS) service.
But you can also run the executable directly:
# wiresteward -agent -config=path-to-config.jsonPlease note that because wiresteward will create and manage network devices
and network routes, it requires NET_ADMIN capabilities. You can run it as
root with sudo.
See examples/server.json and
examples/agent.json for example configuration.
The agent can take a config file as an argument or look for it under the default location:
/etc/wiresteward/config.json
The config contains details about the oauth server and the local devices that we need the agent to manage.
An example, where the config format can be found in
examples/agent.json.
The default MTU for the interfaces created via the agent is 1420 and it comes
from the default value of wireguard-go
package.
Optionally, MTU can be set explicitly per wg device created by the agent via
the configuration file (using the "MTU" key under device config)
The agent identifies itself to the servers with a device id, a UUID that it creates on first start and keeps in a file. The servers keep a lease per user and device id, see Leases per user, so a restart of the agent keeps its lease and several devices of a user can be connected at the same time.
The file is set with -device-id-file and is
/var/lib/wiresteward/device-id by default, next to the oauth token whose
location is set with -token-file. The agent does not start when it cannot read
or create the file, or create the directory of the token, so the directories
have to be writable by the user that runs it. It does not start either when the
file has other content than a UUID, with or without dashes, braces or a
urn:uuid: prefix, and it does not replace it. An empty file is replaced.
Delete the file to give the agent a new identity, which takes a new lease.
Every installation needs its own id. Machines that share the file share a lease and keep replacing each other's, so do not copy the file to another machine, and remove it before taking an image of a machine or cloning a virtual machine.
The agent also sends its version, operating system and architecture as its
User-Agent, which the servers show as the client of a peer.
The agent is designed to run as a Systemd service. An example working service
is described in
examples/wiresteward.service.
A typical location for user defined systemd service is
/etc/systemd/system/wiresteward.service so you'll need to copy the unit file
to that location and then run:
# systemctl daemon-reload
# systemctl enable --now wiresteward.serviceTo look at its logs:
$ journalctl -u wiresteward.serviceAn example working service for launchd is described in
examples/uk.co.uw.wiresteward.plist or if you installed using homebrew examples/homebrew-setup/uk.co.uw.wiresteward.plist
You need to copy the file under /Library/LaunchDaemons/ and then set the
ownership to root:
# chown root:admin /Library/LaunchDaemons/uk.co.uw.wiresteward.plistThen you need to load the service to allow it to run as root. This is required to operate on the network devices and routing table:
# sudo launchctl load /Library/LaunchDaemons/uk.co.uw.wiresteward.plistIf you run into any issues, you can restart with:
# sudo launchctl kickstart -k system/uk.co.uw.wirestewardLogs are stored in /var/log/wirestward.log as defined in the service file. To
view the logs you can:
$ tail -f /var/log/wiresteward.logYou might want to setup log rotation as well if you find that the log file grows too large.
The agent runs a local server on port 7773 and expects the user to visit
http://localhost:7773/ in order to authenticate. Once authenticated, the
agent will be able to continue operating until the token retrieved is expired,
at which point the user needs to authenticate again.
Visiting http://localhost:7773/ will cause the agent to immediately configure
the local WireGuard devices. If it already has a valid token, it will not prompt
the user to re-authenticate but it will re-configure the system.
The Wiresteward server is responsible for:
- creating new network WireGuard device
- registering new peers and allocating ip addresses for them
- configuring WireGuard peers
- revoking access for expired address leases
It is recommended that the agent is run as a systemd service.
The server can take a config file as an argument or look for it under the
default location /etc/wiresteward/config.json. The config contains details
about the oauth server and the network subnets that need to be exposed, as well
as the network subnet from which peer addresses are leased to agents.
An example, where the config format can be found in
examples/server.json.
A lease request can carry a DeviceID, a UUID that identifies the installation
of the agent that sends it. The server keeps one lease, with its own address,
per user and device id, so that several devices of a user can be connected at
the same time. Requests without a device id share one lease per user.
A user can hold at most maxLeasesPerUser leases on a server, 3 by default. A
request from another device over that limit replaces the oldest lease of the
user, the one that was renewed least recently, and takes over its address. A
client that does not keep its device id can therefore not take more addresses
than the limit. The wiresteward_lease_evictions_total metric counts the
replaced leases.
The leases file keeps one line per lease. The user name column is the user name
for a lease without a device id and <user name>|<device id> for the others.
The server will refuse to start if address or any entry in allowedIPs is
not fully contained within a private address range (RFC 1918: 10.0.0.0/8,
172.16.0.0/12, 192.168.0.0/16; or RFC 4193 IPv6 ULA: fc00::/7). This
prevents accidentally configuring a public IP as the WireGuard interface
address, or advertising overly broad routes that could hijack public internet
traffic on connected agents.
If you intentionally need to use public CIDRs, start the server with the
-allow-public-routes flag to bypass this check:
# wiresteward -server -allow-public-routes -config=path-to-config.jsonThere are Terraform modules defined under terraform/ which
describe the recommended deployment method in AWS and GCP. See the more specific
README file for details.
