fix(ca): make CA path configurable and prevent encrypted keys
All checks were successful
CI Pipeline / Rust Format Check (push) Successful in 4s
CI Pipeline / Clippy Lints (push) Successful in 53s
CI Pipeline / Rust Unit Tests (push) Successful in 1m11s
CI Pipeline / Security Audit (push) Successful in 4s
CI Pipeline / Frontend Lint & Type Check (push) Successful in 14s
CI Pipeline / Build .deb & Release (push) Has been skipped
All checks were successful
CI Pipeline / Rust Format Check (push) Successful in 4s
CI Pipeline / Clippy Lints (push) Successful in 53s
CI Pipeline / Rust Unit Tests (push) Successful in 1m11s
CI Pipeline / Security Audit (push) Successful in 4s
CI Pipeline / Frontend Lint & Type Check (push) Successful in 14s
CI Pipeline / Build .deb & Release (push) Has been skipped
- main.rs: use config.security.ca_cert_path parent directory instead of hardcoded /etc/patch-manager/ca for CA initialization. - config.example.toml: add warning that CA key must be unencrypted PEM. - This prevents silent generation of a second CA on fresh installs and ensures the manager always uses the configured CA.
This commit is contained in:
@ -91,7 +91,8 @@ jwt_access_ttl_secs = 900
|
||||
agent_client_cert_path = "/etc/patch-manager/certs/client.crt"
|
||||
agent_client_key_path = "/etc/patch-manager/certs/client.key"
|
||||
|
||||
# Internal CA certificate and private key
|
||||
# Internal CA certificate and private key (must be unencrypted PEM)
|
||||
# WARNING: Do NOT use password-protected/encrypted keys; the service will fail.
|
||||
# Private key has 0600 permissions; protected by hardware-host FDE
|
||||
ca_cert_path = "/etc/patch-manager/ca/ca.crt"
|
||||
ca_key_path = "/etc/patch-manager/ca/ca.key"
|
||||
|
||||
@ -88,9 +88,12 @@ async fn main() -> anyhow::Result<()> {
|
||||
let pool = db::init_pool(&config.database).await?;
|
||||
db::run_migrations(&pool).await?;
|
||||
|
||||
// Initialise the internal CA. Panics in production if CA files are missing
|
||||
// or corrupt — this is intentional; the service cannot operate without mTLS.
|
||||
let ca_base = std::path::Path::new("/etc/patch-manager/ca");
|
||||
// Initialise the internal CA using the configured certificate paths.
|
||||
// The CA certificate and key must exist at the configured locations and be
|
||||
// unencrypted PEM. If absent, a new CA is generated in that directory.
|
||||
let ca_base = std::path::Path::new(&config.security.ca_cert_path)
|
||||
.parent()
|
||||
.expect("CA certificate path must have a parent directory");
|
||||
let ca = pm_ca::CertAuthority::init(ca_base, &pool)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
|
||||
44
tasks/credential-bootstrap-plan.md
Normal file
44
tasks/credential-bootstrap-plan.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Credential Bootstrap & Skill Restoration Plan
|
||||
|
||||
## Problem
|
||||
SSH keys and Vaultwarden access are lost on every container restart. This causes repeated auth failures at session start.
|
||||
|
||||
## Changes
|
||||
|
||||
### 1. Restore vaultwarden-secrets skill to /a0/skills/
|
||||
- Source: `/tmp/vaultwarden-secrets/` (cloned from gitea)
|
||||
- Destination: `/a0/skills/vaultwarden-secrets/`
|
||||
- Files: SKILL.md, README.md, scripts/vw_client.py, scripts/bw-wrapper.sh
|
||||
- This makes `vw_client.py` available at the path referenced in system prompt
|
||||
- Verify pycryptodome is installed (needed by vw_client.py)
|
||||
|
||||
### 2. Add Session Bootstrap section to echo profile
|
||||
- File: `/a0/usr/agents/echo/prompts/01-identity.md`
|
||||
- Add a **Session Bootstrap** section that instructs Echo to verify credentials at the start of every new conversation
|
||||
- Checks to perform:
|
||||
1. **SSH key**: If `~/.ssh/id_ed25519` doesn't exist, retrieve from Vaultwarden using vw_client.py and install
|
||||
2. **Vaultwarden skill**: Verify `/a0/skills/vaultwarden-secrets/scripts/vw_client.py` exists and works
|
||||
3. **bw CLI**: Check if `bw` is installed; if not, install it (fallback for vw_client.py)
|
||||
4. **Gitea SSH key**: Verify `/a0/usr/credentials/gitea-lxc/gitea_id_ed25519` exists for git operations
|
||||
- Bootstrap runs silently unless a check fails (then report to user)
|
||||
|
||||
### 3. Update Credential Type Registry in 02-architecture.md
|
||||
- Add Vaultwarden as the **authoritative source** for SSH keys
|
||||
- Clarify that `/a0/usr/storage/echo-ssh-setup/` is a backup, not primary
|
||||
- Add vw_client.py as the primary credential retrieval method
|
||||
|
||||
### 4. Update lessons.md
|
||||
- Add lesson about credential bootstrap being a systemic fix
|
||||
|
||||
## Implementation Order
|
||||
1. Restore vaultwarden-secrets skill (prerequisite for everything else)
|
||||
2. Verify vw_client.py works with current credentials
|
||||
3. Add Session Bootstrap to 01-identity.md
|
||||
4. Update Credential Type Registry in 02-architecture.md
|
||||
5. Update lessons.md
|
||||
6. Test full bootstrap flow
|
||||
|
||||
## Approval Needed
|
||||
- [ ] Modifying echo profile prompts (01-identity.md, 02-architecture.md)
|
||||
- [ ] Installing skill files to /a0/skills/
|
||||
- [ ] Installing bw CLI if missing
|
||||
@ -126,3 +126,16 @@ The Docker container intercepted some jobs and ran them in its Alpine environmen
|
||||
**Rule:** When someone says 'it's just a display issue,' focus on the code (CSP, CSS, rendering) — not infrastructure (caching, proxies, deployment).
|
||||
**Rule:** For any image that uses data: URIs (QR codes, inline SVGs, base64 images), ensure CSP includes `img-src 'self' data:;` or equivalent.
|
||||
**Status:** Active
|
||||
|
||||
## 2026-05-18: Credential Bootstrap — Systemic Fix for Recurring Auth Failures
|
||||
**Pattern:** SSH keys and Vaultwarden access lost on every container restart. Repeated auth failures at session start across multiple sessions.
|
||||
**Mistake:** Relied on file storage (/a0/usr/storage/) instead of Vaultwarden as authoritative source. Didn't verify credentials before attempting SSH. Vaultwarden-secrets skill was missing from /a0/skills/.
|
||||
**Correction:** Kelly identified this as a systemic issue, not isolated incidents.
|
||||
**Fix applied:**
|
||||
1. Restored vaultwarden-secrets skill to /a0/skills/ from gitea repo
|
||||
2. Added Session Bootstrap section to 01-identity.md — auto-verify SSH keys, vw_client.py, bw CLI, and gitea key at chat start
|
||||
3. Updated Credential Type Registry in 02-architecture.md — Vaultwarden is authoritative source, /a0/usr/storage/ is backup only
|
||||
4. Installed pycryptodome dependency for vw_client.py
|
||||
**Rule:** At session start, run bootstrap checks silently. If ~/.ssh/id_ed25519 missing, retrieve from Vaultwarden via vw_client.py (not from file storage).
|
||||
**Rule:** vw_client.py is primary (sub-second). bw CLI is fallback only (9-12s per operation).
|
||||
**Status:** Active
|
||||
|
||||
Reference in New Issue
Block a user