# 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](https://tabler.io) (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, proxy detection servers/ ← Server and server group management, access assignments sshutil/ ← SSH key generation (RSA, Ed25519, Ed448) 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 1. **Load configuration** from environment variables 2. **Initialize logging** with the configured log level 3. **Create data directories** (`/data`, `/data/keys`, `/data/master`) 4. **Initialize SQLite database** with WAL mode and run all migrations 5. **Initialize services**: encryption, auth, keys, servers, deploy, audit, cron, mail 6. **Create initial owner account** (if no users exist) with auto-generated password 7. **Ensure system master key** exists (generates on first run) 8. **Configure security** subsystem (trusted proxy parsing) 9. **Set up HTTP routes** and load templates 10. **Start session cleanup** goroutine (removes expired sessions every minute) 11. **Apply middleware chain**: request logger → security headers → rate limiting → size limiting → CSRF 12. **Start cron scheduler** (checks for pending jobs every 30 seconds) 13. **Start key enforcement worker** (if enabled in Admin Settings) 14. **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) │ ├── 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: 1. The `KEYWARDEN_ENCRYPTION_KEY` environment variable is hashed with SHA-256 to derive a 32-byte AES key 2. Each private key is encrypted with a random 12-byte nonce 3. 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: 1. Marks the job as `running` 2. Resolves the SSH key and target servers 3. Deploys the key to the specified system user 4. If `remove_after_min > 0`, starts a background timer that triggers the expiry action 5. 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`.