7.2 KiB
Architecture Overview
This document describes the system architecture and design of Keywarden.
Technology Stack
| Component | Technology |
|---|---|
| Language | Go 1.26 |
| Database | SQLite 3 (WAL mode, embedded) |
| Web Framework | Go standard library (net/http) |
| Template Engine | Go html/template |
| UI Framework | Tabler (Bootstrap-based) |
| SSH Library | golang.org/x/crypto/ssh |
| Encryption | AES-256-GCM (Go crypto/aes, crypto/cipher) |
| Password Hashing | bcrypt (golang.org/x/crypto/bcrypt) |
| Ed448 Support | github.com/cloudflare/circl |
| Containerization | Docker (Alpine Linux) |
Application Structure
Keywarden is a single Go binary with embedded static assets and templates. It serves a web UI and handles all SSH operations internally.
cmd/keywarden/main.go ← Application entry point
internal/
audit/ ← Audit logging service
auth/ ← Authentication, users, MFA, password policy, invitations
config/ ← Environment-based configuration
cron/ ← Scheduled temporary access jobs
database/ ← SQLite connection, migrations, backup/restore
deploy/ ← SSH key deployment to remote servers
encryption/ ← AES-256-GCM encryption service
handlers/ ← HTTP handlers and routing (all UI logic)
keys/ ← SSH key management, system master key
logging/ ← Structured logging with levels
mail/ ← SMTP email service (notifications, invitations)
models/ ← Data models (User, SSHKey, Server, etc.)
security/ ← CSRF, security headers, rate limiting, gzip compression, proxy detection
servers/ ← Server and server group management, access assignments
sshutil/ ← SSH key generation (RSA, Ed25519, Ed448)
updater/ ← Background update checker (Gitea releases API)
worker/ ← Background key enforcement worker (Bastillion-style)
web/
embed.go ← Go embed directives for templates and static files
static/ ← CSS, JS, fonts (Tabler UI framework)
templates/ ← HTML templates (Go template syntax)
Startup Sequence
- Load configuration from environment variables
- Initialize logging with the configured log level
- Create data directories (
/data,/data/keys,/data/master) - Initialize SQLite database with WAL mode and run all migrations
- Initialize services: encryption, auth, keys, servers, deploy, audit, cron, mail
- Create initial owner account (if no users exist) with auto-generated password
- Ensure system master key exists (generates on first run)
- Configure security subsystem (trusted proxy parsing)
- Set up HTTP routes and load templates
- Start session cleanup goroutine (removes expired sessions every minute)
- Apply middleware chain: request logger → security headers → rate limiting → size limiting → CSRF → gzip compression
- Start cron scheduler (checks for pending jobs every 30 seconds)
- Start key enforcement worker (if enabled in Admin Settings)
- Start HTTP server
Database Design
Keywarden uses SQLite with the following tables:
| Table | Purpose |
|---|---|
users |
User accounts (username, email, password hash, role, MFA, themes) |
ssh_keys |
SSH key pairs (public key, encrypted private key, fingerprint) |
servers |
Managed remote servers (hostname, port, SSH username) |
server_groups |
Named groups of servers |
server_group_members |
Many-to-many relation: servers ↔ groups |
access_assignments |
Maps users + keys → hosts/groups with system user config |
cron_jobs |
Scheduled temporary access jobs |
key_deployments |
Deployment history log |
audit_log |
Full audit trail of all actions |
settings |
Key-value application settings |
invitation_tokens |
One-time invitation links for new users |
_migrations |
Tracks applied database migrations |
Database migrations are idempotent and run automatically on every startup. New columns are added via ALTER TABLE with migration tracking to prevent duplicate additions.
Request Flow
Client → [Nginx/Caddy] → Keywarden HTTP Server
│
├── Request Logger Middleware
├── Security Headers Middleware
├── Rate Limit Middleware (login endpoints)
├── Size Limit Middleware
├── CSRF Middleware (double-submit cookie)
├── Gzip Compression Middleware
│
├── Public Routes (/login, /invite/*)
├── Auth Routes (requireAuth → all authenticated users)
├── Admin Routes (requireAdmin → admin + owner)
└── Owner Routes (requireOwner → owner only)
Session Management
Sessions are stored in-memory (not in the database) as a map of session tokens to session data. Each session tracks:
- User ID
- Last activity timestamp (for sliding timeout)
- MFA setup requirement flag
Session tokens are cryptographically random 32-byte hex strings stored in an HTTP-only cookie (keywarden_session). Sessions expire after the configured timeout (default: 60 minutes of inactivity). A background goroutine cleans up expired sessions every minute.
Encryption Architecture
Private Key Storage
All SSH private keys are encrypted at rest using AES-256-GCM:
- The
KEYWARDEN_ENCRYPTION_KEYenvironment variable is hashed with SHA-256 to derive a 32-byte AES key - Each private key is encrypted with a random 12-byte nonce
- The encrypted blob (nonce + ciphertext + GCM tag) is base64-encoded and stored in the database
Backup Encryption
Database backups are encrypted with a user-provided password using the same AES-256-GCM scheme. The password is hashed with SHA-256 to derive the encryption key.
Password Storage
User passwords are hashed with bcrypt at the default cost factor.
System Master Key
The system master key is an Ed25519 SSH key pair generated on first startup. It is used for all SSH connections to managed servers. The private key is stored encrypted in the settings table.
The master key enables Keywarden to:
- Deploy SSH keys to server
authorized_keys - Create and manage system users on remote servers
- Add/remove sudo privileges
- Disable or delete system users during access expiry
Cron Scheduler
The cron service runs a tick every 30 seconds, checking for jobs where next_run <= now and status == 'active'. For each due job, it:
- Marks the job as
running - Resolves the SSH key and target servers
- Deploys the key to the specified system user
- If
remove_after_min > 0, starts a background timer that triggers the expiry action - Updates the job status and calculates the next run time
Supported schedules: once, hourly, daily, weekly, monthly.
Expiry actions: remove_key (default), disable_user, delete_user.