Giter Site home page Giter Site logo

nhas / wag Goto Github PK

View Code? Open in Web Editor NEW
375.0 8.0 23.0 8.54 MB

Simple Wireguard 2FA

License: BSD 3-Clause "New" or "Revised" License

Go 45.36% HTML 12.04% CSS 0.94% C 30.87% Makefile 0.08% Dockerfile 0.16% Shell 0.12% JavaScript 6.54% SCSS 3.89%
2fa mfa wireguard wireguard-admin firewall vpn management-portal ui network linux

wag's Introduction

Wag

Wag adds 2fa and device enrolment to wireguard.

It allows you to restrict routes based on 2fa, while allowing other routes to remain public as long as a client has a valid public key.

Sponsorship

This work was very kindly supported by Aura Information Security.

image

Requirements

iptables and libpam must be installed.
Wag must be run as root, to manage iptables and the wireguard device.

Forwarding must be enabled in sysctl.

sysctl -w net.ipv4.ip_forward=1

Wag does not need wg-quick or other equalivent as long as the kernel supports wireguard.

Setup instructions

Both options require a kernel newer than 5.9+

Binary release (requires glibc 2.31+):

curl -L $(curl -s https://api.github.com/repos/NHAS/wag/releases/latest | jq -M -r '.assets[0].browser_download_url') -o wag
sudo ./wag gen-config

sudo ./wag start -config <generated_config_name>

From source (will require go1.19, npm, gulp, clang, llvm-strip, libbpf):

git clone [email protected]:NHAS/wag.git
cd wag
make

cp example_config.json config.json

sudo ./wag start

If running behind a reverse proxy, X-Forwarded-For must be set.

Management

The root user is able to manage the wag server with the following command:

wag subcommand [-options]

Supported commands: start, cleanup, reload, version, firewall, registration, devices, users, webadmin, gen-config

start: starts the wag server

Usage of start:
  Start wag server (does not daemonise)
  -config string
        Configuration file location (default "./config.json")

cleanup: Will remove all firewall forwards, and shutdown the wireguard device

reload: Reloads ACLs from configuration

version: Display the version of wag

firewall: Get firewall rules

Usage of firewall:
  -list
        List firewall rules
  -socket string
        Wag socket to act on (default "/tmp/wag.sock")

registration: Deals with creating, deleting and listing the registration tokens

Usage of registration:
  -add
        Create a new enrolment token
  -del
        Delete existing enrolment token
  -group value
        Manually set user group (can supply multiple -group, or use -groups for , delimited group list, useful for OIDC)
  -groups string
        Set user groups manually, ',' delimited list of groups, useful for OIDC
  -list
        List tokens
  -overwrite string
        Add registration token for an existing user device, will overwrite wireguard public key (but not 2FA)
  -socket string
        Wag socket to act on (default "/tmp/wag.sock")
  -token string
        Manually set registration token (Optional)
  -username string
        User to add device to

devices: Manages devices

Usage of devices:
  -address string
        Address of device
  -del
        Remove device and block wireguard access
  -list
        List wireguard devices
  -lock
        Lock device access to mfa routes
  -mfa_sessions
        Get list of devices with active authorised sessions
  -socket string
        Wag control socket to act on (default "/tmp/wag.sock")
  -unlock
        Unlock device
  -username string
        Owner of device (indicates that command acts on all devices owned by user)

users: Manages users MFA and can delete all users devices

Usage of users:
  -del
        Delete user and all associated devices
  -list
        List users, if '-username' supply will filter by user
  -lockaccount
        Lock account disable authention from any device, deauthenticates user active sessions
  -reset-mfa
        Reset MFA details, invalids all session and set MFA to be shown
  -socket string
        Wag socket location, (default "/tmp/wag.sock")
  -unlockaccount
        Unlock a locked account, does not unlock specific device locks (use device -unlock -username <> for that)
  -username string
        Username to act upon

webadmin: Manages the administrative users for the web UI

Usage of webadmin:
  -add
        Add web administrator user (requires -password)
  -del
        Delete admin user
  -list
        List web administration users, if '-username' supply will filter by user
  -lockaccount
        Lock admin account disable login for this web administrator user
  -password string
        Username to act upon
  -socket string
        Wag instance control socket (default "/tmp/wag.sock")
  -unlockaccount
        Unlock a web administrator account
  -username string
        Admin Username to act upon

User guide

Installing wag

  1. Copy wag, config.json to /opt/wag
  2. Generate a wireguard private key with wg genkey set PrivateKey in the example config to it
  3. Copy (or link) wag.service to /etc/systemd/system/ and start/enable the service

Creating new registration tokens

First generate a token.

# ./wag registration -add -username tester
token,username
e83253fd9962c68f73aa5088604f3f425d58a963bfb5c0889cca54d63a34b2e3,tester

Then curl said token.

curl http://public.server.address:8080/register_device?key=e83253fd9962c68f73aa5088604f3f425d58a963bfb5c0889cca54d63a34b2e3

The service will return a fully templated response:

[Interface]
PrivateKey = <omitted>
Address = 192.168.1.1

[Peer]
Endpoint =  public.server.address:51820
PublicKey = pnvl40WiRt++0NucEGexlpfwWA8QzBYg2+8ZWZJvejA=
AllowedIPs = 10.7.7.7/32, 192.168.1.1/32, 192.168.3.4/32, 192.168.3.5/32
PersistentKeepAlive = 10

Which can then be written to a config file.

Entering MFA

To authenticate the user should browse to the servers vpn address, in the example, case 192.168.1.1:8080, where they will be prompted for their 2fa code.
The configuration file specifies how long a session can live for, before expiring.

Signing in to the Management console

Make sure that you have ManagementUI.Enabled set as true, then do the following from the console:

sudo ./wag webadmin -add -username <your_username> -password <your-password-here>

Then browse to your management listening address and enter your credentials.

The web interface itself cannot add administrative users.

Configuration file reference

Proxied: Respect the X-Forward-For directive, must ensure that you are setting the X-Forward-For directive in your reverse proxy as wag relies on the client IP for authentication in the VPN tunnel
HelpMail: The email address that is shown on the prompt page
Lockout: Number of times a person can attempt mfa authentication before their account locks
NAT: Turn on or off masquerading
ExposePorts: Expose ports on the VPN server to the client (adds rules to IPtables) example: [ "443/tcp", "100-200/udp" ]
CheckUpdates: If enabled (off by default) the management UI will show an alert if a new version of wag is available. This talks to api.github.com
MFATemplatesDirectory: A string path option, when set templates will be queried from disk rather than the embedded copies. Allows you to customise the MFA registration, entry, and success pages, allows custom js and css in the MFATemplatesDirectory /custom/ directory
DownloadConfigFileName: The filename of the wireguard config that is downloaded, defaults to wg0.conf

ExternalAddress: The public address of the server, the place where wireguard is listening to the internet, and where clients can reach the /register_device endpoint

MaxSessionLifetimeMinutes: After authenticating, a device will be allowed to talk to privileged routes for this many minutes, if -1, timeout is disabled
SessionInactivityTimeoutMinutes: If a device has not sent data in n minutes, it will be required to reauthenticate, if -1 timeout is disabled

DatabaseLocation: Where to load the sqlite3 database from, it will be created if it does not exist
Socket: Wag control socket, changing this will allow multiple wag instances to run on the same machine
Acls: Defines the Groups and Policies that restrict routes
Policies: A map of group or user names to policy objects which contain the wag firewall & route capture rules. The most specific match governs the type of access a user has to a route, e.g if you have a /16 defined as MFA, but one ip address in that range as allow that is /32 then the /32 will take precedence over the /16
Policies.<policy name>.Mfa: The routes and services that require Mfa to access
Policies.<policy name>.Public: Routes and services that do not require authorisation Policies.<policy name>.Deny: Deny access to this route

Webserver: Object that contains the public and tunnel listening addresses of the webserver

WebServer.Public.ListenAddress: Listen address for endpoint
WebServer.Tunnel.Port: Port for in-vpn-tunnel webserver, this does not take a full IP address, as the tunnel listener should never be outside the wireguard device

WebServer.<endpoint>.CertPath: TLS Certificate path for endpoint
WebServer.<endpoint>.KeyPath: TLS key for endpoint

Authenticators: Object that contains configurations for the authentication methods wag provides
Authenticators.Issuer: TOTP issuer, the name that will get added to the TOTP app
Authenticators.DomainURL: Full url of the vpn authentication endpoint, required for webauthn and oidc Authenticators.DefaultMethod: String, default method the user will be presented, if not specified a list of methods is displayed to the user (possible values: webauth, totp, oidc, pam)
Authenticators.Methods: String array, enabled authentication methods, e.g ["totp","webauthn","oidc", "pam"].

Authenticators.OIDC: Object that contains OIDC specific configuration options Authenticators.OIDC.IssuerURL: Identity provider endpoint, e.g http://localhost:8080/realms/account Authenticators.OIDC.ClientID: OIDC identifier for application Authenticators.OIDC.ClientSecret: OIDC secret Authenticators.OIDC.GroupsClaimName: Not yet used.

Authenticators.PAM.ServiceName: Name of PAM-Auth file in /etc/pam.d/ will default to /etc/pam.d/login if unset or empty

Wireguard: Object that contains the wireguard device configuration
Wireguard.DevName: The wireguard device to attach or to create if it does not exist, will automatically add peers (no need to configure peers with wg-quick)
Wireguard.ListenPort: Port that wireguard will listen on
Wireguard.PrivateKey: The wireguard private key, can be generated with wg genkey
Wireguard.Address: Subnet the VPN is responsible for
Wireguard.MTU: Maximum transmissible unit defaults to 1420 if not set for IPv4 over Ethernet
Wireguard.DNS: An array of DNS servers that will be automatically used, and set as "Allowed" (no MFA)

ManagementUI: Object that contains configurations for the webadministration portal. It is not recommend to expose this portal, I recommend setting ListenAddress to 127.0.0.1/localhost and then use ssh forwarding to expose it
ManagementUI.Enabled: Enable the web UI
ManagementUI.ListenAddress: Listen address to expose the management UI on
ManagementUI.CertPath: TLS Certificate path for management endpoint
ManagementUI.KeyPath: TLS key for the management endpoint

Full config example

{
    "Proxied": true,
    "ExposePorts": [
        "443/tcp",
        "100-200/udp"
     ],
    "CheckUpdates": true,
    "Lockout": 5,
    "NAT": true,
    "HelpMail": "[email protected]",
    "MaxSessionLifetimeMinutes": 2,
    "SessionInactivityTimeoutMinutes": 1,
    "ExternalAddress": "81.80.79.78",
    "DatabaseLocation": "devices.db",
    "Socket":"/tmp/wag.sock",
    "Webserver": {
        "Public": {
            "ListenAddress": "192.168.121.61:8080",
            "CertPath": "/etc/example/cert/path",
            "KeyPath": "/etc/ssl/private/somecert.key"
        },
        "Tunnel": {
            "Port": "8080"
        }
    },
    "ManagementUI": {
        "ListenAddress": "127.0.0.1:4433",
        "CertPath": "/etc/example/cert/path",
        "KeyPath": "/etc/ssl/private/somecert.key",
        "Enabled": true
    },
    "Authenticators": {
        "Issuer": "vpn.test",
        "DomainURL": "https://vpn.test:8080",
        "DefaultMethod":"webauthn",
        "Methods":["totp","webauthn", "oidc", "pam"],
        "OIDC": {
            "IssuerURL": "http://localhost:8080/",
            "ClientSecret": "<OMITTED>",
            "ClientID": "account",
            "GroupsClaimName": "groups"
        }
    },
    "Wireguard": {
        "DevName": "wg0",
        "ListenPort": 53230,
        "PrivateKey": "AN EXAMPLE KEY",
        "Address": "192.168.1.1/24",
        "MTU": 1420,
        "DNS": ["1.1.1.1"]
    },
    "Acls": {
        "Groups": {
            "group:nerds": [
                "daviv.test",
                "franky.someone",
                "any_username"
            ]
        },
        "Policies": {
            "*": {
                "Mfa": [
                     "10.0.0.2/32 8080/any"
                ],
                "Allow": [
                    "10.7.7.7/32",
                    "google.com"
                ]
            },
            "username": { 
                "Mfa": [
                     "someinternal.service 9100/tcp"
                ],
                "Allow":[ "10.0.0.1/32"]
            },
            "group:nerds": {
                "Mfa": [
                    "192.168.3.4/32",
                    "10.0.0.0/24",
                    "thing.internal 443/tcp icmp"
                ],
                "Allow": [
                    "192.168.3.5/32"
                ],
                "Deny": [
                    "10.0.0.5/32"
                 ]
            }
        }
    }
}

Defining ACL rules

The Policies section allows you to define what routes should be both captured by the VPN and what ports and protocols are allowed through Wag.

Rules use the subnet prefix length to determine which rule applies. The most specific match is use to determine the level of user access to a route.
For example:

 "*": {
                "Mfa": [
                     "10.0.0.0/16"
                ],
                "Allow": [
                    "10.0.1.1/32",
                ]
            },

Users will be able to access 10.0.1.1 without MFA as the match is more specific. This change occured in v6.0.0, previously MFA routes would always take precedence.

Additionally if multiple policies are defined for a single route they are composed with MFA rules taking preference.
For example:

 "*": {
            "Mfa": [
                  "10.0.0.0/16",
                  "10.0.1.1/32 22/tcp",
            ]
  },
 "group:users": {
            "Allow": [
                  "10.0.1.1/32 443/tcp",
            ]
 }

All users will be able to access 22/tcp on the 10.0.1.1/32 host, but users in the group:users will be able to access 443/tcp on that host as well, along with 22/tcp when authorized.

As of [version number, yet to be released] you can now define deny rules which will block access to a route.

Example:

 "*": {
            "Allow": [
                  "10.0.0.0/16",
                  "10.0.1.1/32 443/tcp",
            ]
  },
 "group:users": {
            "Deny": [
                  "10.0.1.1/32 443/tcp",
            ]
 }

Its important to note that the most specific rule effectively creates a new rule "bucket", so if you do something like:

"group:nerds": {
      "Allow": [
            "10.0.0.0/24 443/tcp"
      ],
      "Deny": [
            "10.0.0.5/32 22/tcp"
      ]
}

Your clients will not be able to access 10.0.0.5/32 443/tcp, as the only rule in the /32 "bucket" is a deny rule. You can solve this by adding the following:

"group:nerds": {
      "Allow": [
            "10.0.0.0/24 443/tcp"
            "10.0.0.5/32 22/tcp"
      ],
      "Deny": [
            "10.0.0.5/32 22/tcp"
      ]
}

or

"group:nerds": {
      "Allow": [
            "10.0.0.0/24 443/tcp"
      ],
      "Deny": [
            "10.0.0.0/24 22/tcp"
      ]
}

As then you're adding the deny rule to the /24 "bucket".

Additionally, It is possible to define what services a user can access by defining port and protocol rules.
Currently 3 types of port and protocol rules are supported:

Any

When no other rules are defined or the any keyword is used wag will allow all services and port combinations.

Example:

"1.1.1.1": Allows all ports and protocols to 1.1.1.1/32
"1.1.1.1 54/any": Allows both tcp and udp to 1.1.1.1/32

Single Service

Example:

192.168.1.1 22/tcp 53/udp: Fairly self explanatory, allows you to hit 22/tcp and 53/udp on a host
1.1.1.1 icmp: As icmp doesnt have ports really you dont need it either

Ranges

You can also define a range of ports with a protocol. wag requires that the lower port is first.

Example:

192.168.1.1 22-1024/tcp 23-53/any: Format is low port-high port/service

Limitations

  • Only supports clients with one AllowedIP, which is perfect for site to site, or client -> server based architecture.
  • IPv4 only.
  • Linux only
  • Very Modern kernel 5.9+ at least (>5.9 allows loops in ebpf and bpf_link)

Development

Custom templates

With the introduction of the MFATemplatesDirectory option, you can now specify a directory that contains template files for customising the MFA entry, registration and wireguard config file.
An example of all these files can be found in the embedded variants here: internal/webserver/resources/templates.

When the option is set, you must define all the files this guide is a brief description of what each file is:
interface.tmpl: The wireguard configuration file that is served to clients
oidc_error.html: If a users login to the oidc provider as some issue (i.e user isnt registered for the device)
prompt_mfa_totp.html: Page for taking TOTP code entry
prompt_mfa_webauthn.html: Page for webauthn entry
qrcode_registration.html: When a client registers with the ?type=mobile option set, shows a QR code for the wireguard app on android/ios to simply registration
register_mfa_totp.html: Registration for TOTP that should show a QR code
register_mfa_webauth.html: Page to do webauthn registration
register_mfa.html: If multiple MFA methods are registered this page is displayed giving the user an option of what method to use
success.html: This page is not a template, and is displayed when a user is successfully authed, or if they attempt to access the authorisation endpoint while being authorised

Testing

cd internal/router
sudo go test -v .

Sudo is required to load the eBPF program into the kernel.

Building a release

If you havent build the release docker image (used because it has a stable version of glibc) do the following:

cd release_builder
sudo docker build -t wag_builder .
cd ..

make docker

External contributions

If you're looking to add your own features, or bug fixes to wag (thank you!). Please make sure that you've written a test for your changes if possible.
There are a few _test.go files around that give example on how to do this.

Then open a pull request and we can discuss it there.

Donations and Support

If you like wag and use it to support your work flow, consider donating to the project. Your donations go directly towards the time and effort I put in, and the amount of support I can provide.

You can do this by either using the Support button on the side or the cryptocurrency wallets detailed below.

Monero (XMR):
8A8TRqsBKpMMabvt5RxMhCFWcuCSZqGV5L849XQndZB4bcbgkenH8KWJUXinYbF6ySGBznLsunrd1WA8YNPiejGp3FFfPND

Bitcoin (BTC):
bc1qm9e9sfrm7l7tnq982nrm6khnsfdlay07h0dxfr

wag's People

Contributors

bluecraank avatar jsmith-aura avatar marulitua avatar nhas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

wag's Issues

High Availability

This issue is to discuss the ins-and-outs of making a highly-available Wag.

In general, it would be nice to have the ability to have Wag running on 2 different servers, for a highly available configuration, so if one server fails (or needs to be shut down), then operation can continue.

Since Wag relies on in-memory maps, it would quite difficult to support to an active-active configuration, so instead, allowing for an active-passive (failover) configuration would be nice.

During a failover condition, users would have to re-auth, but I think that's fine.

The first problem I see is the SQLite database cannot be easily shared, so perhaps one of the first steps could be allowing for other databases (Postgres, MySQL..?)

I don't think it should be Wag's responsibility to direct traffic to the different instances. Instead, the administrator should use features of their networking equipment to perform failover, or use something like keepalived with Vrrp.

Feature request: session expiration based on src-ip/src-port

hi,

first, thanks for the project ... i like wireguard - and MFA on top of it ... great

do you think it would be a good idea to use the client-src-IP/port as a parameter to timeout a session?
means: if client-src-ip or client-src-port changes a re-authentication is requrired

the solution with a time-based session-timout ... hmm ...

XDP eBPF firewall blocks register_mfa?

Hi

I'm trying to setup WAG on my local intranet but the eBPF firewall blocks the connection by returning XDP_DROP.
This seems to be due to the Device having sessionExpiry = 0, as pasted below as output from kernel ring buffer.

Steps:

  1. Add debug logs
  • adapted the internal/router/xdp.c to print the checks done that result in XDP_DROP and also the values of each test branch.
  • rebuilt the WAG executable
  1. Test registration
  • enable port-forward in router to VM that hosts the WAG server, for <Webserver.Public.ListenAddress>
  • start WAG server
  • from WAG Host, open Webadmin and add a Registration_Token
  • from the Client device, open register_device url at http://:<Public.ListenAddress>/register_device?key=<Registration_Token>. A WireGuard .conf file gets downloaded.
  • configure the file in Client's WireGuard
  • start Client's Wireguard and activate the config
  • handshake works and Transfer begins for both received/sent which is OK
  • register a WAG_DOMAIN.TLD with LetsEncrypt SSL
  • open the https://<WAG_DOMAIN.TLD>:<Tunnel.Port>/
  • the browser hangs and there's below errors in kernel tracing:
> sudo cat  /sys/kernel/debug/tracing/trace_pipe

kworker/3:0-4612    [003] d.s1  8233.786962: bpf_trace_printk: conntrack(): *isAccountLocked || isTimedOut || current_device->
kworker/3:0-4612    [003] d.s1  8233.787763: bpf_trace_printk: current_device->sessionExpiry == 0
kworker/3:0-4612    [003] d.s1  8233.787770: bpf_trace_printk: currentTime > current_device->sessionExpiry
kworker/3:0-4612    [003] d.s1  8233.787771: bpf_trace_printk: xdp_wag_firewall() = XDP_DROP

Is there something I didn't understand from the Usage guides or is this actually a bug in WAG?
Thank you!

unable to start router: could not attach XDP program: bpf_link not supported

Hi All

When we start the wag service, we got this:
root@server015:/opt/wag# systemctl status wag
? wag.service - Wireguard Manager
Loaded: loaded (/etc/systemd/system/wag.service; enabled; vendor preset: enabled)
Active: activating (auto-restart) (Result: exit-code) since Thu 2023-04-20 03:50:04 PDT; 5s ago
Process: 345636 ExecStart=/opt/wag/wag start (code=exited, status=1/FAILURE)
Process: 345678 ExecStopPost=/opt/wag/wag cleanup (code=exited, status=1/FAILURE)
Main PID: 345636 (code=exited, status=1/FAILURE)
root@server015:/opt/wag#

root@server015:/opt/wag# journalctl -u wag
Apr 20 03:58:39 pa015 systemd[1]: Started Wireguard Manager.
Apr 20 03:58:39 pa015 wag[349530]: 2023/04/20 03:58:39 Removing Firewall rules...
Apr 20 03:58:39 pa015 wag[349530]: 2023/04/20 03:58:39 unable to start router: could not attach XDP program: bpf_link not supported (>
Apr 20 03:58:39 pa015 systemd[1]: wag.service: Main process exited, code=exited, status=1/FAILURE
Apr 20 03:58:39 pa015 wag[349572]: 2023/04/20 03:58:39 Cleaning up
Apr 20 03:58:39 pa015 wag[349572]: 2023/04/20 03:58:39 Removing Firewall rules...
Apr 20 03:58:39 pa015 wag[349572]: 2023/04/20 03:58:39 Unable to clean up firewall rules: running [/usr/sbin/iptables -t filter -D F>
Apr 20 03:58:39 pa015 wag[349572]: 2023/04/20 03:58:39 Unable to clean up firewall rules: running [/usr/sbin/iptables -t filter -D F>

We are running Wag and Wireguard on Ubuntu 20.04.1.
Thank you very much in anticipation.

Build Prerequisites v4.1.1-1-gf055b4c

Documentation requires update.

Building the latest version:

Error

$ make
BPF_CLANG=clang BPF_CFLAGS='-O2 -g -Wall -Werror' go generate ./...
Compiled /opt/wag/internal/router/bpf_bpfeb.o
Stripped /opt/wag/internal/router/bpf_bpfeb.o
Wrote /opt/wag/internal/router/bpf_bpfeb.go
Compiled /opt/wag/internal/router/bpf_bpfel.o
Stripped /opt/wag/internal/router/bpf_bpfel.o
Wrote /opt/wag/internal/router/bpf_bpfel.go
cd ui/src; npm install; gulp build
/bin/sh: npm: not found
/bin/sh: gulp: not found
make: *** [Makefile:21: .build_ui] Error 127

Fix

sudo apk add npm
sudo npm install --global gulp-cli

XdpWagFirewall error on sudo ./wag start

I did:

sudo -u wag git clone https://github.com/NHAS/wag.git
cd /home/wag/wag
sudo -u make OR sudo make both not working
sudo ./wag start

Make output

BPF_CLANG=clang BPF_CFLAGS='-O2 -g -Wall -Werror' go generate ./...
go: downloading golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde
go: downloading golang.zx2c4.com/wireguard v0.0.0-20230304142546-b6a68cf211aa
go: downloading github.com/NHAS/webauthn v0.0.0-20230305085302-c94263588cef
go: downloading github.com/mattn/go-sqlite3 v1.14.16
go: downloading golang.org/x/crypto v0.7.0
go: downloading github.com/cilium/ebpf v0.10.0
go: downloading github.com/coreos/go-iptables v0.6.0
go: downloading github.com/mdlayher/netlink v1.7.1
go: downloading golang.org/x/sys v0.6.0
go: downloading github.com/boombuler/barcode v1.0.1
go: downloading github.com/pquerna/otp v1.4.0
go: downloading github.com/zitadel/oidc v1.13.0
go: downloading github.com/josharian/native v1.1.0
go: downloading github.com/mdlayher/socket v0.4.0
go: downloading golang.org/x/net v0.8.0
go: downloading github.com/golang-jwt/jwt/v4 v4.5.0
go: downloading github.com/golang-jwt/jwt v3.2.2+incompatible
go: downloading github.com/google/go-tpm v0.3.3
go: downloading github.com/google/uuid v1.3.0
go: downloading github.com/mitchellh/mapstructure v1.5.0
go: downloading golang.org/x/oauth2 v0.6.0
go: downloading gopkg.in/square/go-jose.v2 v2.6.0
go: downloading github.com/gorilla/securecookie v1.1.1
go: downloading golang.org/x/text v0.8.0
go: downloading golang.org/x/sync v0.1.0
go: downloading github.com/mdlayher/genetlink v1.3.1
go: downloading github.com/go-webauthn/revoke v0.1.9
go: downloading github.com/fxamacker/cbor/v2 v2.4.0
go: downloading github.com/gorilla/schema v1.2.0
go: downloading github.com/x448/float16 v0.8.4
Compiled /home/wag/wag/internal/router/bpf_bpfel.o
Stripped /home/wag/wag/internal/router/bpf_bpfel.o
Wrote /home/wag/wag/internal/router/bpf_bpfel.go
Compiled /home/wag/wag/internal/router/bpf_bpfeb.o
Stripped /home/wag/wag/internal/router/bpf_bpfeb.o
Wrote /home/wag/wag/internal/router/bpf_bpfeb.go
cd ui/src; npm install; gulp build
npm WARN deprecated [email protected]: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated [email protected]: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated [email protected]: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated [email protected]: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated [email protected]: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
npm WARN deprecated [email protected]: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1

added 491 packages, and audited 492 packages in 15s

29 packages are looking for funding
  run `npm fund` for details

7 high severity vulnerabilities

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
[10:42:20] Using gulpfile ~/wag/ui/src/gulpfile.js
[10:42:20] Starting 'build'...
[10:42:20] Starting 'clean'...
[10:42:20] Finished 'clean' after 26 ms
[10:42:20] Starting 'modules'...
[10:42:20] Finished 'modules' after 145 ms
[10:42:20] Starting 'js'...
[10:42:20] Starting 'scss'...
[10:42:20] Finished 'js' after 364 ms
Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($spacer, 2) or calc($spacer / 2)

More info and automated migrator: https://sass-lang.com/d/slash-div

    โ•ท
302 โ”‚ $headings-margin-bottom:      $spacer / 2 !default;
    โ”‚                               ^^^^^^^^^^^
    โ•ต
    vendor/bootstrap/scss/_variables.scss 302:31  @import
    vendor/bootstrap/scss/bootstrap.scss 9:9      @import
    scss/sb-admin-2.scss 5:9                      root stylesheet

Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($input-padding-y, 2) or calc($input-padding-y / 2)

More info and automated migrator: https://sass-lang.com/d/slash-div

    โ•ท
498 โ”‚ $input-height-inner-quarter:            add($input-line-height * .25em, $input-padding-y / 2) !default;
    โ”‚                                                                         ^^^^^^^^^^^^^^^^^^^^
    โ•ต
    vendor/bootstrap/scss/_variables.scss 498:73  @import
    vendor/bootstrap/scss/bootstrap.scss 9:9      @import
    scss/sb-admin-2.scss 5:9                      root stylesheet

Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($custom-control-indicator-size, 2) or calc($custom-control-indicator-size / 2)

More info and automated migrator: https://sass-lang.com/d/slash-div

    โ•ท
568 โ”‚ $custom-switch-indicator-border-radius:         $custom-control-indicator-size / 2 !default;
    โ”‚                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    โ•ต
    vendor/bootstrap/scss/_variables.scss 568:49  @import
    vendor/bootstrap/scss/bootstrap.scss 9:9      @import
    scss/sb-admin-2.scss 5:9                      root stylesheet

Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($spacer, 2) or calc($spacer / 2)

More info and automated migrator: https://sass-lang.com/d/slash-div

    โ•ท
713 โ”‚ $nav-divider-margin-y:              $spacer / 2 !default;
    โ”‚                                     ^^^^^^^^^^^
    โ•ต
    vendor/bootstrap/scss/_variables.scss 713:37  @import
    vendor/bootstrap/scss/bootstrap.scss 9:9      @import
    scss/sb-admin-2.scss 5:9                      root stylesheet

Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($spacer, 2) or calc($spacer / 2)

More info and automated migrator: https://sass-lang.com/d/slash-div

    โ•ท
718 โ”‚ $navbar-padding-y:                  $spacer / 2 !default;
    โ”‚                                     ^^^^^^^^^^^
    โ•ต
    vendor/bootstrap/scss/_variables.scss 718:37  @import
    vendor/bootstrap/scss/bootstrap.scss 9:9      @import
    scss/sb-admin-2.scss 5:9                      root stylesheet

Warning: 64 repetitive deprecation warnings omitted.

[10:42:23] gulp-autoprefixer:
  autoprefixer: /home/wag/wag/ui/src/scss/sb-admin-2.css:3269:3: Replace color-adjust to print-color-adjust. The color-adjust shorthand is currently deprecated.
[10:42:23] Finished 'scss' after 3.24 s
[10:42:23] Starting 'css'...
[10:42:24] Finished 'css' after 676 ms
[10:42:24] Finished 'build' after 4.1 s
go build -ldflags="-X 'github.com/NHAS/wag/internal/config.Version=v5.1.1'"

Versions

WAG:
newest (5.1.1)

GO:
go version go1.20.2 linux/amd64

Clang:
Ubuntu clang version 14.0.0-1ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/11
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/11
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Candidate multilib: x32;@mx32
Selected multilib: .;@m64

Error

2023/03/10 10:43:38 can do migrations, backing up database to  devices.db.20230310104338.bak
2023/03/10 10:43:38 Running migration:  202206251953_inital.sql
2023/03/10 10:43:38 Running migration:  202210171955_rename_totp_devices_table.sql
2023/03/10 10:43:38 Running migration:  20221130174858_registration_update_device.sql
2023/03/10 10:43:38 Running migration:  20221130203322_multi_device.sql
2023/03/10 10:43:38 Running migration:  20221217161441_add_mfa_type.sql
2023/03/10 10:43:38 Running migration:  20221224115527_add_registration_groups.sql
2023/03/10 10:43:38 Running migration:  20230123215232_add_ui_users.sql
2023/03/10 10:43:38 Running migration:  20230211004046_preshared_key.sql
; int xdp_wag_firewall(struct xdp_md *ctx)
0: (b7) r2 = 0
; struct ip ip_info = {0};
1: (63) *(u32 *)(r10 -28) = r2
last_idx 1 first_idx 0
regs=4 stack=0 before 0: (b7) r2 = 0
2: (63) *(u32 *)(r10 -32) = r2
3: (63) *(u32 *)(r10 -36) = r2
4: (b7) r6 = 1
; void *data_end = (void *)(long)ctx->data_end;
5: (61) r2 = *(u32 *)(r1 +4)
; void *data = (void *)(long)ctx->data;
6: (61) r1 = *(u32 *)(r1 +0)
; if ((void *)(ip + 1) > data_end)
7: (bf) r3 = r1
8: (07) r3 += 20
; if ((void *)(ip + 1) > data_end)
9: (2d) if r3 > r2 goto pc+244
 R1_w=pkt(id=0,off=0,r=20,imm=0) R2_w=pkt_end(id=0,off=0,imm=0) R3_w=pkt(id=0,off=20,r=20,imm=0) R6_w=inv1 R10=fp0 fp-32=00000000 fp-40=0000????
; if (ip->version != 4)
10: (71) r3 = *(u8 *)(r1 +0)
; if (ip->version != 4)
11: (57) r3 &= 240
; if (ip->version != 4)
12: (55) if r3 != 0x40 goto pc+241
 R1_w=pkt(id=0,off=0,r=20,imm=0) R2_w=pkt_end(id=0,off=0,imm=0) R3_w=inv64 R6_w=inv1 R10=fp0 fp-32=00000000 fp-40=0000????
; ip_info->proto = ip->protocol;
13: (71) r3 = *(u8 *)(r1 +9)
14: (b7) r8 = 0
; ip_info->src_port = 0;
15: (6b) *(u16 *)(r10 -36) = r8
last_idx 15 first_idx 0
regs=100 stack=0 before 14: (b7) r8 = 0
; ip_info->proto = ip->protocol;
16: (63) *(u32 *)(r10 -24) = r3
; switch (ip->protocol)
17: (15) if r3 == 0x1 goto pc+11
 R1=pkt(id=0,off=0,r=20,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R6=inv1 R8=invP0 R10=fp0 fp-24=????mmmm fp-32=00000000 fp-40=0000????
18: (15) if r3 == 0x6 goto pc+18
 R1=pkt(id=0,off=0,r=20,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R6=inv1 R8=invP0 R10=fp0 fp-24=????mmmm fp-32=00000000 fp-40=0000????
19: (55) if r3 != 0x11 goto pc+31
 R1=pkt(id=0,off=0,r=20,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=inv17 R6=inv1 R8=invP0 R10=fp0 fp-24=????mmmm fp-32=00000000 fp-40=0000????
; struct udphdr *udph = (data + (ip->ihl * 4));
20: (71) r3 = *(u8 *)(r1 +0)
; struct udphdr *udph = (data + (ip->ihl * 4));
21: (67) r3 <<= 2
22: (57) r3 &= 60
; struct udphdr *udph = (data + (ip->ihl * 4));
23: (bf) r4 = r1
24: (0f) r4 += r3
last_idx 24 first_idx 17
regs=8 stack=0 before 23: (bf) r4 = r1
regs=8 stack=0 before 22: (57) r3 &= 60
regs=8 stack=0 before 21: (67) r3 <<= 2
regs=8 stack=0 before 20: (71) r3 = *(u8 *)(r1 +0)
; if (udph + 1 > (struct udphdr *)data_end)
25: (bf) r5 = r4
26: (07) r5 += 8
; if (udph + 1 > (struct udphdr *)data_end)
27: (2d) if r5 > r2 goto pc+226
 R1=pkt(id=0,off=0,r=20,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R4=pkt(id=1,off=0,r=8,umax_value=60,var_off=(0x0; 0x3c)) R5=pkt(id=1,off=8,r=8,umax_value=60,var_off=(0x0; 0x3c)) R6=inv1 R8=invP0 R10=fp0 fp-24=????mmmm fp-32=00000000 fp-40=0000????
28: (05) goto pc+16
; struct udphdr *udph = (data + (ip->ihl * 4));
45: (bf) r2 = r1
46: (0f) r2 += r3
;
47: (69) r8 = *(u16 *)(r2 +2)
invalid access to packet, off=2 size=2, R2(id=2,off=2,r=0)
R2 offset is outside of the packet
processed 32 insns (limit 1000000) max_states_per_insn 0 total_states 2 peak_states 2 mark_read 22023/03/10 10:43:38 Removing Firewall rules...
2023/03/10 10:43:38 unable to start router: loading objects: field XdpWagFirewall: program xdp_wag_firewall: load program: permission denied: invalid access to packet, off=2 size=2, R2(id=2,off=2,r=0): R2 offset is outside of the packet (68 line(s) omitted)

Feature Request: support for port based firewall

Hi

Thank you for a great product!

Would it be possible to extend wag to limit users & group by destanation port?

For example, I need to allow 'public' users only specitic destanation port "10.10.0.1:8080", but for MFA users allow a port range "10.10.0.1:2000-3000". As I discovered XDP is a very flexible, but I am a potato to implement this in C-code.

Allow internal devices to access wireguard client

Problem

So far everything is running, I only have the problem that, apart from the server, no other devices can ping WireGuard peers or generally no communication can be established

My solution

        err = ipt.Append("filter", "FORWARD", "-i", "ens160", "-o", "wg0", "-j", "ACCEPT")
        if err != nil {
                return err
        }

So i added this code in iptables.go before line 29 to allow incoming traffic from interface where everything else is connected to wg0 interface

General solution

There should be a way to allow this, but i do not know really how. How i solved it allows EVERYTHING from internal, thats may not be the best way

ACL Rule Mfa always has precedence over Allow?

Hi All

In OpenVPN, our clients are able to access each other using the VPN tunnel IP address. We are unable to do this with WAG.

10.125.0.0/16 is the VPN tunnel network. 10.125.0.1 is the VPN tunnel IP address of the WG interface of our WG "server".

The config below does not work because the Mfa takes precedence over the Allow. So 10.125.0.1 also requires MFA and therefore we cannot reach http://10.125.0.1:8080 to enter the MFA code.

            "group:users": {
                "Allow": [
                    "10.125.0.1/32 8080/any"
                ],
                "Mfa": [
                    "10.125.0.0/16",
                    "192.168.5.0/24",
                    "192.168.6.0/24"
                ]
            },

To make it work, we have to remove the "10.125.0.0/16" from the Mfa. The config below works:

            "group:users": {
                "Allow": [
                    "10.125.0.1/32 8080/any"
                ],
                "Mfa": [
                    "192.168.5.0/24",
                    "192.168.6.0/24"
                ]
            },

But we want to be able to reach all the other peers in the VPN tunnel network 10.125.0.0/16 like we can do with OpenVPN. We tried doing "Mfa": [ "10.125.0.0/16 1-8079/any 8081-10000/any"] but it didn't work.
"Mfa": ["10.125.0.1 1-8079/any 8081-10000/any"] also did not work.

Looks like there's no way to do this?

Except specifying all the peers IP addresses in 10.125.0.0/16 one by one except 10.125.0.1 (since "10.125.0.1 1-8079/any 8081-10000/any" does not work) ?

Thank you very much in anticipation.

Breaking changes v1.4.2

You made me work hard for this update :D

Needed to upgrade to go 1.18 from 1.17 as a module requires 1.18. This meant an upgrade from Alpine 3.15 to 3.16 to get go 1.18

Then the change in the config.json required the creation of a "Wireguard": {} stanza as per the new documented example_config.json.

A release notes file would be useful to prevent prolonged downtime when upgrading.

Leaves iptables rule after stopping

Very nice.

I'm just testing it out and picked one small issue. When stopping, it leaves one iptables rule behind. So next time you start you get another one, and another one, etc.

-A INPUT -i wg0 -p tcp -m tcp --dport 8080 -j ACCEPT
-A INPUT -i wg0 -p tcp -m tcp --dport 8080 -j ACCEPT

MFA port accessible without authentication

Hey there,

there is an issue we have come up with. The setup is the following:
wag runs on a system with the IP 192.168.1.2 and has the IP 10.1.2.1 for its WireGuard interface. The Tunnel listener is set to Port 443 for the authentication web UI and the 192.168.1.0/24 network is set as MFA only for everyone.

The problem is, after the initial WireGuard connection and without authentication Port 443 is accessible on 192.168.1.2 as well but shouldn't without authentication. When the authentication is done, 192.168.1.2 should be accessible with all ports but has still only port 443 reachable.

Hope you can help us there. Thanks a lot :)

package embed is not in GOROOT

I put this on a different system to test some more. Previously it was on Alpine Linux 3.15, now I put it on Debian 11

I'll confess to being a go novice.

$ go build                                 
router/bpf_bpfel.go:9:2: package embed is not in GOROOT (/usr/lib/go-1.15/src/embed)

I suspect it is a difference in the go package on the two environments.

$ doas apk add go
$ go version
go version go1.17.10 linux/amd64

Versus

$ sudo apt install golang
$ go version  
go version go1.15.15 linux/amd64

feat req: Interactive config generator

It would be nice for Wag to have a CLI command to generate a configuration file interactively.

For example

What is the public address your devices will connect to? 1.2.3.4:4321
What help email would you like displayed on the auth page? [email protected]
.. etc ..

flag provided but not defined: -config

When starting from a different directory, I'm unable to specify a path to the config.json.

$ /opt/wag/wag start --config ./config.json
flag provided but not defined: -config
Usage of start:
Error:  flag provided but not defined: -config
Usage of start:
  Run the wag server on the settings found in config.json

But the help details how:

$ /opt/wag/wag -h                          
			Wag
Adds 2fa and device enrolment to wireguard deployments.

Supported commands: start, cleanup, reload, registration, devices, firewall
All commands require:
  -config string
    Configuration file location (default "./config.json")

RAW routing mode

Hello!
I've set NAT to false and am trying to get WAG to route traffic to another host on the same LAN as the WAG server.
But all my attempts failed
Is this feature supported and what do I need to do to get it?
I saw the section with Limitations, but I don't quite understand if it fits this case

routes.go#L36 on make

//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf xdp.c -- -I headers

โ””โ”€# make
BPF_CLANG=clang BPF_CFLAGS='-O2 -g -Wall -Werror' go generate ./...
go: downloading golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220916014741-473347a5e6e3
go: downloading github.com/mattn/go-sqlite3 v1.14.15
go: downloading golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d
go: downloading github.com/pquerna/otp v1.3.0
go: downloading github.com/cilium/ebpf v0.9.3
go: downloading github.com/mdlayher/netlink v1.6.2
go: downloading github.com/coreos/go-iptables v0.6.0
go: downloading golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43
go: downloading golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
go: downloading github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc
go: downloading github.com/josharian/native v1.0.0
go: downloading github.com/mdlayher/socket v0.2.3
go: downloading golang.org/x/net v0.0.0-20221014081412-f15817d10f9b
go: downloading golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7
go: downloading github.com/mdlayher/genetlink v1.2.0
Error: exec: "llvm-strip": executable file not found in $PATH
exit status 1
router/routes.go:36: running "go": exit status 1
make: *** [Makefile:12: .generate_ebpf] Error 1

//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf xdp.c -- -I headers

it is wrong to attack the two // but just detach them and the make continues.
// go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf xdp.c -- -I headers

bye bye

OIDC issue

I have a second problem, I tried to set up oidc
I added an oidc to Authenticators Methods, received data from Google API and wrote down the necessary:

"DomainURL": "https://my domain",
         "OIDC": {
             "IssuerURL": "https://accounts.google.com",
             "ClientSecret": "secret",
             "ClientID": "client ID",
             "GroupsClaimName": "groups"

In the Google management console, I specified Authorized redirect URIs for my domain (https://mydomain/authorise/oidc)
Also in the config I specified "accounts.google.com" in the allow section so that it would be available during the mfa

But when i choose SSO and choose my google account, then I get
https://mydomain/authorise/oidc?state=some key
ERR_CONNECTION_REFUSED

Could you please tell me what I'm doing wrong?
I also read a lot of documents about oidc but I can't understand what is the problem here

Need a little help with setup (as a user)

I tried your package (binary) and it seems to work i.e. webui (admin) opens, I can add devices and I get the wireguard config via curl, and the remote peer connects.

But I fail to understand how to enter MFA.

In the docs is written:

Entering MFA

"To authenticate the user should browse to the servers vpn address, in the example, case 192.168.1.1:8080, where they will be prompted for their 2fa code.
The configuration file specifies how long a session can live for, before expiring."

I have no idea to WHICH server vpn address to call: is it the external IP VPN address or internal (vpn) one ?

I get a 404/not found error in http://externalipaddress:8080 and a SSL error with https://externalvnpaddress:8080

Management interface works.

There is a working example...somewhere ? Docs are quite confusing on many subjects.

Thanks a lot.

Allow users to add multiple MFA devices

Users should be able to add multiple MFA devices so they arent immediately locked out on MFA device loss.

  • Should be limitable by configuration (i.e users should be able to have 1 to n MFA options)
  • Needs UI page

Currently the only way to do this is by adding another wireguard device, which is not ideal for single user deployments.

Roaming Users

If a user is using 3rd party wifi/4G etc. when they roam between points and get a new connection they will be seen as a new connection. This will cause a need to revisit the OTP page to reauth. I have a few users who see this as an issue.

Is there any thought you have toward maintaining authentication between roaming changes?

Invalidate 2fa token after first use

Currently a 2fa TOTP code can be used as many times as a user wants within the 30 second window it is valid.

This may allow a malicious actor who can somehow capture one valid 2fa code to reauthenticate during this time.

So we need to invalidate the token once it is used once.

Change: DNS

It would be very useful to include the DNS directive in the users config.

In my case, I add the DNS into the wg0.conf before giving it to the user. In the ACL's I have a policy that allows the wildcard "*" to access the DNS servers IP Address. The DNS server has a record for otp. After a user connects using WireGuard they can then visit http://otp to authenticate.

config.json

    "Policies": {
      "*": {
        "Allow": [
          "10.0.6.254"
        ]
      },

wg0.conf

[Interface]
PrivateKey = SuperSecretKey
DNS = 10.0.6.254
Address = 192.168.4.4

Feature request: support authentication using an oauth2 client

Hi

Thank you for a great project, it is really useful.

Would it be possible for to extend wag to support user authentication using OpenID Connect / oauth 2.0 protocol? This would add the benefit of both simplifying the user managment and allow for a rich set of MFA solutions in addtion to supporting single sign-on from different providers. Authentication could be implemented using locally hosted services, e.g. by using implementations such as keycloak, or provided by trusted third parties for example google or github?

https://github.com/coreos/go-oidc
https://pkg.go.dev/golang.org/x/oauth2#section-readme

examples:
https://fusionauth.io/blog/2020/10/22/securing-a-golang-app-with-oauth
https://medium.com/@pliutau/getting-started-with-oauth2-in-go-2c9fae55d187

Make status endpoint

It would be handy for people designing things that autodetect when the VPN has de-authenticated to have an easy way of getting that information.

/status would work perfectly and also be open for sharing more details about the connection

Version returns UNKNOWN

After upgrading/pulling the latest version, when using the version option, it returns UNKNOWN

$ sudo ./wag version                   
UNKNOWN

Other than that, it appears to behave as previously.

Possibility to customize MFA Portal

At the moment, i have to download source and customize template files.

Maybe it is possible, that the compiled version looks for a folder where templates are in

License missing

Hello,
I noticed that no license is shown for this project, is this done intentionally?

WAG 2.0.0 base installation with glibc

I'm trying to create a 2.0.0 installation using Alpine or Debian, and I am struggling with the prerequisites. In particular glibc-2.34+.

Can I ask what base OS you were using to instal WAG?

No such file or directory

Edited config.json and added an IP address to a policy - 10.0.4.125/32 then tried to use reload.

            "group:infrastructure": {
                "Mfa": [
                    "10.0.4.24/32",
                    "10.0.4.125/32"
                ]
            },
sudo ./wag reload
2022/09/08 18:59:10 Unable to reload config:  Unable to load configuration file from : open : no such file or directory

Stop and start wag and if fires up as it should with the new rule.

Have to say I'm rather impressed by this so far. I was expecting it to add in lots of iptables rules that I could see happening, but I see it uses xdp ebpf - which must be where the cleverness hides.

If you have a mind for future expansion, I'd consider further authentication modules, maybe as plugins. LDAP, OpenIDC, maybe SAML, even a simple database auth.

Keep up the excellent work

SaveConfig is not enough

Need to make it so that when each peer is added/removed that the change is synced to the disk.

Whether to operate wireguard with routing or natting should be adjustable

iptables.go line 39

	err = ipt.Append("nat", "POSTROUTING", "-s", config.Values().Wireguard.Range.String(), "-j", "MASQUERADE")
	if err != nil {
		return err
	}

Me again,

it would be great if you could set whether the traffic should be routed or natted, since routing can later be used to clearly identify which request comes from which client

example config.json

DEFAULT: false

"routing": "false"

If routing is true, just skip that code

Hope it is understandable.

[Pre Release Bug] Hot upgrading + wag managing wg device breaks hot reloading

The wag wireguard endpoint watcher mechanism detects that the peers have changed from <nil> to a value, this causes them to be de-authenticated kind of defeating the point of hot upgrading.

This can be solved up adding a field to the database table Totp that records the last endpoint and sets it on device startup.

Config Generated Wrong DNS

$ sudo ./wag version                                       
remote
Version: v4.1.1-1-gf055b4c
Hash: 853da9fd51248b4cb68c9418b6e3fc871b7dad492521b5b7bb02689c14d04633

I just registered a new user, and it generated the config for me.

[Interface]
PrivateKey = SuperSecretKey
DNS = 10.10.6.254/32
Address = 192.168.254.27

[Peer]
Endpoint =  82.123.123.123:51821
PresharedKey = SuperSecretKey
PublicKey = SecretKey
AllowedIPs = ...
PersistentKeepAlive = 10

I wasn't paying attention, and then wondered why it never used resolvd and I could not do any DNS lookups.

It stuck a bogus /32 onto the DNS entry. Removed this and DNS now works.

Policies on expiration

Hey there! I came across this project and it fits my goals almost to a T for what I am looking for! I just had one question (hoping this is already how this works and not additional features)

I aim to have custom expiration based on the policy / ip/port being connected to. This is to allow say, VPNing in to access my email server to require MFA each time, but VPNing in to route to my diagram software to only need it once a month.

I do not believe this is currently possible, but wanted to check!

Add gen-config

Wag should be able to interactively generate its own config with wag gen-config

ManagementUI over TLS

Even with Certpath and KeyPath management UI runs without TLS.

    "ManagementUI": {
        "ListenAddress": "10.0.0.78:8443",
        "Enabled": true,
        "CertPath": "/etc/letsencrypt/live/domain.tld/fullchain.pem",
        "KeyPath": "/etc/letsencrypt/live/domain.tld/privkey.pem"
    },

Evidence

$ curl https://10.0.0.78:8443
curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number

$ curl http://10.0.0.78:8443 
<a href="/login">Temporary Redirect</a>.

PS. Nice job on the web gui ๐Ÿ‘

Issues with acls/policies and ssh session connections (mtu)

Hi, is it possible to have a network map of the example you published? I can't understand the rules and how it handles the rules after I've authenticated. It would seem that it works only for internal networks and not through public ip and therefore wireguard input from public ip. Thank you

Overwrite ips which should be routed in wireguard config

Your current version takes all ips which the client has to access and put them into AllowedIPs. It would be nice to overwrite them. So e.g instead of:

  • 10.10.10.32
  • 10.9.9.5
  • 10.20.30.40 and many more in same range

Simply 10.0.0.0/8 if needed

e.g ConfigKey OverwriteAllowedIPs= 10.0.0.0/8, 192.168.0.0/16

I hope its understandable

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.