Skip to content
This repository has been archived by the owner on Oct 3, 2024. It is now read-only.

Added vyatta config tree structure #2

Merged
merged 1 commit into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ tokio = { version = "1.26", default-features = false, features = ["macros", "rt-
tokio-tungstenite = { version = "0.18", default-features = false, features = ["handshake"] }
tracing-subscriber = { version = "0.3", features = ["tracing-log"] }
clap = { version = "4.1", features = ["derive", "env"] }
tracing = "0.1"
tracing = { version = "0.1", features = [] }
axum = { version = "0.6.16", features = ["macros"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Expand All @@ -23,8 +23,9 @@ tower-http = { version = "0.4", features = ["sensitive-headers", "trace", "valid

[package.metadata.deb]
maintainer-scripts = "debian/"
systemd-units = { enable = true }
systemd-units = { enable = false }
assets = [
["target/x86_64-unknown-linux-musl/release/wpm-api-vyos", "/usr/bin/wpm-api-vyos", "755"],
# TODO add vyos config tree structure, see https://github.com/pkgs-hub/vyatta-web
["target/x86_64-unknown-linux-musl/release/wpm-api-vyos", "/opt/vyatta-wpm-api/wpm-api-vyos", "755"],
["debian/etc/default/wpm-api", "/etc/default/wpm-api", "640"],
["debian/opt/**/*", "/opt/", "644"],
]
10 changes: 2 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Wireguard Peer Manager
# Wireguard Peer Manager: VyOS API

Wireguard Peer Manager is used for managing Road Warrior VPN endpoints and consists of two components. Users and
administrators utilize the Django app for graphical management of Wireguard peers. It communicates with the router's
REST API interfaces (for vyos this project) to apply the Wireguard configuration.
REST API (for VyOS [this project](https://github.com/secshellnet/wpm-api-vyos)) to apply the Wireguard configuration.

After the user logs in, they can easily create new Wireguard peers (each device should have its own peer to enable
simultaneous connections) and view or delete the Wireguard configuration. Due to this abstraction layer, end-users don't
Expand All @@ -19,12 +19,6 @@ changes to green (usually taking no longer than 30 seconds), the peer is usable.
All clients connecting to the same router use the same Wireguard endpoint (in our case, the interface `wg100`),
differing only in the IPv4 and IPv6 addresses used within the tunnel.

## Build
VyOS has some old weird libc, so we build with musl instead.
```shell
cargo build --target x86_64-unknown-linux-musl --release
```

## Specification
- HTTP Authorization using Bearer Access Tokens.

Expand Down
10 changes: 10 additions & 0 deletions debian/DEBIAN/postinst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# TODO adjust permissions of assets (doesn't work for whatever reason)
for path in /opt/vyatta-wpm-api/ /opt/vyatta/share/vyatta-cfg/templates/service/wpm-api/ \
/opt/vyatta/share/vyatta-op/templates/{restart,show,show/log}/wpm-api/; do
find ${path} -type d -exec chmod 0755 {} \;
find ${path} -type f -exec chmod 0644 {} \;
done

chmod +x /opt/vyatta-wpm-api/config.py
Empty file added debian/etc/default/wpm-api
Empty file.
11 changes: 11 additions & 0 deletions debian/opt/vyatta-wpm-api/config.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% for key, value in data.items() %}
{%- if key == 'listen-address' -%}
WPM_LISTEN_ADDR={{ value }}
{%- endif %}
{%- if key == 'interface' -%}
WPM_INTERFACE={{ value }}
{%- endif %}
{%- if key == 'api-token' -%}
WPM_SECRET={{ value }}
{%- endif %}
{% endfor %}
79 changes: 79 additions & 0 deletions debian/opt/vyatta-wpm-api/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env python3
import os

from sys import exit

from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configverify import verify_vrf
from vyos.util import call
from vyos.template import render
from vyos import ConfigError
from vyos import airbag
from jinja2 import Template


airbag.enable()

config_file = r'/etc/default/wpm-api'

def get_config(config=None):
if config:
conf = config
else:
conf = Config()
base = ['service', 'wpm-api']
if not conf.exists(base):
return None

wpm_api = conf.get_config_dict(base, get_first_key=True)

return wpm_api

def verify(wpm_api):
if wpm_api is None:
return None

verify_vrf(wpm_api)
return None

def generate(wpm_api):
if wpm_api is None:
if os.path.isfile(config_file):
os.unlink(config_file)
return None

# merge web/listen-address with subelement web/listen-address/port
# {'web': {'listen-address': {'0.0.0.0': {'port': '8080'}}}
if 'listen-address' in wpm_api:
address = list(wpm_api['listen-address'].keys())[0]
port = wpm_api['listen-address'][address].get("port", 8080)
wpm_api['listen-address'] = f"{address}:{port}"

with open('/opt/vyatta-wpm-api/config.j2', 'r') as tmpl, open(config_file, 'w') as out:
template = Template(tmpl.read()).render(data=wpm_api)
out.write(template)

# Reload systemd manager configuration
call('systemctl daemon-reload')

return None

def apply(wpm_api):
if wpm_api is None:
# wpm_api is removed in the commit
call('systemctl stop wpm-api.service')
return None

call('systemctl restart wpm-api.service')
return None

if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
exit(1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type: txt
help: API Token, which is required to manage peers with wpm api.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type: txt
help: Wireguard interface to manage peers on.
allowed: sh -c "${vyos_completion_dir}/list_interfaces.py -t wireguard"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
tag:
type: txt
help: Address on which to expose wpm api.
val_help: ipv4; IPv4 address to expose wpm api
val_help: ipv6; IPv6 address to expose wpm api
allowed: sh -c "${vyos_completion_dir}/list_local_ips.sh --both"
syntax:expression: exec "${vyos_libexec_dir}/validate-value --exec \"${vyos_validators_dir}/ipv4-address \" --exec \"${vyos_validators_dir}/ipv6-address \" --value \'$VAR(@)\'"; "Invalid value"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type: txt
help: Port for wpm-api service (default: '8080')
val_help: u32:1-65535; Numeric IP port
syntax:expression: exec "${vyos_libexec_dir}/validate-value --exec \"${vyos_validators_dir}/numeric --range 1-65535\" --value \'$VAR(@)\'"; "Port number must be in range 1 to 65535"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
help: Wireguard Peer Manager API configuration
end: sudo sh -c "${vyshim} /opt/vyatta-wpm-api/config.py"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
help: Restart wpm-api
run: sudo systemctl restart wpm-api
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
help: Show wpm-api logs
run: journalctl -u wpm-api | less
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
help: Show wpm-api status
run: systemctl status wpm-api
6 changes: 2 additions & 4 deletions debian/service
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
[Unit]
Description=Wireguard Peer Manager API for VyOS.
After=network.target

[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/wpm-api-vyos
EnvironmentFile=/etc/default/wpm-api
ExecStart=/opt/vyatta-wpm-api/wpm-api-vyos

[Install]
WantedBy=multi-user.target
9 changes: 7 additions & 2 deletions src/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use axum::{
extract::{State, Json, Path}
};
use serde::Serialize;
use tracing::info;

use crate::schemas::{ApiResponse, AddPeerSchema, ConfigState, StatusResponse};
use crate::utils::validate_key;
Expand All @@ -30,6 +31,8 @@ pub async fn get_peer(
State(config): State<ConfigState>,
Path(identifier): Path<String>
) -> Result<Json<ApiReturnTypes>, StatusCode> {
info!("? {}", identifier);

// get existing allowed ips for this identifier from current vyatta configuration
// vyatta config systems used transactions, so if one setting is there everything is there
let vyatta_config = format!("\
Expand Down Expand Up @@ -90,9 +93,11 @@ pub async fn add_peer(
}
}

// todo sanitize addresses, user identifier, peer identifier

// generate the identifier, which is the user identifier + peer identifier
let identifier = format!("{}-{}", peer_data.user_identifier, peer_data.peer_identifier);
print!("+ {}", identifier);
info!("+ {}", identifier);

// VyOS allows the label for a peer to have 100 characters.
if identifier.to_string().len() > 100 {
Expand Down Expand Up @@ -169,7 +174,7 @@ pub async fn delete_peer(
State(config): State<ConfigState>,
Path(identifier): Path<String>
) -> Result<Json<ApiReturnTypes>, StatusCode> {
print!("- {}", identifier);
info!("- {}", identifier);

// get existing allowed ips for this identifier from current vyatta configuration
let vyatta_config = format!("\
Expand Down
Loading