v0.0.6 - Tier-1 TCP listener + FIPS deployment documentation

This commit is contained in:
Laan Tungir
2026-05-02 18:14:20 -04:00
parent 3e86e539e0
commit b089bf36e3
15 changed files with 1166 additions and 203 deletions

179
documents/QUBES_OS.md Normal file
View File

@@ -0,0 +1,179 @@
# QUBES_OS.md
## 1. Goal
Run `n_signer` inside a dedicated Qubes OS qube (for example `vault`-like behavior), and let caller qubes access signing via qrexec with explicit policy control.
This doc outlines what must be implemented/packaged for a reliable Qubes deployment path.
---
## 2. Current status (where we are now)
Implemented in current codebase:
- `nsigner` supports `--listen qrexec` and `--listen stdio`.
- Framing is transport-agnostic and shared via length-prefixed JSON (`4-byte big-endian length + payload`).
- In qrexec/stdio mode, server handles one framed request-response exchange.
- Caller identity extraction supports `QREXEC_REMOTE_DOMAIN`, surfaced as `qubes:<source-vm>` when available.
Still missing for complete Qubes integration:
- qrexec service file + wrapper script artifacts.
- dom0 qrexec policy artifacts with sane defaults.
- install/uninstall guidance and verification flow for real Qubes deployment.
- packaging path (`packaging/qubes/`) and docs wired into README map.
---
## 3. Architecture in Qubes
### 3.1 Components
- **Signer qube** (target): runs `nsigner` service entrypoint.
- **Caller qube(s)**: apps/tools invoking qrexec service.
- **dom0 policy**: controls which caller qubes may invoke signer service.
### 3.2 Request path
1. Caller qube invokes qrexec service (e.g. `qubes.NsignerRpc`).
2. qrexec starts service command inside signer qube.
3. Service command runs `nsigner --listen qrexec`.
4. Caller sends framed JSON-RPC request over qrexec stdio channel.
5. `nsigner` returns framed JSON-RPC response.
### 3.3 Trust and identity
- Source qube identity comes from `QREXEC_REMOTE_DOMAIN`.
- `n_signer` maps caller as `qubes:<source-vm>` where available.
- qrexec policy in dom0 remains first enforcement boundary.
- `n_signer` policy/approval remains second boundary.
---
## 4. Required implementation tasks
## 4.1 Service entrypoint artifacts ✅ Implemented
Implemented repo artifacts:
- `packaging/qubes/rpc/qubes.NsignerRpc`
- `packaging/qubes/install-service.sh`
`qubes.NsignerRpc` runs:
- `exec /usr/local/bin/nsigner --listen qrexec`
Install inside the signer qube:
```bash
sudo sh packaging/qubes/install-service.sh
```
This installs the qrexec service to `/etc/qubes-rpc/qubes.NsignerRpc` with executable permissions.
## 4.2 dom0 policy artifacts ✅ Implemented
Implemented repo artifacts:
- `packaging/qubes/policy.d/40-nsigner.policy`
- `packaging/qubes/install-policy.sh`
Policy defaults now use explicit `ask` plus deny catch-all:
- `qubes.NsignerRpc * @anyvm @tag:nsigner-signer ask default_target=nsigner-vault`
- `qubes.NsignerRpc * @anyvm @anyvm deny`
Install in dom0:
```bash
sudo sh packaging/qubes/install-policy.sh
```
This installs `/etc/qubes/policy.d/40-nsigner.policy` and prints signer-tag guidance.
## 4.3 Policy model inside n_signer for qubes callers ✅ Implemented
Current code reads caller as `qubes:<vm>` and qrexec default behavior is hardened.
In qrexec mode, default prompt behavior is now:
- `PROMPT_EVERY_REQUEST`
This replaces the previous permissive `PROMPT_NEVER` temporary setting.
## 4.4 Client helper examples ✅ Implemented
Added:
- `documents/qubes_client_examples.md`
Includes:
- shell helper example invoking `qrexec-client-vm` with framed request/response handling
- Python helper example implementing frame encode/decode over qrexec stdio channel
- reference to `documents/CLIENT_IMPLEMENTATION.md` for full protocol details
---
## 5. Operational runbook
## 5.1 Setup signer qube
- install `nsigner` binary at `/usr/local/bin/nsigner`
- run `sudo sh packaging/qubes/install-service.sh`
- verify `/etc/qubes-rpc/qubes.NsignerRpc` exists and is executable
## 5.2 Setup dom0 policy
- run `sudo sh packaging/qubes/install-policy.sh`
- tag signer qube (example): `qvm-tags nsigner-vault add nsigner-signer`
- reload qrexec policy per Qubes procedure/version
## 5.3 Verification
- from caller qube, invoke test request (`get_public_key`)
- confirm signer qube receives request
- confirm activity log displays `qubes:<source-vm>` caller prefix
- validate deny behavior from unauthorized qube
## 5.4 Failure checks
- malformed frame -> parse error response
- missing policy -> deny path
- missing `QREXEC_REMOTE_DOMAIN` -> fallback identity path
---
## 6. Security requirements
- Never run signer service in disposable qube if mnemonic persistence is expected.
- Prefer dedicated minimal template for signer qube.
- Keep qrexec policy narrowly scoped (explicit source + target).
- Require user approval for sensitive methods unless explicitly intended otherwise.
- Log caller identity and method (without secret payload logging).
---
## 7. Documentation tasks
Update these after packaging lands:
- `README.md`
- add Qubes deployment subsection under transport/usage
- add `documents/QUBES_OS.md` and moved `documents/CLIENT_IMPLEMENTATION.md` in document map
- `plans/nsigner.md`
- mark T1 done with packaging status clearly separated
---
## 8. Definition of done (Qubes)
Qubes integration is considered complete when:
1. qrexec service artifact exists and is installable.
2. dom0 policy artifact exists with secure default pattern.
3. End-to-end call from allowed caller qube succeeds.
4. Call from unauthorized qube is denied.
5. Caller displayed as `qubes:<vm>` in activity.
6. README + docs include full setup and troubleshooting.