Skip to content

Security

ollikurki edited this page May 20, 2026 · 1 revision

Security

HomePilot's security model is built around zero-secrets deployment, encrypted vault storage, scoped API tokens, and an approval-gated artifact lifecycle.

Zero-Secrets Architecture

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.

Secret Resolution Priority

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.

What Goes in the Vault

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

What Stays in .env

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 Security

Encryption

  • Vault files are encrypted with age (X25519 + ChaCha20-Poly1305)
  • Pure Python implementation via pyrage — no system age binary 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

Passphrase Protection

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.

Backup Considerations

  • 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 export includes the database but not the vault. Vault files must be backed up independently
  • After restoring, run hp kb reindex to rebuild the search index

Authentication

Token-Based Auth

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.

Token Scopes

Scope Permissions
read GET endpoints, read-only MCP tools
write All endpoints including artifact propose/approve
admin Full access including token management

Creating Tokens

# Full scope (default)
hp token create

# Read-only
hp token create --scope read_only

# JSON output
hp token create --output json

Admin Secret Header

For 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.

Token Rotation

# 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"

RBAC and Tool Access

MCP Tool Scopes

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.

Artifact Approval Gate

The artifact lifecycle enforces human review:

  1. AI proposes → artifact status: proposed
  2. Human reviews → hp artifacts show <id> to inspect the full spec
  3. Human approves or rejects → hp artifacts approve <id> or hp artifacts reject <id>
  4. Executor applies → only after approval
  5. 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>

Proxmox API Safety

Read-Only Access

The proxmox_api_read MCP tool is restricted to GET requests on allowlisted paths. It cannot modify Proxmox resources.

Least-Privilege Token

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 PVEAuditor

Store the resulting token in the vault:

hp vault set pve-token
# Enter: {"token": "monitor@pam!api=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}

SSH Safety

  • The jump server uses its own key pair — private keys are never exposed to the backend container
  • PVE_NODE_NAMES can block SSH access to Proxmox nodes entirely
  • exec_on_guest_readonly only allows whitelisted commands (cat, ls, ps, systemctl status, etc.)

Network Security

CORS

Default: * (all origins). Restrict with:

HP_CORS_ORIGINS=https://homepilot.example.com

Rate Limiting

Default: 60 requests per IP per minute. Adjust with HP_RATE_LIMIT.

Cookie Security

Set HP_COOKIE_SECURE=true for HTTPS deployments. This marks session cookies with the Secure attribute.

CSRF

Current: double-submit cookie pattern. Future: synchronizer token pattern for stronger guarantees.

Audit Trail

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.

Security Checklist

  • 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=true if using HTTPS
  • HP_CORS_ORIGINS restricted to known domains
  • HP_RATE_LIMIT set appropriately
  • HP_ENV=production set (prevents auto-generated secrets)
  • Jump server SSH key registered on all managed hosts
  • PVE_NODE_NAMES set to block SSH to Proxmox nodes
  • Artifact git remote uses SSH deploy key with restricted permissions

See Also

  • Configuration — Vault setup, passphrase management, environment variables
  • Installation — Proxmox token setup, jump server configuration
  • Artifacts — Artifact lifecycle and approval gate