Repository navigation
Security
HomePilot's security model is built around zero-secrets deployment, encrypted vault storage, scoped API tokens, and an approval-gated artifact lifecycle.
The .env file contains no HomePilot secrets. All sensitive values are stored in the age-encrypted vault and resolved at runtime via _try_vault_secret.
1. Environment variable (highest priority, used directly)
2. Vault (encrypted storage, recommended for production)
3. Auto-generated (fallback, development only)
For production (HP_ENV=production), HP_SECRET_KEY must be explicitly set or stored in vault — auto-generation is forbidden and the application will refuse to start with a ConfigError.
| Vault Key | Purpose | Sensitive? |
|---|---|---|
secret-key |
API token signing key | Yes |
admin-secret |
Admin bootstrap authentication | Yes |
pve-token |
Proxmox API credentials | Yes |
jumpserver-token |
SSH relay authentication | Yes |
webhook-secret |
Webhook HMAC-SHA256 signing | Yes |
Only non-secret configuration:
- Port numbers (
HP_DAEMON_PORT) - Host addresses (
HP_PROXMOX_HOST) - Feature flags (
HP_AUTO_APPLY_ENABLED) - Service URLs (
HP_EMBEDDING_SERVICE_URL) - Boolean settings (
HP_PROXMOX_VERIFY_SSL)
- Vault files are encrypted with age (X25519 + ChaCha20-Poly1305)
- Pure Python implementation via
pyrage— no systemagebinary required - Master identity is protected with AES-256-GCM derived from the vault passphrase
- Each secret is individually encrypted; compromising one secret does not compromise others
| Method | Security Level | Use Case |
|---|---|---|
| Auto-generated | Good (for Docker) | Default; persisted to {data_dir}/.vault_passphrase (mode 0o600) |
| Passphrase file | Better |
HP_VAULT_PASSPHRASE_FILE with Docker secrets |
| Environment variable | Acceptable (for dev) |
HP_VAULT_PASSPHRASE — visible in process list |
Recommended for production: Use Docker secrets with HP_VAULT_PASSPHRASE_FILE.
- Vault files (
master.protected,secrets/*.age) must be backed up alongside the database - The passphrase file must be backed up separately — loss of the passphrase means loss of all vault secrets
-
hp exportincludes the database but not the vault. Vault files must be backed up independently - After restoring, run
hp kb reindexto rebuild the search index
All API access requires a Bearer token in the Authorization header:
Authorization: Bearer hp_abc123def456...
Tokens are created with hp token create and stored as SHA-256 hashes in the database. Only the token prefix (first 8 characters) is stored for lookup.
| Scope | Permissions |
|---|---|
read |
GET endpoints, read-only MCP tools |
write |
All endpoints including artifact propose/approve |
admin |
Full access including token management |
# Full scope (default)
hp token create
# Read-only
hp token create --scope read_only
# JSON output
hp token create --output jsonFor bootstrap operations when no token exists yet, use the admin secret:
curl -X POST http://localhost:8000/auth/tokens \
-H "Content-Type: application/json" \
-H "x-hp-admin-secret: <secret>" \
-d '{"label": "ci-deploy", "scope": "full"}'The admin secret is stored in the vault (admin-secret) and is never exposed in environment variables.
# Create a new token
hp token create
# > hp_new123...
# Revoke the old one
curl -X DELETE http://localhost:8000/auth/tokens/hp_old123 \
-H "Authorization: Bearer $ADMIN_TOKEN"| Tool | Required Scope |
|---|---|
query_inventory |
read |
refresh_inventory |
read |
get_environment_doc |
read |
query_artifacts |
read |
get_artifact_status |
read |
search_kb |
read |
proxmox_api_read |
read |
http_call_read |
read |
read_file_on_guest |
read |
exec_on_guest_readonly |
read |
check_artifact_drift |
read |
record_fact |
write |
propose_artifact |
write |
approve_artifact |
write (rate-limited: 10/min/caller) |
Tokens with read_only scope cannot call write-scoped tools. This provides defense in depth — even if a read-only token is compromised, it cannot create or modify artifacts.
The artifact lifecycle enforces human review:
-
AI proposes → artifact status:
proposed -
Human reviews →
hp artifacts show <id>to inspect the full spec -
Human approves or rejects →
hp artifacts approve <id>orhp artifacts reject <id> - Executor applies → only after approval
- Hash verification → body hash is checked at both approve and apply time
This means the AI cannot apply changes without human approval. The approval is a recorded action:
approved_by:
user: <user-id from API token or web session>
at: <ISO8601 timestamp>
reason: <optional explanation>The proxmox_api_read MCP tool is restricted to GET requests on allowlisted paths. It cannot modify Proxmox resources.
Create a dedicated Proxmox user with minimal permissions:
# Create user with auditor role (read-only)
pveum user add monitor@pam --comment "HomePilot API user"
pveum user token add monitor@pam api --privsep 0
pveum aclmod / --users monitor@pam --roles PVEAuditorStore the resulting token in the vault:
hp vault set pve-token
# Enter: {"token": "monitor@pam!api=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}- The jump server uses its own key pair — private keys are never exposed to the backend container
-
PVE_NODE_NAMEScan block SSH access to Proxmox nodes entirely -
exec_on_guest_readonlyonly allows whitelisted commands (cat, ls, ps, systemctl status, etc.)
Default: * (all origins). Restrict with:
HP_CORS_ORIGINS=https://homepilot.example.comDefault: 60 requests per IP per minute. Adjust with HP_RATE_LIMIT.
Set HP_COOKIE_SECURE=true for HTTPS deployments. This marks session cookies with the Secure attribute.
Current: double-submit cookie pattern. Future: synchronizer token pattern for stronger guarantees.
All artifact state transitions write to an append-only audit_log table:
{ user, action, artifact_id, at, source, request_id }
The audit log is independent of artifact frontmatter (which can be edited) and cannot be modified through the API.
- Vault passphrase stored in Docker secrets, not
.env -
HP_PROXMOX_VERIFY_SSL=true(or CA cert added to container trust store) - Proxmox token uses least-privilege role (
PVEAuditor) -
HP_COOKIE_SECURE=trueif using HTTPS -
HP_CORS_ORIGINSrestricted to known domains -
HP_RATE_LIMITset appropriately -
HP_ENV=productionset (prevents auto-generated secrets) - Jump server SSH key registered on all managed hosts
-
PVE_NODE_NAMESset to block SSH to Proxmox nodes - Artifact git remote uses SSH deploy key with restricted permissions
- Configuration — Vault setup, passphrase management, environment variables
- Installation — Proxmox token setup, jump server configuration
- Artifacts — Artifact lifecycle and approval gate