Refactor attestation engine and synchronize project documentation
- Refine session and storage lifecycle handling - Improve VM extension architecture across server, shared, and WASM runtimes - Enhance synthetic gene mutation engine integration and parity guarantees - Align deterministic state progression between server and browser execution paths - Update configuration examples and deployment guidance - Expand architecture, API, threat model, privacy, and WASM build documentation - Refresh README with comprehensive project overview, operational workflows, browser integration details, storage backend documentation, and security model - Document v0.6.0 refactoring outcomes and design rationale - Improve consistency across documentation, configuration, and implementation This commit consolidates the v0.6.0 architectural refactoring effort, strengthening deterministic browser/server parity while improving maintainability, operational clarity, and project documentation.
This commit is contained in:
1 parent
2b8afd54e0
commit
0ed3cb444d
15 files changed
+2357
-797
No files matched your search
+249
-127
@@ -1,160 +1,244 @@
|
||||
# ChronoSeal Deployment Guide
|
||||
|
||||
ChronoSeal v0.6.0 is designed for production deployment as a Unix-native daemon with hardened systemd support, lightweight WASM client runtime, and flexible backend storage.
|
||||
ChronoSeal is intended to run as a small Unix daemon behind TLS, with static browser assets served either by the daemon or by the same protected origin. This guide covers native, service, and container deployment.
|
||||
|
||||
## Prerequisites
|
||||
## Deployment Model
|
||||
|
||||
| Tool | Minimum version | Purpose |
|
||||
|---|---|---|
|
||||
| Rust | 1.87 stable | Server and WASM compilation |
|
||||
| wasm-pack | 0.13 | WASM build and packaging |
|
||||
| Docker | 24.x | Optional container deployment |
|
||||
| docker-compose | 2.x | Optional local orchestration |
|
||||
| systemd | 248+ | Service management |
|
||||
Typical production topology:
|
||||
|
||||
Install Rust: [https://rustup.rs](https://rustup.rs)
|
||||
Install wasm-pack: `cargo install wasm-pack`
|
||||
```text
|
||||
Internet
|
||||
|
|
||||
v
|
||||
TLS reverse proxy
|
||||
|
|
||||
v
|
||||
chronoseal daemon on 127.0.0.1:3000
|
||||
|
|
||||
v
|
||||
sqlite-in-disk or valkey storage
|
||||
```
|
||||
|
||||
---
|
||||
For local evaluation, the daemon can bind directly to `0.0.0.0:3000` or `127.0.0.1:3000`.
|
||||
|
||||
## Build Steps
|
||||
## Requirements
|
||||
|
||||
### 1. Build the WASM module
|
||||
| Tool | Minimum | Purpose |
|
||||
|---|---:|---|
|
||||
| Rust | 1.87 stable | Build server and shared crates |
|
||||
| `wasm32-unknown-unknown` target | current stable | Compile WASM runtime |
|
||||
| `wasm-pack` | 0.13 | Generate browser WASM package |
|
||||
| systemd | 248+ | Native service management |
|
||||
| Docker | 24.x | Optional container image |
|
||||
| Docker Compose | 2.x | Optional local orchestration |
|
||||
|
||||
Install Rust from rustup, then install the WASM tooling:
|
||||
|
||||
```bash
|
||||
rustup target add wasm32-unknown-unknown
|
||||
cargo install wasm-pack
|
||||
wasm-pack build wasm --target web --release
|
||||
rm -rf frontend/pkg
|
||||
mv wasm/pkg frontend/pkg
|
||||
```
|
||||
|
||||
This produces the browser runtime assets required by the frontend and the server static file handler.
|
||||
## Build
|
||||
|
||||
### 2. Build the server binary
|
||||
|
||||
```bash
|
||||
cargo build -p server --release
|
||||
```
|
||||
|
||||
Binary output: `target/release/server`
|
||||
|
||||
### 3. Convenience script
|
||||
Use the repository build script:
|
||||
|
||||
```bash
|
||||
bash scripts/build.sh
|
||||
```
|
||||
|
||||
This script builds the WASM module, moves the generated package into `frontend/pkg`, and builds the server binary.
|
||||
The script:
|
||||
|
||||
---
|
||||
1. Builds `wasm/` with `wasm-pack build --target web --release`.
|
||||
2. Replaces `frontend/pkg` with the generated package.
|
||||
3. Builds the release daemon binary.
|
||||
|
||||
## Deploying as a Native Service
|
||||
Manual equivalent:
|
||||
|
||||
ChronoSeal is intended to run as a proper Unix daemon managed by systemd.
|
||||
```bash
|
||||
wasm-pack build wasm --target web --release
|
||||
rm -rf frontend/pkg
|
||||
mv wasm/pkg frontend/pkg
|
||||
|
||||
### Install
|
||||
cargo build -p chronoseal-server --bin chronoseal --release
|
||||
```
|
||||
|
||||
Release binary:
|
||||
|
||||
```text
|
||||
target/release/chronoseal
|
||||
```
|
||||
|
||||
## Native Install
|
||||
|
||||
The installer builds, installs, enables, and starts the service:
|
||||
|
||||
```bash
|
||||
sudo bash scripts/install.sh
|
||||
```
|
||||
|
||||
This installer should perform the following tasks:
|
||||
Installer actions:
|
||||
|
||||
* create a system user for `chronoseal`
|
||||
* install the server binary into `/usr/local/bin/chronoseal`
|
||||
* install static frontend assets into `/opt/chronoseal/frontend`
|
||||
* install `chronoseal.service` into `/etc/systemd/system/`
|
||||
* enable and start the service
|
||||
- create the `chronoseal` system user if missing
|
||||
- build WASM and server artifacts
|
||||
- install `target/release/chronoseal` to `/usr/local/bin/chronoseal`
|
||||
- copy `frontend/` to `/opt/chronoseal/frontend`
|
||||
- install `chronoseal.service` to `/etc/systemd/system/chronoseal.service`
|
||||
- reload systemd
|
||||
- enable and start the service
|
||||
|
||||
### Verify the service
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
sudo systemctl status chronoseal
|
||||
chronoseal status --format json
|
||||
chronoseal health
|
||||
sudo journalctl -u chronoseal -f
|
||||
```
|
||||
|
||||
## Running Without Install
|
||||
|
||||
For local development:
|
||||
|
||||
```bash
|
||||
bash scripts/build.sh
|
||||
cargo run -p chronoseal-server --bin chronoseal -- run \
|
||||
--bind 127.0.0.1:3000 \
|
||||
--frontend-dir frontend
|
||||
```
|
||||
|
||||
Probe the daemon:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:3000/health
|
||||
curl http://127.0.0.1:3000/stats
|
||||
curl http://127.0.0.1:3000/metrics
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
ChronoSeal resolves configuration in this order:
|
||||
|
||||
1. CLI flags
|
||||
2. `CHRONOSEAL_*` environment variables
|
||||
3. TOML config file
|
||||
4. built-in defaults
|
||||
|
||||
Default config discovery:
|
||||
|
||||
1. `CHRONOSEAL_CONFIG`, if it points to an existing file
|
||||
2. `/etc/chronoseal/config.toml`
|
||||
3. `$XDG_CONFIG_HOME/chronoseal/config.toml`
|
||||
4. `~/.config/chronoseal/config.toml`
|
||||
|
||||
Validate effective configuration:
|
||||
|
||||
```bash
|
||||
chronoseal config check --format yaml
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```toml
|
||||
bind = "127.0.0.1:3000"
|
||||
db_type = "sqlite-in-disk"
|
||||
pid_file = "/run/chronoseal.pid"
|
||||
db_path = "/var/lib/chronoseal/chronoseal.sqlite"
|
||||
frontend_dir = "/usr/share/chronoseal/frontend"
|
||||
log_file = "/var/log/chronoseal/chronoseal.jsonl"
|
||||
|
||||
heartbeat_min_interval_ms = 12000
|
||||
heartbeat_max_interval_ms = 25000
|
||||
expiration_minutes = 30
|
||||
rate_limit_count = 5
|
||||
rate_limit_window_secs = 10
|
||||
max_timestamp_drift_ms = 30000
|
||||
|
||||
min_mouse_total_dist = 10.0
|
||||
max_mouse_avg_speed = 2.0
|
||||
min_pause_count = 1
|
||||
require_mouse_activity = true
|
||||
|
||||
gene_size = 512
|
||||
mutation_rounds = 4
|
||||
```
|
||||
|
||||
## Storage Backends
|
||||
|
||||
| Backend | `db_type` | Use case |
|
||||
|---|---|---|
|
||||
| SQLite memory | `sqlite-in-memory` | ephemeral local or stateless deployment |
|
||||
| SQLite disk | `sqlite-in-disk` | persisted session continuity across restarts |
|
||||
| Valkey | `valkey` | external session storage |
|
||||
|
||||
For disk persistence:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /var/lib/chronoseal
|
||||
sudo chown -R chronoseal:chronoseal /var/lib/chronoseal
|
||||
```
|
||||
|
||||
For Valkey:
|
||||
|
||||
```bash
|
||||
export CHRONOSEAL_DB_TYPE=valkey
|
||||
export CHRONOSEAL_VALKEY_ADDR=127.0.0.1:6666
|
||||
```
|
||||
|
||||
If Valkey connection setup fails, the current implementation logs a warning and falls back to in-memory SQLite.
|
||||
|
||||
## systemd
|
||||
|
||||
The supplied service file is intended as the baseline unit. Keep the daemon under a dedicated user and restrict filesystem access to the paths it needs.
|
||||
|
||||
Useful commands:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now chronoseal
|
||||
sudo systemctl restart chronoseal
|
||||
sudo systemctl status chronoseal
|
||||
sudo journalctl -u chronoseal -f
|
||||
```
|
||||
|
||||
### Recommended runtime options
|
||||
Recommended hardening properties include:
|
||||
|
||||
Use structured info-level logging in production:
|
||||
- `NoNewPrivileges=true`
|
||||
- `PrivateTmp=true`
|
||||
- `ProtectSystem=strict`
|
||||
- `ProtectHome=true`
|
||||
- `ProtectKernelTunables=true`
|
||||
- `ProtectKernelModules=true`
|
||||
- `ProtectControlGroups=true`
|
||||
- `MemoryDenyWriteExecute=true`
|
||||
- `RestrictRealtime=true`
|
||||
- `RestrictSUIDSGID=true`
|
||||
- `SystemCallArchitectures=native`
|
||||
|
||||
```bash
|
||||
export RUST_LOG=info
|
||||
sudo systemctl restart chronoseal
|
||||
```
|
||||
Any hardening must still allow access to:
|
||||
|
||||
Avoid `RUST_LOG=debug` in production because debug logs can expose internal session identifiers.
|
||||
|
||||
---
|
||||
|
||||
## systemd Integration
|
||||
|
||||
The supplied `chronoseal.service` is designed for hardened Unix-native operation.
|
||||
|
||||
Recommended service options:
|
||||
|
||||
* `NoNewPrivileges=true`
|
||||
* `PrivateTmp=true`
|
||||
* `ProtectSystem=strict`
|
||||
* `ProtectHome=true`
|
||||
* `ProtectKernelTunables=true`
|
||||
* `ProtectKernelModules=true`
|
||||
* `ProtectControlGroups=true`
|
||||
* `MemoryDenyWriteExecute=true`
|
||||
* `RestrictRealtime=true`
|
||||
* `RestrictSUIDSGID=true`
|
||||
* `SystemCallArchitectures=native`
|
||||
|
||||
These options reduce the host attack surface and keep the daemon constrained to its required runtime privileges.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
ChronoSeal reads configuration from a TOML file, environment variables, and CLI overrides. Use `chronoseal config` to validate the effective configuration.
|
||||
|
||||
Example runtime configuration options:
|
||||
|
||||
```toml
|
||||
bind = "0.0.0.0:3000"
|
||||
pid_file = "/run/chronoseal.pid"
|
||||
log_level = "info"
|
||||
db_type = "sqlite-in-memory"
|
||||
db_path = "/var/lib/chronoseal/chronoseal.db"
|
||||
```
|
||||
|
||||
### Supported `db_type`
|
||||
|
||||
* `sqlite-in-memory`
|
||||
* `sqlite-disk`
|
||||
* `valkey`
|
||||
|
||||
`sqlite-in-memory` is the default and preserves ephemeral session semantics.
|
||||
|
||||
`sqlite-disk` will persist session state to a file specified by `db_path`.
|
||||
|
||||
`valkey` selects the Valkey-compatible backend mode and may be useful for future deployment scenarios.
|
||||
|
||||
---
|
||||
- the binary
|
||||
- frontend assets
|
||||
- PID file directory
|
||||
- optional log file directory
|
||||
- SQLite database directory, if using `sqlite-in-disk`
|
||||
|
||||
## Reverse Proxy and TLS
|
||||
|
||||
ChronoSeal should be served over HTTPS in production. The heartbeat protocol includes timestamps and entropy data; serving that traffic in plaintext weakens security and allows easier traffic analysis.
|
||||
ChronoSeal should be served over HTTPS in production. Terminate TLS at a reverse proxy or load balancer and proxy to the local daemon.
|
||||
|
||||
### nginx example
|
||||
Minimal nginx example:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name your.domain.com;
|
||||
server_name example.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/your.domain.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/your.domain.com/privkey.pem;
|
||||
ssl_protocols TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
|
||||
|
||||
proxy_read_timeout 35s;
|
||||
proxy_send_timeout 10s;
|
||||
proxy_read_timeout 35s;
|
||||
proxy_send_timeout 10s;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
@@ -168,41 +252,79 @@ server {
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name your.domain.com;
|
||||
server_name example.com;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
```
|
||||
|
||||
### Docker deployment
|
||||
Keep `/init`, `/hb`, and frontend assets on the same origin when possible. If you split origins, configure CORS and cookie/application policy deliberately.
|
||||
|
||||
## Docker
|
||||
|
||||
Build and run:
|
||||
|
||||
```bash
|
||||
bash scripts/build.sh
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The supplied `docker-compose.yml` is intended for local evaluation and development. It mounts `frontend/` and exposes port `3000`.
|
||||
The Compose file exposes port `3000`.
|
||||
|
||||
Note: build the WASM package before container startup, or mount a pre-built `frontend/pkg/` volume.
|
||||
```bash
|
||||
curl http://127.0.0.1:3000/health
|
||||
```
|
||||
|
||||
---
|
||||
The Dockerfile copies `frontend/` from the working tree. Build `frontend/pkg` before building the image when the browser WASM runtime is required inside the container.
|
||||
|
||||
## Production Best Practices
|
||||
## Observability
|
||||
|
||||
* Use TLS termination at the perimeter
|
||||
* Run ChronoSeal behind a reverse proxy or firewall
|
||||
* Keep `RUST_LOG` at `info` or `warn`
|
||||
* Use `systemctl` for lifecycle management
|
||||
* Monitor `chronoseal` metrics with Prometheus
|
||||
* Place the frontend under the same origin as the protected pages or configure CORS carefully
|
||||
CLI:
|
||||
|
||||
---
|
||||
```bash
|
||||
chronoseal status --format json
|
||||
chronoseal health
|
||||
chronoseal stats --format json
|
||||
chronoseal metrics
|
||||
```
|
||||
|
||||
## Health and Metrics
|
||||
HTTP:
|
||||
|
||||
ChronoSeal exposes runtime endpoints for health and metrics.
|
||||
```bash
|
||||
curl http://127.0.0.1:3000/health
|
||||
curl http://127.0.0.1:3000/stats
|
||||
curl http://127.0.0.1:3000/metrics
|
||||
```
|
||||
|
||||
* `chronoseal health` — health probe
|
||||
* `chronoseal metrics` — Prometheus metrics output
|
||||
* `chronoseal status` — runtime status report
|
||||
* `chronoseal stats` — runtime statistics
|
||||
Prometheus metrics:
|
||||
|
||||
These endpoints are accessible locally from the daemon and may be proxied or scraped by monitoring infrastructure.
|
||||
- `chronoseal_sessions`
|
||||
- `chronoseal_expired_sessions`
|
||||
- `chronoseal_max_chain_length`
|
||||
|
||||
## Logging
|
||||
|
||||
Use info-level logs for production:
|
||||
|
||||
```bash
|
||||
CHRONOSEAL_LOG=info chronoseal run
|
||||
```
|
||||
|
||||
or with systemd:
|
||||
|
||||
```bash
|
||||
sudo systemctl edit chronoseal
|
||||
```
|
||||
|
||||
Avoid debug logging in production because internal identifiers may be written to logs.
|
||||
|
||||
## Production Checklist
|
||||
|
||||
- Build `frontend/pkg` before packaging.
|
||||
- Serve ChronoSeal traffic over HTTPS.
|
||||
- Bind the daemon to localhost behind a reverse proxy unless direct exposure is required.
|
||||
- Use a dedicated service user.
|
||||
- Keep debug logs disabled.
|
||||
- Choose storage intentionally: `sqlite-in-memory`, `sqlite-in-disk`, or `valkey`.
|
||||
- Protect SQLite and log directories with correct ownership.
|
||||
- Monitor `/health`, `/stats`, and `/metrics`.
|
||||
- Verify `chronoseal config check` after environment or config changes.
|
||||
Reference in new issue
Block a user