README.md (700 lines): - Three-tier deployment model with ASCII diagram - Federation blueprint in web UI routes - deploy/ directory in architecture tree - Documentation index linking all guides CLAUDE.md (256 lines): - Updated architecture tree with all new docs and deploy files New guides: - docs/federation.md (317 lines) — gossip protocol mechanics, peer setup, trust filtering, offline bundles, relay deployment, jurisdiction - docs/evidence-guide.md (283 lines) — evidence packages, cold archives, selective disclosure, chain anchoring, legal discovery workflow - docs/source-dropbox.md (220 lines) — token management, client-side hashing, extract-then-strip pipeline, receipt mechanics, opsec - docs/index.md — documentation hub linking all guides Training materials: - docs/training/reporter-quickstart.md (105 lines) — printable one-page card: boot USB, attest photo, encode message, check-in, emergency - docs/training/emergency-card.md (79 lines) — wallet-sized laminated card: three destruction methods, 10-step order, key contacts - docs/training/admin-reference.md (219 lines) — deployment tiers, CLI tables, backup checklist, hardening checklist, troubleshooting Also includes existing architecture docs from the original repos. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
514 lines
15 KiB
Markdown
514 lines
15 KiB
Markdown
# SooSeF Admin Operations Guide
|
|
|
|
**Audience**: IT administrators, system operators, and technically competent journalists
|
|
responsible for deploying, configuring, and maintaining SooSeF instances for their
|
|
organization.
|
|
|
|
**Prerequisites**: Familiarity with Linux command line, Docker basics, and SSH. For Tier 1
|
|
USB builds, familiarity with Debian `live-build`.
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
This guide covers the operational tasks an admin performs after initial deployment. For
|
|
installation and deployment, see [deployment.md](../deployment.md). For architecture
|
|
details, see [docs/architecture/](../architecture/).
|
|
|
|
Your responsibilities as a SooSeF admin:
|
|
|
|
1. Deploy and maintain SooSeF instances (Tier 1 USB, Tier 2 server, Tier 3 relay)
|
|
2. Manage user accounts and access
|
|
3. Configure threat level presets for your environment
|
|
4. Manage the source drop box
|
|
5. Set up and maintain federation between organizations
|
|
6. Monitor system health and perform backups
|
|
7. Respond to security incidents
|
|
|
|
---
|
|
|
|
## 1. User Management
|
|
|
|
### Creating User Accounts
|
|
|
|
On first start, the web UI prompts for the first admin account. Additional users are
|
|
created through the **Admin** panel at `/admin/`.
|
|
|
|
Each user has:
|
|
- A username and password (stored as Argon2id hashes in SQLite)
|
|
- An admin flag (admin users can manage other accounts and the drop box)
|
|
|
|
### Password Resets
|
|
|
|
From the admin panel, issue a temporary password for a locked-out user. The user should
|
|
change it on next login. All password resets are recorded in the audit log
|
|
(`~/.soosef/audit.jsonl`).
|
|
|
|
### Account Lockout
|
|
|
|
After `login_lockout_attempts` (default: 5) failed logins, the account is locked for
|
|
`login_lockout_minutes` (default: 15). Lockout state is in-memory and clears on server
|
|
restart.
|
|
|
|
For persistent lockout (e.g., a compromised account), delete the user from the admin panel.
|
|
|
|
### Audit Trail
|
|
|
|
All admin actions are logged to `~/.soosef/audit.jsonl` in JSON-lines format:
|
|
|
|
```json
|
|
{"timestamp": "2026-04-01T12:00:00+00:00", "actor": "admin", "action": "user.create", "target": "user:reporter1", "outcome": "success", "source": "web"}
|
|
```
|
|
|
|
Actions logged: `user.create`, `user.delete`, `user.password_reset`,
|
|
`key.channel.generate`, `key.identity.generate`, `killswitch.fire`
|
|
|
|
> **Warning**: The audit log is destroyed by the killswitch. This is intentional --
|
|
> in a field compromise, data destruction takes precedence over audit preservation.
|
|
|
|
---
|
|
|
|
## 2. Threat Level Configuration
|
|
|
|
SooSeF ships four presets at `deploy/config-presets/`. Select based on your operational
|
|
environment.
|
|
|
|
### Applying a Preset
|
|
|
|
```bash
|
|
$ cp deploy/config-presets/high-threat.json ~/.soosef/config.json
|
|
```
|
|
|
|
Restart the server to apply.
|
|
|
|
### Preset Summary
|
|
|
|
| Preset | Session Timeout | Killswitch | Dead Man's Switch | USB Monitor | Cover Name |
|
|
|---|---|---|---|---|---|
|
|
| **Low** (press freedom) | 30 min | Off | Off | Off | None |
|
|
| **Medium** (restricted press) | 15 min | On | 48h / 4h grace | On | "Office Document Manager" |
|
|
| **High** (conflict zone) | 5 min | On | 12h / 1h grace | On | "Local Inventory Tracker" |
|
|
| **Critical** (targeted surveillance) | 3 min | On | 6h / 1h grace | On | "System Statistics" |
|
|
|
|
### Custom Configuration
|
|
|
|
Edit `~/.soosef/config.json` directly. All fields have defaults. Key fields for security:
|
|
|
|
| Field | What It Controls |
|
|
|---|---|
|
|
| `host` | Bind address. `127.0.0.1` = local only; `0.0.0.0` = LAN access |
|
|
| `session_timeout_minutes` | How long before idle sessions expire |
|
|
| `killswitch_enabled` | Whether the software killswitch is available |
|
|
| `deadman_enabled` | Whether the dead man's switch is active |
|
|
| `deadman_interval_hours` | Hours between required check-ins |
|
|
| `deadman_grace_hours` | Grace period after missed check-in before auto-purge |
|
|
| `deadman_warning_webhook` | URL to POST a JSON warning during grace period |
|
|
| `cover_name` | CN for the self-signed TLS certificate (cover/duress mode) |
|
|
| `backup_reminder_days` | Days before `soosef status` warns about overdue backups |
|
|
|
|
> **Warning**: Setting `auth_enabled: false` disables all login requirements. Never
|
|
> do this on a network-accessible instance.
|
|
|
|
---
|
|
|
|
## 3. Source Drop Box Operations
|
|
|
|
The drop box provides SecureDrop-style anonymous file intake.
|
|
|
|
### Creating Upload Tokens
|
|
|
|
1. Go to `/dropbox/admin` in the web UI (admin account required)
|
|
2. Set a **label** (internal only -- the source never sees this)
|
|
3. Set **expiry** in hours (default: 24)
|
|
4. Set **max files** (default: 10)
|
|
5. Click **Create Token**
|
|
|
|
You receive a URL like `https://<host>:<port>/dropbox/upload/<token>`.
|
|
|
|
### Sharing URLs With Sources
|
|
|
|
Share the URL over an already-secure channel only:
|
|
|
|
- **Best**: Hand-written on paper, in person
|
|
- **Good**: Signal, Wire, or other end-to-end encrypted messenger
|
|
- **Acceptable**: Encrypted email (PGP/GPG)
|
|
- **Never**: Unencrypted email, SMS, or any channel you do not control
|
|
|
|
### What Happens When a Source Uploads
|
|
|
|
1. The source opens the URL in any browser (no account needed, no SooSeF branding)
|
|
2. Their browser computes SHA-256 hashes client-side before upload (SubtleCrypto)
|
|
3. Files are uploaded and processed:
|
|
- EXIF metadata is extracted (evidentiary fields: GPS, timestamp)
|
|
- All metadata is stripped from the stored copy (protects source device info)
|
|
- The original bytes are attested (signed) before stripping
|
|
4. The source receives a receipt code (HMAC of file hash + token)
|
|
5. Files are stored in `~/.soosef/temp/dropbox/` with mode 0700
|
|
|
|
### Revoking Tokens
|
|
|
|
From `/dropbox/admin`, click **Revoke** on any active token. The token is immediately
|
|
deleted from the database. Any source with the URL can no longer upload.
|
|
|
|
### Receipt Verification
|
|
|
|
Sources can verify their submission was received at `/dropbox/verify-receipt` by entering
|
|
their receipt code. This returns the filename, SHA-256, and reception timestamp.
|
|
|
|
### Operational Security
|
|
|
|
- The upload page has no SooSeF branding -- it is a minimal HTML form
|
|
- No external resources are loaded (no CDN, fonts, analytics) -- Tor Browser compatible
|
|
- SooSeF does not log source IP addresses
|
|
- If using a reverse proxy (nginx, Caddy), disable access logging for `/dropbox/upload/`
|
|
- Tokens auto-expire and are cleaned up on every admin page load
|
|
- For maximum source protection, run SooSeF as a Tor hidden service
|
|
|
|
### Storage Management
|
|
|
|
Uploaded files accumulate in `~/.soosef/temp/dropbox/`. Periodically review and process
|
|
submissions, then remove them from the temp directory. The files are not automatically
|
|
cleaned up (they persist until you act on them or the killswitch fires).
|
|
|
|
---
|
|
|
|
## 4. Key Management
|
|
|
|
### Two Key Domains
|
|
|
|
SooSeF manages two independent key types:
|
|
|
|
| Key | Algorithm | Location | Purpose |
|
|
|---|---|---|---|
|
|
| **Identity key** | Ed25519 | `~/.soosef/identity/` | Sign attestations, chain records |
|
|
| **Channel key** | AES-256-GCM (Argon2id-derived) | `~/.soosef/stegasoo/channel.key` | Steganographic encoding |
|
|
|
|
These are never merged. Rotating one does not affect the other.
|
|
|
|
### Key Rotation
|
|
|
|
**Identity rotation** archives the old keypair and generates a new one. If the chain is
|
|
enabled, a `soosef/key-rotation-v1` record is signed by the OLD key, creating a
|
|
verifiable trust chain.
|
|
|
|
```bash
|
|
$ soosef keys rotate-identity
|
|
```
|
|
|
|
After rotating, immediately:
|
|
1. Take a fresh backup (`soosef keys export`)
|
|
2. Notify all collaborators of the new fingerprint
|
|
3. Update trusted-key lists at partner organizations
|
|
|
|
**Channel rotation** archives the old key and generates a new one:
|
|
|
|
```bash
|
|
$ soosef keys rotate-channel
|
|
```
|
|
|
|
After rotating, share the new channel key with all stego correspondents.
|
|
|
|
### Trust Store
|
|
|
|
Import collaborator public keys so you can verify their attestations and accept their
|
|
federation bundles:
|
|
|
|
```bash
|
|
$ soosef keys trust --import /media/usb/partner-pubkey.pem
|
|
```
|
|
|
|
Always verify fingerprints out-of-band (in person or over a known-secure voice channel).
|
|
|
|
List trusted keys:
|
|
|
|
```bash
|
|
$ soosef keys show
|
|
```
|
|
|
|
Remove a trusted key:
|
|
|
|
```bash
|
|
$ soosef keys untrust <fingerprint>
|
|
```
|
|
|
|
### Backup Schedule
|
|
|
|
SooSeF warns when backups are overdue (configurable via `backup_reminder_days`).
|
|
|
|
```bash
|
|
# Create encrypted backup
|
|
$ soosef keys export -o /media/usb/backup.enc
|
|
|
|
# Check backup status
|
|
$ soosef status
|
|
```
|
|
|
|
Store backups on separate physical media, in a different location from the device.
|
|
|
|
---
|
|
|
|
## 5. Federation Setup
|
|
|
|
Federation allows multiple SooSeF instances to exchange attestation records.
|
|
|
|
### Adding Federation Peers
|
|
|
|
**Through the web UI:** Go to `/federation/`, click **Add Peer**, enter the peer's URL
|
|
and Ed25519 fingerprint.
|
|
|
|
**Through the CLI or peer_store:**
|
|
|
|
```bash
|
|
# Peers are managed via the web UI or programmatically through PeerStore
|
|
```
|
|
|
|
### Trust Key Exchange
|
|
|
|
Before two organizations can federate, exchange public keys:
|
|
|
|
1. Export your public key: `cp ~/.soosef/identity/public.pem /media/usb/our-pubkey.pem`
|
|
2. Give it to the partner organization (physical handoff or secure channel)
|
|
3. Import their key: `soosef keys trust --import /media/usb/their-pubkey.pem`
|
|
4. Verify fingerprints out-of-band
|
|
|
|
### Exporting Attestation Bundles
|
|
|
|
```bash
|
|
# Export all records
|
|
$ soosef chain export --output /media/usb/bundle.zip
|
|
|
|
# Export a specific range
|
|
$ soosef chain export --start 100 --end 200 --output /media/usb/bundle.zip
|
|
|
|
# Export filtered by investigation
|
|
# (investigation tag is set during attestation)
|
|
```
|
|
|
|
### Importing Attestation Bundles
|
|
|
|
On the receiving instance, imported records are:
|
|
- Verified against the trust store (untrusted signers are rejected)
|
|
- Deduplicated by SHA-256 (existing records are skipped)
|
|
- Tagged with `federated_from` metadata
|
|
- Acknowledged via a delivery-ack chain record (two-way handshake)
|
|
|
|
### Gossip Sync (Tier 2 <-> Tier 3)
|
|
|
|
If the Tier 2 server and Tier 3 relay have network connectivity, gossip sync runs
|
|
automatically at the configured interval (default: 60 seconds, set via
|
|
`VERISOO_GOSSIP_INTERVAL` environment variable).
|
|
|
|
Gossip flow:
|
|
1. Nodes exchange Merkle roots
|
|
2. If roots differ, request consistency proof
|
|
3. Fetch missing records
|
|
4. Append to local log
|
|
|
|
Monitor sync status at `/federation/` in the web UI.
|
|
|
|
### Airgapped Federation
|
|
|
|
All federation is designed for sneakernet operation:
|
|
|
|
1. Export bundle to USB on sending instance
|
|
2. Physically carry USB to receiving instance
|
|
3. Import bundle
|
|
4. Optionally export delivery acknowledgment back on USB
|
|
|
|
No network connectivity is required at any point.
|
|
|
|
---
|
|
|
|
## 6. Chain and Anchoring
|
|
|
|
### Chain Verification
|
|
|
|
Verify the full chain periodically:
|
|
|
|
```bash
|
|
$ soosef chain verify
|
|
```
|
|
|
|
This checks all hash linkage and Ed25519 signatures. It also verifies key rotation
|
|
records and tracks authorized signers.
|
|
|
|
### Timestamp Anchoring
|
|
|
|
Anchor the chain head to prove it existed before a given time:
|
|
|
|
```bash
|
|
# Automated (requires network)
|
|
$ soosef chain anchor --tsa https://freetsa.org/tsr
|
|
|
|
# Manual (prints hash for external submission)
|
|
$ soosef chain anchor
|
|
```
|
|
|
|
A single anchor implicitly timestamps every prior record (the chain is append-only).
|
|
|
|
**When to anchor:**
|
|
- Before sharing evidence with third parties
|
|
- At regular intervals (daily or weekly)
|
|
- Before key rotation
|
|
- Before and after major investigations
|
|
|
|
### Selective Disclosure
|
|
|
|
For legal discovery or court orders, produce a proof showing specific records while
|
|
keeping others redacted:
|
|
|
|
```bash
|
|
$ soosef chain disclose -i 42,43,44 -o disclosure.json
|
|
```
|
|
|
|
The output includes full records for selected indices and hash-only entries for everything
|
|
else. A third party can verify the selected records are part of an unbroken chain.
|
|
|
|
---
|
|
|
|
## 7. Evidence Preservation
|
|
|
|
### Evidence Packages
|
|
|
|
For handing evidence to lawyers, courts, or organizations without SooSeF:
|
|
|
|
Self-contained ZIP containing original images, attestation records, chain data, your
|
|
public key, a standalone `verify.py`, and a README. The recipient verifies with:
|
|
|
|
```bash
|
|
$ pip install cryptography
|
|
$ python verify.py
|
|
```
|
|
|
|
### Cold Archives
|
|
|
|
For long-term preservation (10+ year horizon), OAIS-aligned:
|
|
|
|
Full state export including chain binary, attestation log, LMDB index, anchors, public
|
|
key, trusted keys, optional encrypted key bundle, `ALGORITHMS.txt`, and `verify.py`.
|
|
|
|
**When to create cold archives:**
|
|
- Weekly or monthly as part of backup strategy
|
|
- Before key rotation or travel
|
|
- When archiving a completed investigation
|
|
|
|
Store on at least two separate physical media in different locations.
|
|
|
|
---
|
|
|
|
## 8. Monitoring and Health
|
|
|
|
### Health Endpoint
|
|
|
|
```bash
|
|
# Web UI
|
|
$ curl -k https://127.0.0.1:5000/health
|
|
|
|
# Federation API
|
|
$ curl http://localhost:8000/health
|
|
```
|
|
|
|
Returns capabilities (stego-lsb, stego-dct, attest, fieldkit, chain).
|
|
|
|
### System Status
|
|
|
|
```bash
|
|
$ soosef status --json
|
|
```
|
|
|
|
Checks: identity key, channel key, chain integrity, dead man's switch state, backup
|
|
status, geofence, trusted keys.
|
|
|
|
### Docker Monitoring
|
|
|
|
```bash
|
|
# Service status
|
|
$ docker compose ps
|
|
|
|
# Logs
|
|
$ docker compose logs -f server
|
|
|
|
# Resource usage
|
|
$ docker stats
|
|
```
|
|
|
|
The Docker images include `HEALTHCHECK` directives that poll `/health` every 30 seconds.
|
|
|
|
---
|
|
|
|
## 9. Incident Response
|
|
|
|
### Device Seizure (Imminent)
|
|
|
|
1. Trigger killswitch: `soosef fieldkit purge --confirm CONFIRM-PURGE`
|
|
2. For Tier 1 USB: pull the USB stick and destroy it physically if possible
|
|
3. Verify with a separate device that federation copies are intact
|
|
|
|
### Device Seizure (After the Fact)
|
|
|
|
1. Assume all local data is compromised
|
|
2. Verify Tier 2/3 copies of attestation data
|
|
3. Generate new keys on a fresh instance
|
|
4. Record a key recovery event in the chain (if the old chain is still accessible)
|
|
5. Notify all collaborators to update their trust stores
|
|
|
|
### Federation Peer Compromise
|
|
|
|
1. The compromised peer has attestation metadata (hashes, signatures, timestamps) but not
|
|
decrypted content
|
|
2. Remove the peer from your peer list (`/federation/` > Remove Peer)
|
|
3. Assess what metadata exposure means for your organization
|
|
4. Consider whether attestation patterns reveal sensitive information
|
|
|
|
### Dead Man's Switch Triggered Accidentally
|
|
|
|
Data is gone. Restore from the most recent backup:
|
|
|
|
```bash
|
|
$ soosef init
|
|
$ soosef keys import -b /media/usb/backup.enc
|
|
```
|
|
|
|
Federation copies of attestation data are unaffected. Local attestations created since
|
|
the last federation sync or backup are lost.
|
|
|
|
---
|
|
|
|
## 10. Maintenance Tasks
|
|
|
|
### Regular Schedule
|
|
|
|
| Task | Frequency | Command |
|
|
|---|---|---|
|
|
| Check system status | Daily | `soosef status` |
|
|
| Check in (if deadman armed) | Per interval | `soosef fieldkit checkin` |
|
|
| Backup keys | Per `backup_reminder_days` | `soosef keys export` |
|
|
| Verify chain integrity | Weekly | `soosef chain verify` |
|
|
| Anchor chain | Weekly | `soosef chain anchor` |
|
|
| Review drop box submissions | As needed | `/dropbox/admin` |
|
|
| Clean temp files | Monthly | Remove processed files from `~/.soosef/temp/` |
|
|
| Create cold archive | Monthly | Export via CLI or web |
|
|
| Update SooSeF | As releases are available | `pip install --upgrade soosef` |
|
|
|
|
### Docker Volume Backup
|
|
|
|
```bash
|
|
$ docker compose stop server
|
|
$ docker run --rm -v server-data:/data -v /backup:/backup \
|
|
busybox tar czf /backup/soosef-$(date +%Y%m%d).tar.gz -C /data .
|
|
$ docker compose start server
|
|
```
|
|
|
|
### Log Rotation
|
|
|
|
`audit.jsonl` grows indefinitely. On long-running Tier 2 servers, archive old entries
|
|
periodically. The audit log is append-only; truncate by copying the tail:
|
|
|
|
```bash
|
|
$ tail -n 10000 ~/.soosef/audit.jsonl > ~/.soosef/audit.jsonl.tmp
|
|
$ mv ~/.soosef/audit.jsonl.tmp ~/.soosef/audit.jsonl
|
|
```
|
|
|
|
> **Warning**: Truncating the audit log removes historical records. Archive the full
|
|
> file before truncating if you need the history for compliance or legal purposes.
|