- Go 94.4%
- Shell 4.6%
- Makefile 1%
Ajout d'une subcommand export qui permet d'exporter les informations du serveur Vpigo provenant de la db et de la config sous la forme d'une config Wireguard. Une option --output est disponible pour choisir d'avoir l'export dans un fichier au lieu du stdout. Correctifs et changements mineurs. Reviewed-on: #6 Reviewed-by: Valentin Doreau <v.doreau@e-durable.ch> |
||
|---|---|---|
| .forgejo/workflows | ||
| cmd | ||
| deb | ||
| doc | ||
| posting | ||
| .gitignore | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| Makefile | ||
| README.md | ||
Vpigo
Vpigo is an API written in Go(1.26.1) that expose some endpoints that allow manage Wireguard peers on the server. Peers information are keep in a SQLite database, client private key is stored but encrypt with AES-256-GCM.
Vpigo needs Wireguard installed and must be run as root to manipulate Wireguard interface.
Endpoints
| endpoint | type | HTTP Code | result | note |
|---|---|---|---|---|
| /create/{vpn_id} | POST | 201,400,409,500 | wg config | Return the client configuration in plaintext format |
| /delete/{vpn_id} | DELETE | 204,400,404,500 | none | |
| /enable/{vpn_id} | PATCH | 204,400,404,500 | none | |
| /disable/{vpn_id} | PATCH | 204,400,404,500 | none | |
| /config/{vpn_id} | GET | 200,400,404,500 | wg config | Return the client configuration in plaintext format |
API Configuration
The configuration file is located at /etc/vpigo/vpigo.json.
All keys are required.
| key | type | description |
|---|---|---|
| aes_256_secret_key | base64 | A 32 bytes encoded base64 string to encode the Wireguard client private key in the database. |
| auth_token | str | Token that will be used to authenticate with the API. |
| database_path | filepath | (Optional) Path to the SQLite database file. Default at /var/lib/vpigo/clients.db |
| endpoint | fqdn|ip | Endpoint that peers will use to connect to the Wireguard server. |
| listening_addr | hostname _port | Address that the API will listen on. |
| log_level | str | Define log level, case insensitive. Debug|Info|Warn|Error |
| network_ipv6 | cidrv6 | Network that the API will use to generate server and peers IPs. |
| server_public_key | base64 | Wireguard server public key. |
| wireguard_port | port | Port that the Wireguard server will listen on. |
For more details on the type used refer to the Go validator package documentation
Key Rotation
To make a rotation of the AES key, you need to stop the program, then execute the following command :
vpigo --rotate-aes-key "New32BytesKey"
If no error occurs, replace the old key in the configuration file by the new one and start the program.
Example
Example of configuration file :
{
"log_level":"debug",
"auth_token" : "supertoken",
"aes_256_secret_key":"QkJCQkxDTnEzUEFENlZzWFlMPVlGQWFDaVlxbEhxSUE=",
"listening_addr":":8080",
"network_ipv6":"2a0d:d9c4:c4:d::/96",
"endpoint":"vpn.swdn.ch.recycled.cloud",
"wireguard_port":51820,
"server_public_key_path": "/etc/wireguard/public_key",
"database_path":"db.db"
}
Technical Choices
CLI
I chose not to use a third-party package because it was not worth it for the current usage, the standard flag package is enough on its own. The downside is that I have to write the output of --help by myself.
Configuration
For the file format, I chose json because it is well integrated in Go. I just have to write flags to the configuration structure and I can map to it with a few lines of code.
To easily check fields that are loaded from the json file, I use Validator. It allows me to write validation flags in the configuration structure that avoid to manually verifying each field and there are a lots of custom types like: filepath,cidrv6 or hostname_port.
ORM
I chose to use an ORM because it allows me to easily manipulate the database using Go structs. This helps me minimize my interaction with raw SQL and results in more readable code. The ORM I chose is GORM because it is mature, widely used, and well-documented. It also has Prometheus metrics that can be useful to us.
Important: because I use GORM SQLite driver, which use CGO enabled package, you are required to have a gcc compiler present within your path.
WireGuard
To generate WireGuard private key, the easiest way is to use the Go implementation of WireGuard. Then Vpigo stores encrypted peers private key in the database. More details in cmd/wg/wireguard.go for the private key generation and in cmd/db/aes.go for the private key encryption in SQLite.
Private Key Encryption
The algorithm used to encrypt keys is AES-GCM 256 because it is the first one that came to my mind. It's not the most modern, but it remains efficient and quantum proof.
Error Handling
The philosophy of Go encourages errors to be returned as a value, which is very verbose. Vpigo error management is then based on a Panic-based Error Handling. Since Vpigo is primarily a web server and each request is a goroutine, an error middleware has been implemented that incorporates recover(), as well as an error structure AppError and a function Check(). All this allows us to use panic() in the functions called by the handlers, ensuring that a proper HTTP error is returned and avoiding the need to escalate errors through the functions.
