🌐 getbor.dev · 📦 GitHub · 📖 Contributing · 🔒 Security
Bor is an open-source policy management system for Linux desktops. A central server distributes configuration policies to enrolled Linux endpoints in real-time. A lightweight Go agent daemon on each machine receives policies over an encrypted gRPC stream and enforces them locally.
Currently enforced policies:
- Firefox ESR — system-wide
policies.json(RPM/DEB and Flatpak) - Google Chrome / Chromium — managed JSON in
/etc/opt/chrome/and/etc/chromium/(including Flatpak) - KDE Plasma — KDE Kiosk (
kconfigfiles under/etc/xdg/, KCM module restrictions)
┌─────────────────────┐ gRPC stream / mTLS ┌──────────────────────┐
│ Bor Agent │ ◄────── port 8444 ────────► │ Bor Server │
│ (Go daemon, root) │ │ Go + PatternFly UI │
└─────────────────────┘ gRPC enrollment / TLS └──────────┬───────────┘
• One-time token enrollment ◄── port 8443 ──► │ SQL
• mTLS client certificate auth ▼
• Applies Firefox / Chrome / ┌──────────────────────────────┐
KDE Kiosk policies │ PostgreSQL │
• Reports compliance │ policies · nodes · users │
• Desktop notifications │ bindings · RBAC · audit log │
└──────────────────────────────┘
The server runs two HTTPS listeners with different security postures:
| Port | Purpose | TLS | Client cert |
|---|---|---|---|
| 8443 | Admin UI (REST) + enrollment gRPC | TLS 1.2+ | Optional |
| 8444 | Agent policy stream + cert renewal | TLS 1.3, mTLS | Mandatory |
REST and enrollment gRPC share port 8443, routed by Content-Type:
application/grpc* → gRPC handler, everything else → REST API + embedded
PatternFly web UI.
- Centralised web UI — PatternFly 5 dashboard for policies, nodes, and bindings
- Real-time distribution — gRPC server-side streaming; agents receive changes instantly
- Secure by design — mTLS certificate authentication for every agent; internal CA auto-generated on first run; FIPS 140-3 validated crypto module
- Easy enrollment — one-time token generated in the UI; agent bootstraps its own certificate
- Automatic renewal — agent certificates (90-day) are renewed automatically before expiry; no operator action required
- Delta sync — monotonic revision counter with ring buffer; reconnecting agents receive only what changed
- Node Groups — many-to-many assignment of nodes to policy groups
- RBAC — built-in roles (Super Admin, Org Admin, Policy Editor, …) with granular per-resource permissions
- Audit log — every API action recorded with user, IP, and timestamp
- Tamper protection — file watcher detects and restores managed files that are modified outside Bor
- LDAP/AD integration — optional, enabled via environment variables
- HSM support — optional PKCS#11 integration stores the CA private key in a hardware security module
- Linux-native packaging — deb, rpm, apk, Arch Linux packages via nfpm
| Component | Requirement |
|---|---|
| Server host | Podman / Docker + podman-compose / docker-compose |
| Agent host | Linux x86_64 or arm64 |
| Building from source | Go 1.24+, Node.js 18+, Make |
git clone https://github.com/VuteTech/Bor.git
cd Bor
cp .env.example .env
$EDITOR .env # set DB_PASSWORD, JWT_SECRET, BOR_ADMIN_PASSWORD at minimum
podman-compose up -dThe server starts on https://localhost:8443 (UI + enrollment) and
https://localhost:8444 (agent mTLS). On first boot it auto-generates an
internal CA (ECDSA P-384) and a server TLS certificate (ECDSA P-256) under
/var/lib/bor/pki/.
Log in at https://localhost:8443 with the admin credentials set in .env.
Every Bor instance ships the agent packages for all supported platforms and
serves them itself: download links, apt/dnf/zypper repositories and a
Deploy agent wizard in the web UI (the download icon in the masthead, or
the button on the Nodes page). The wizard produces a single copy-paste
script that trusts the server CA, sets up the signed repository, installs
the agent, enrolls it with a one-time token and starts the service — managed
nodes never need internet access. A static version of the instructions is
served by the instance itself at https://your-hostname:8443/agent/.
See docs/agent-packages.md for the per-platform details, repository signing and key rotation, and air-gap notes. Packages can also be downloaded manually from getbor.dev/download.
All build targets are in the Makefile. Run make help to list them.
make install-depsThis installs protoc-gen-go, protoc-gen-go-grpc, golangci-lint, nfpm,
and the TypeScript proto plugin via npm. You must have protoc and Node.js
available separately.
All Go builds use GOFIPS140=v1.0.0, which embeds the FIPS 140-3 validated
crypto module snapshot (CAVP certificate A6650) regardless of the host
toolchain.
make server # → server/server (FIPS 140-3)
make agent # → agent/bor-agent (FIPS 140-3)
make frontend # → embedded into the server binary (run before make server)
make proto # regenerate Go + TypeScript from proto/ definitionsBuild everything in the correct order:
make frontend && make server && make agentTo store the CA private key in a hardware security module, build with the
pkcs11 tag. This requires CGO and the crypto11 dependency:
cd server && go get github.com/ThalesIgnite/crypto11
cd ..
make server-pkcs11 # → server/server (FIPS 140-3 + PKCS#11)See docs/SECURITY.md for the full configuration guide and a SoftHSMv2 example.
The build flag embeds the validated module. To additionally restrict the running process to FIPS-approved algorithms only (removes X25519, enforces P-256/P-384):
GODEBUG=fips140=on ./server/serverAdd Environment=GODEBUG=fips140=on to the systemd unit override for
production deployments.
# Start PostgreSQL
make dev
# Run the server (reads .env automatically via go run)
make run-server
# In a separate terminal — run the agent against the local server
sudo ./agent/bor-agent --config agent/config.yaml.exampleBuild distribution packages for all formats:
make packages # deb + rpm + apk + archlinux, version 0.1.0
make packages VERSION=1.2.3 # specify version
make packages VERSION=1.2.3 ARCH=arm64 # cross-arch
make packages-agent VERSION=1.2.3 # agent packages only
make packages-server VERSION=1.2.3 # server packages onlyPackages are written to builds/. Requires nfpm (make install-deps).
make docker # builds bor-server:latest with podmanmake test# all tests (server + agent)
make test-server # server tests only
make test-agent # agent tests only
make coverage # HTML coverage reports → server/coverage.html, agent/coverage.htmlRun a single test by name:
cd server && go test -v -run TestPolicyService ./internal/services/...
cd agent && go test -v -run TestMergeKConfig ./internal/policy/...The server reads configuration from a YAML file (default /etc/bor/server.yaml,
override with BOR_CONFIG) and environment variables. Environment variables
always take precedence. Copy .env.example to .env for local development,
or use /etc/bor/server.env for production (loaded by the systemd unit).
A full annotated YAML reference is in server/server.yaml.example.
| Variable | Description |
|---|---|
DB_PASSWORD | PostgreSQL password |
JWT_SECRET | JWT signing secret — use at least 32 random bytes |
BOR_ADMIN_PASSWORD | Initial admin password (applied only when no users exist) |
| Variable | Default | Description |
|---|---|---|
BOR_ADDRESS | (all interfaces) | Server hostname or IP (no port) |
BOR_ENROLLMENT_PORT | 8443 | UI + enrollment gRPC listen port |
BOR_POLICY_PORT | 8444 | Agent mTLS policy stream listen port |
BOR_HOSTNAMES | — | Comma-separated extra SANs for the auto-generated TLS cert |
| Variable | Default | Description |
|---|---|---|
DB_HOST | localhost | PostgreSQL host |
DB_PORT | 5432 | PostgreSQL port |
DB_USER | bor | PostgreSQL user |
DB_NAME | bor | PostgreSQL database name |
DB_SSLMODE | disable | PostgreSQL SSL mode (disable, require, verify-full) |
If the CA and TLS variables are not set, the server auto-generates an internal
CA (ECDSA P-384, 10 years) and a server TLS certificate (ECDSA P-256, 365 days)
under /var/lib/bor/pki/ and reuses them on subsequent starts.
| Variable | Default | Description |
|---|---|---|
BOR_CA_CERT_FILE | auto | Path to CA certificate PEM |
BOR_CA_KEY_FILE | auto | Path to CA private key PEM (unused when PKCS#11 is set) |
BOR_CA_AUTOGEN_DIR | /var/lib/bor/pki/ca | Directory for auto-generated CA files |
BOR_TLS_CERT_FILE | auto | Path to server TLS certificate PEM |
BOR_TLS_KEY_FILE | auto | Path to server TLS private key PEM |
BOR_TLS_AUTOGEN_DIR | /var/lib/bor/pki/ui | Directory for auto-generated TLS cert |
Requires the server-pkcs11 binary. The PIN must come from an environment
variable — never store it in a YAML file.
| Variable | Description |
|---|---|
BOR_CA_PKCS11_LIB | Path to PKCS#11 shared library (.so) |
BOR_CA_PKCS11_TOKEN_LABEL | HSM token label |
BOR_CA_PKCS11_KEY_LABEL | CA private key label on the token |
BOR_CA_PKCS11_PIN | Token PIN |
| Variable | Default | Description |
|---|---|---|
BOR_ADMIN_TOKEN | — | Static token for gRPC enrollment calls (optional) |
LDAP_ENABLED | false | Enable LDAP authentication |
LDAP_HOST | localhost | LDAP server hostname |
LDAP_PORT | 389 | LDAP server port |
LDAP_USE_TLS | false | Use TLS for the LDAP connection |
LDAP_BIND_DN | — | LDAP bind distinguished name |
LDAP_BIND_PASSWORD | — | LDAP bind password |
LDAP_BASE_DN | — | LDAP search base DN |
The agent reads /etc/bor/config.yaml by default. Pass --config <path> to
override. A full annotated reference is in agent/config.yaml.example.
server:
address: "bor-server.example.com"enrollment_port: 8443# UI + enrollment gRPCpolicy_port: 8444# mTLS policy streaminsecure_skip_verify: false # true only for self-signed certs during setupagent:
client_id: ""# defaults to system hostnameenrollment:
data_dir: "/var/lib/bor/agent"# cert, key, and CA cert stored herefirefox:
policies_path: "/etc/firefox/policies/policies.json"flatpak_policies_path: "/var/lib/flatpak/extension/org.mozilla.firefox.systemconfig/x86_64/stable/policies/policies.json"chrome:
chrome_policies_path: "/etc/opt/chrome/policies/managed"chromium_policies_path: "/etc/chromium/policies/managed"chromium_browser_policies_path: "/etc/chromium-browser/policies/managed"flatpak_chromium_policies_path: ""# set to enable Flatpak Chromiumkconfig:
config_path: "/etc/xdg"# KDE Kiosk overlay directory- Security — cryptographic algorithms, FIPS 140-3 compliance, EU standards, deployment checklist, HSM integration
- Architecture — detailed design and data flows
- Contributing — setup, coding standards, PR process
Contributions are welcome via GitHub pull requests or by emailing patches to bor@vute.tech.
See docs/CONTRIBUTING.md for the full guide.
- Core policy management API and web UI
- Dual-port architecture (8443 UI/enrollment, 8444 agent mTLS)
- gRPC streaming with mTLS (TLS 1.3, mandatory client cert)
- Token-based agent enrollment (one-time, 5-minute TTL)
- Automatic certificate renewal (ECDSA P-256, 90-day lifetime)
- FIPS 140-3 validated builds (
GOFIPS140=v1.0.0, CAVP A6650) - PKCS#11 HSM support for CA private key (
-tags pkcs11) - Kerberos-based agent enrollment (AD / FreeIPA, token-free)
- Firefox ESR policy enforcement (RPM/DEB + Flatpak)
- Thunderbird policy enforcement
- Chrome / Chromium policy enforcement (including Flatpak)
- Microsoft Edge policy enforcement
- KDE Plasma KConfig (Kiosk) enforcement + KCM module restrictions
- dconf (GNOME) policy enforcement
- polkit rule enforcement
- firewalld policy enforcement
- Package management policies (packages + repositories)
- Tamper protection (file watcher restores managed files)
- RBAC with roles and permissions
- Web UI MFA (TOTP + WebAuthn)
- LDAP / Active Directory authentication
- Audit log
- Persistent compliance reporting (database storage)
- Prometheus metrics endpoint
- Desktop notifications on policy change
- Many-to-many node group membership
- deb / rpm / apk / Arch Linux packaging
- systemd unit policies
- Agent auto-update mechanism
- Multi-tenancy
Copyright (C) 2026 Vute Tech LTD Copyright (C) 2026 Bor contributors
Licensed under the GNU Lesser General Public License v3.0.