Files
thakares 3397ca121b Enhance deployment documentation with security checks
Added sections for binary hardening verification, runtime verification, and deployment footprint details.
2026-06-05 13:55:16 +05:30

581 lines
13 KiB
Markdown

# ChronoSeal Deployment Guide
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.
## Deployment Model
Typical production topology:
```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`.
## Requirements
| 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
```
## Build
Use the repository build script:
```bash
bash scripts/build.sh
```
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.
Manual equivalent:
```bash
wasm-pack build wasm --target web --release
rm -rf frontend/pkg
mv wasm/pkg frontend/pkg
cargo build -p chronoseal-server --bin chronoseal --release
```
Release binary:
```text
target/release/chronoseal
```
## Binary Hardening Verification
Before packaging or deploying ChronoSeal, verify that the release binary includes the expected platform hardening protections.
### Security Inspection
Inspect the release binary with `checksec`:
```bash
checksec file target/release/chronoseal
```
Expected protections:
```text
Full RELRO
Stack Canary Found
NX enabled
PIE Enabled
No RPATH
No RUNPATH
```
These mitigations help reduce the impact of memory corruption vulnerabilities and runtime exploitation.
### Stripped Production Binary
To verify symbol reduction and release artifact quality:
```bash
strip target/release/chronoseal -o chronoseal.stripped
nm -D chronoseal.stripped | wc -l
```
A stripped production binary should expose only a small dynamic symbol set.
Check for remaining debug sections:
```bash
readelf -S chronoseal.stripped | grep debug
```
Production artifacts should not contain `.debug_*` sections.
### Source Path Disclosure
Rust release builds may embed local source paths from the build environment.
To reduce path disclosure:
```bash
RUSTFLAGS="--remap-path-prefix=$HOME=~" \
cargo build --release
```
or:
```bash
RUSTFLAGS="--remap-path-prefix=$(pwd)=." \
cargo build --release
```
Recommended release profile:
```toml
[profile.release]
lto = true
codegen-units = 1
panic = "abort"
strip = "symbols"
```
### Runtime Verification
Start the daemon locally:
```bash
./chronoseal run --bind 127.0.0.1:8080
```
Expected startup output:
```text
INFO chronoseal daemon started bind=127.0.0.1:8080
```
Verify core endpoints:
```bash
curl http://127.0.0.1:8080/health
curl http://127.0.0.1:8080/stats
curl http://127.0.0.1:8080/metrics
```
Successful responses confirm that:
* configuration loading succeeded
* storage initialization completed
* HTTP listeners are active
* observability endpoints are operational
### PID File Permissions
When running as an unprivileged user, writing directly to `/run` may fail:
```text
could not write PID file
Permission denied
```
For local development:
```bash
chronoseal run --pid-file /tmp/chronoseal.pid
```
For production systemd deployments, prefer:
```ini
RuntimeDirectory=chronoseal
```
and:
```text
/run/chronoseal/chronoseal.pid
```
managed by systemd.
### Additional Validation
Inspect runtime dependencies:
```bash
ldd target/release/chronoseal
```
Verify ELF program headers:
```bash
readelf -l target/release/chronoseal
```
Look for:
```text
GNU_RELRO
GNU_STACK
```
Confirm binary size:
```bash
ls -lh target/release/chronoseal
```
These checks should be performed before publishing release artifacts, container images, or distribution packages.
## Native Install
The installer builds, installs, enables, and starts the service:
```bash
sudo bash scripts/install.sh
```
Installer actions:
- 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:
```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 / Redis:
ChronoSeal expects a running Valkey or Redis instance when `db_type` is set to `valkey`.
### 1. Installing Valkey or Redis
To install Valkey (the recommended open-source option) or Redis on Linux:
* **Valkey (Debian/Ubuntu)**:
```bash
sudo apt-get install -y valkey-server
```
* **Redis (Debian/Ubuntu)**:
```bash
sudo apt-get install -y redis-server
```
### 2. Local Setup and Startup
By default, ChronoSeal searches for Valkey/Redis on `127.0.0.1:6666`.
You can start a local instance manually:
```bash
# Start Valkey on port 6666
valkey-server --port 6666 --bind 127.0.0.1
# Or start Redis on port 6666
redis-server --port 6666 --bind 127.0.0.1
```
Or run it via Docker:
```bash
# Run Valkey container mapping host port 6666 to container port 6379
docker run -d --name chronoseal-valkey -p 6666:6379 valkey/valkey:latest
```
### 3. Service Configuration
Configure the environment variables to point ChronoSeal to your instance:
```bash
export CHRONOSEAL_DB_TYPE=valkey
export CHRONOSEAL_VALKEY_ADDR=127.0.0.1:6666
```
#### Providing Credentials & SSL/TLS
If your Valkey/Redis server requires authentication or secure TLS/SSL, include them directly in the `CHRONOSEAL_VALKEY_ADDR` connection URL:
* **Password Only**:
```bash
export CHRONOSEAL_VALKEY_ADDR=redis://:your_password@127.0.0.1:6666
```
* **Username & Password**:
```bash
export CHRONOSEAL_VALKEY_ADDR=redis://your_username:your_password@127.0.0.1:6666
```
* **Secure Connection (SSL/TLS)**: Use the `rediss://` scheme prefix:
```bash
export CHRONOSEAL_VALKEY_ADDR=rediss://your_username:your_password@secure-valkey-host.example.com:6379
```
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 hardening properties include:
- `NoNewPrivileges=true`
- `PrivateTmp=true`
- `ProtectSystem=strict`
- `ProtectHome=true`
- `ProtectKernelTunables=true`
- `ProtectKernelModules=true`
- `ProtectControlGroups=true`
- `MemoryDenyWriteExecute=true`
- `RestrictRealtime=true`
- `RestrictSUIDSGID=true`
- `SystemCallArchitectures=native`
Any hardening must still allow access to:
- 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. Terminate TLS at a reverse proxy or load balancer and proxy to the local daemon.
Minimal nginx example:
```nginx
server {
listen 443 ssl http2;
server_name example.com;
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;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
```
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 Compose file exposes port `3000`.
```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.
## Observability
CLI:
```bash
chronoseal status --format json
chronoseal health
chronoseal stats --format json
chronoseal metrics
```
HTTP:
```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
```
Prometheus metrics:
- `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.
## Runtime Footprint
ChronoSeal is intentionally designed to maintain a small deployment footprint while providing browser attestation, cryptographic verification, session continuity, and WASM execution capabilities.
Typical v1.0.2 release artifact sizes:
| Component | Approximate Size |
| ----------------------------------------------- | ---------------: |
| Native daemon (`chronoseal`) | ~9.1 MiB |
| Browser runtime (`chronoseal_wasm.wasm`) | ~728 KiB |
| WASM static library (`libchronoseal_wasm.rlib`) | ~188 KiB |
Example:
```text
chronoseal
9501232 bytes
≈ 9.06 MiB
chronoseal_wasm.wasm
745569 bytes
≈ 728 KiB
```
These compact artifact sizes help:
* reduce deployment overhead
* minimize container image growth
* improve cold-start performance
* reduce browser download size
* simplify edge and self-hosted deployments
ChronoSeal intentionally avoids heavyweight runtime dependencies and large browser frameworks, allowing the complete attestation stack to remain compact while preserving functionality.
```
## v1.0.2 Deployment Notes
- Containers run as a dedicated non-root user.
- Reverse proxies should forward X-Forwarded-For or X-Real-IP.
- Security headers are enabled by default.