Add HTMX-based UI templates and handlers for account and audit management
- Introduced `web/templates/` for HTMX-fragmented pages (`dashboard`, `accounts`, `account_detail`, `error_fragment`, etc.). - Implemented UI routes for account CRUD, audit log display, and login/logout with CSRF protection. - Added `internal/ui/` package for handlers, CSRF manager, session validation, and token issuance. - Updated documentation to include new UI features and templates directory structure. - Security: Double-submit CSRF cookies, constant-time HMAC validation, login password/Argon2id re-verification at all steps to prevent bypass.
This commit is contained in:
@@ -88,7 +88,7 @@ mciassrv (passphrase or keyfile) to decrypt secrets at rest.
|
||||
|
||||
| Purpose | Algorithm | Rationale |
|
||||
|---|---|---|
|
||||
| Password hashing | Argon2id | OWASP-recommended; memory-hard; resists GPU/ASIC attacks. Parameters: time=3, memory=64MB, threads=4 (meets OWASP 2023 minimum of time=2, memory=64MB). |
|
||||
| Password hashing | Argon2id | OWASP-recommended; memory-hard; resists GPU/ASIC attacks. Parameters: time=3, memory=64MB, threads=4 (meets OWASP 2023 minimum of time=2, memory=64MB). Master key derivation uses time=3, memory=128MB, threads=4 (higher cost acceptable at startup). |
|
||||
| JWT signing | Ed25519 (EdDSA) | Fast, short signatures, no parameter malleability, immune to invalid-curve attacks. RFC 8037. |
|
||||
| JWT key storage | Raw Ed25519 private key in PEM-encoded PKCS#8 file, chmod 0600. | |
|
||||
| TOTP | HMAC-SHA1 per RFC 6238 (industry standard). Shared secret stored encrypted with AES-256-GCM using a server-side key. | |
|
||||
@@ -278,8 +278,8 @@ All endpoints use JSON request/response bodies. All responses include a
|
||||
| Method | Path | Auth required | Description |
|
||||
|---|---|---|---|
|
||||
| POST | `/v1/token/validate` | none | Validate a JWT (passed as Bearer header) |
|
||||
| POST | `/v1/token/issue` | admin JWT or role-scoped JWT | Issue service account token |
|
||||
| DELETE | `/v1/token/{jti}` | admin JWT or role-scoped JWT | Revoke token by JTI |
|
||||
| POST | `/v1/token/issue` | admin JWT | Issue service account token |
|
||||
| DELETE | `/v1/token/{jti}` | admin JWT | Revoke token by JTI |
|
||||
|
||||
### Account Endpoints (admin only)
|
||||
|
||||
@@ -310,9 +310,15 @@ All endpoints use JSON request/response bodies. All responses include a
|
||||
|
||||
| Method | Path | Auth required | Description |
|
||||
|---|---|---|---|
|
||||
| GET | `/v1/accounts/{id}/pgcreds` | admin JWT or role-scoped JWT | Retrieve Postgres credentials |
|
||||
| GET | `/v1/accounts/{id}/pgcreds` | admin JWT | Retrieve Postgres credentials |
|
||||
| PUT | `/v1/accounts/{id}/pgcreds` | admin JWT | Set/update Postgres credentials |
|
||||
|
||||
### Audit Endpoints (admin only)
|
||||
|
||||
| Method | Path | Auth required | Description |
|
||||
|---|---|---|---|
|
||||
| GET | `/v1/audit` | admin JWT | List audit log events |
|
||||
|
||||
### Admin / Server Endpoints
|
||||
|
||||
| Method | Path | Auth required | Description |
|
||||
@@ -335,8 +341,11 @@ CREATE TABLE server_config (
|
||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||
-- Ed25519 private key, PEM PKCS#8, encrypted at rest with AES-256-GCM
|
||||
-- using a master key derived from the startup passphrase.
|
||||
signing_key_enc BLOB NOT NULL,
|
||||
signing_key_nonce BLOB NOT NULL,
|
||||
signing_key_enc BLOB,
|
||||
signing_key_nonce BLOB,
|
||||
-- Argon2id salt for master key derivation; stable across restarts so the
|
||||
-- passphrase always yields the same key. Generated on first run.
|
||||
master_key_salt BLOB,
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
|
||||
);
|
||||
@@ -444,6 +453,8 @@ CREATE INDEX idx_audit_event ON audit_log (event_type);
|
||||
- TOTP secrets and Postgres passwords are encrypted with AES-256-GCM using a
|
||||
master key held only in server memory (derived at startup from a passphrase
|
||||
or keyfile). The nonce is stored adjacent to the ciphertext.
|
||||
- The master key salt is stored in `server_config.master_key_salt` so the
|
||||
Argon2id KDF produces the same key on every restart. Generated on first run.
|
||||
- The signing key encryption is layered: the Ed25519 private key is wrapped
|
||||
with AES-256-GCM using the startup master key. Operators must supply the
|
||||
passphrase/keyfile on each server restart.
|
||||
@@ -472,6 +483,7 @@ or a keyfile path — never inline in the config file.
|
||||
```toml
|
||||
[server]
|
||||
listen_addr = "0.0.0.0:8443"
|
||||
grpc_addr = "0.0.0.0:9443" # optional; omit to disable gRPC
|
||||
tls_cert = "/etc/mcias/server.crt"
|
||||
tls_key = "/etc/mcias/server.key"
|
||||
|
||||
@@ -518,7 +530,11 @@ mcias/
|
||||
│ ├── middleware/ # HTTP middleware (auth extraction, logging, rate-limit)
|
||||
│ ├── model/ # shared data types (Account, Token, Role, etc.)
|
||||
│ ├── server/ # HTTP handlers, router setup
|
||||
│ └── token/ # JWT issuance, validation, revocation
|
||||
│ ├── token/ # JWT issuance, validation, revocation
|
||||
│ └── ui/ # web UI context, CSRF, session, template handlers
|
||||
├── web/
|
||||
│ ├── static/ # CSS and static assets
|
||||
│ └── templates/ # HTML templates (base layout, pages, HTMX fragments)
|
||||
├── proto/
|
||||
│ └── mcias/v1/ # Protobuf service definitions (Phase 7)
|
||||
├── gen/
|
||||
@@ -798,7 +814,7 @@ mciassrv starts both listeners in the same process:
|
||||
│ ┌────────────────┐ ┌────────────────────┐ │
|
||||
│ │ REST listener │ │ gRPC listener │ │
|
||||
│ │ (net/http) │ │ (google.golang. │ │
|
||||
│ │ :8443 │ │ org/grpc) :8444 │ │
|
||||
│ │ :8443 │ │ org/grpc) :9443 │ │
|
||||
│ └───────┬─────────┘ └──────────┬─────────┘ │
|
||||
│ └──────────────┬─────────┘ │
|
||||
│ ▼ │
|
||||
@@ -818,7 +834,7 @@ configured window.
|
||||
```toml
|
||||
[server]
|
||||
listen_addr = "0.0.0.0:8443"
|
||||
grpc_addr = "0.0.0.0:8444" # optional; omit to disable gRPC
|
||||
grpc_addr = "0.0.0.0:9443" # optional; omit to disable gRPC
|
||||
tls_cert = "/etc/mcias/server.crt"
|
||||
tls_key = "/etc/mcias/server.key"
|
||||
```
|
||||
@@ -916,7 +932,7 @@ FROM debian:bookworm-slim
|
||||
|
||||
Security properties of the runtime image:
|
||||
|
||||
- No shell, no package manager, no Go toolchain — minimal attack surface
|
||||
- No Go toolchain, no build cache, no source code — minimal attack surface
|
||||
- Non-root user (`mcias`, uid 10001) — no escalation path
|
||||
- TLS termination happens inside the container (same cert/key as bare-metal
|
||||
deployment); the operator mounts `/etc/mcias/` as a read-only volume
|
||||
@@ -953,7 +969,7 @@ The Makefile `docker` target automates the build step with the version tag.
|
||||
| `man` | Build man pages; compress to `.gz` in `man/` |
|
||||
| `install` | Run `dist/install.sh` |
|
||||
| `docker` | `docker build -t mcias:$(VERSION) .` |
|
||||
| `clean` | Remove `bin/`, `gen/`, compressed man pages |
|
||||
| `clean` | Remove `bin/` and compressed man pages |
|
||||
| `dist` | Cross-compile release tarballs for linux/amd64 and linux/arm64 |
|
||||
|
||||
### Upgrade Path
|
||||
|
||||
Reference in New Issue
Block a user