Amnezia VPN client manager written in Rust on top of the public [`cot`](https://cot.rs) framework.
The app uses SQLite as the source of truth, authenticates users through OIDC/SSO, renders AmneziaWG client peers into a Kubernetes Secret, and avoids updating that Secret when the rendered content is byte-for-byte identical.
Open `http://localhost:8000/admin/setup` to create the first local admin account.
## Docker
The image is built by GitHub Actions and published to Docker Hub as
`ultradesu/amnezia-fellow`.
Required repository secrets:
-`DOCKERHUB_USERNAME`
-`DOCKERHUB_TOKEN`
Publishing runs for version tags matching `v*.*.*`. A tag like `v0.1.0` pushes:
-`ultradesu/amnezia-fellow:v0.1.0`
-`ultradesu/amnezia-fellow:0.1.0`
-`ultradesu/amnezia-fellow:latest`
Local image build:
```bash
docker build -t amnezia-fellow .
docker run --rm -p 8000:8000 -v "$PWD/data:/data" amnezia-fellow
```
## Roles
There are two roles:
-`admin`: full access, sees all client configs.
-`client`: sees and manages only their own configs.
OIDC provisioning is deny-by-default:
- users in `AMNEZIA_FELLOW_OIDC_ADMIN_GROUPS` become `admin`;
- users in `AMNEZIA_FELLOW_OIDC_CLIENT_GROUPS` become `client`;
- users outside both group lists cannot sign in.
The OIDC groups claim is expected to be `groups`.
## VPN Data Model
SQLite stores all client data needed to restore configs:
- owner user id
- display name
- assigned IPv4 address
- public key
- private key
- enabled flag
- created/updated timestamps
The Kubernetes Secret is derived from the database. Active clients are rendered into one configured Secret key, `peers.conf` by default.
## Kubernetes Sync
The app is intended to run inside Kubernetes with a ServiceAccount and RBAC that can read and update Secrets and list Pods in the Amnezia namespace.
It reads:
- server public key from `AMNEZIA_FELLOW_K8S_SERVER_SECRET`, key `server-public-key`;
- node endpoints from `AMNEZIA_FELLOW_K8S_ENDPOINTS_SECRET`; Secret data keys are used as Amnezia server names in generated `vpn://` links;
- AmneziaWG pods selected by `app=amneziawg` for config rollout status;
- writes rendered client peers to `AMNEZIA_FELLOW_K8S_CLIENTS_SECRET`.
It does not modify the server Secret. Argo/ExternalSecrets can keep managing `amneziawg-server`, while amnezia-fellow owns only the client Secret content.
## UI
The main user interface is `/configs`. It is an Alpine.js reactive page backed by JSON API endpoints:
- clients and admins use the same page;
- the backend filters data by role;
- admins get an extra manual Secret sync action.
- clients and admins see AmneziaWG pod rollout status and uptime.
## Environment Variables
All settings use `AMNEZIA_FELLOW_` prefix. Priority is: