Enhance API with OIDC support, including login and callback endpoints. Update environment variables for OIDC configuration in .env.example. Add new features to the catalog service for listing software families, Minecraft versions, and deployment regions. Implement server management actions such as kill, delete, and update in the servers module. Integrate feature flags for maintenance mode in server operations. Update pnpm-lock.yaml with new dependencies and versions.
This commit is contained in:
9
docs/security/backup-encryption.md
Normal file
9
docs/security/backup-encryption.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Backup Encryption at Rest
|
||||
|
||||
GameCloud backups are stored in S3-compatible object storage. Production deployments should enable:
|
||||
|
||||
1. **Bucket SSE** — Server-side encryption (AES-256) on the backup bucket
|
||||
2. **Application envelope encryption** (roadmap) — Per-backup data keys wrapped with `ENCRYPTION_KEY`
|
||||
3. **Key rotation** — Documented in `docs/security/secrets.md`
|
||||
|
||||
Current MVP stores backups without client-side encryption. Enable bucket policies before production.
|
||||
14
docs/security/container-hardening.md
Normal file
14
docs/security/container-hardening.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Container Hardening
|
||||
|
||||
The node-agent applies baseline Docker hardening:
|
||||
|
||||
- `cap_drop: ALL` with minimal adds
|
||||
- `security_opt: no-new-privileges`
|
||||
- PID limits and log rotation
|
||||
|
||||
## Roadmap (Post-MVP)
|
||||
|
||||
- **Seccomp** — Custom profile per software family under `deploy/seccomp/`
|
||||
- **AppArmor** — Node-level profiles for game server containers
|
||||
|
||||
See `apps/node-agent/internal/docker/client.go` for current defaults.
|
||||
71
docs/security/container-isolation.md
Normal file
71
docs/security/container-isolation.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Container isolation
|
||||
|
||||
How HexaHost GameCloud isolates Minecraft server workloads on game nodes.
|
||||
|
||||
## Model
|
||||
|
||||
Each customer server runs as a **non-privileged Docker container** on a dedicated game node. The node-agent creates and manages containers; customers never receive Docker socket access.
|
||||
|
||||
```
|
||||
Control plane (trusted) ──mTLS──► Node agent (trusted) ──► Game container (untrusted)
|
||||
```
|
||||
|
||||
## Container hardening (target profile)
|
||||
|
||||
| Control | Setting |
|
||||
|---------|---------|
|
||||
| User | Non-root UID inside container |
|
||||
| Privileges | `--privileged=false` |
|
||||
| Capabilities | Drop ALL, add only required (none for vanilla Java) |
|
||||
| seccomp | Docker default or custom profile (Phase 2) |
|
||||
| AppArmor | Docker default profile |
|
||||
| Network | Bridge network per server; no `host` network mode |
|
||||
| Read-only root | Where compatible with selected software family |
|
||||
| Memory / CPU | cgroup limits from plan slug |
|
||||
| PIDs limit | Prevents fork bombs |
|
||||
|
||||
## Network isolation
|
||||
|
||||
- Game containers reach the internet for Minecraft auth and mod downloads only through controlled egress
|
||||
- No route to control plane PostgreSQL, Redis, or internal APIs
|
||||
- Node-agent management port (`9100`) bound to localhost or management VLAN only
|
||||
|
||||
See threat T05 and T12 in [threat model](threat-model.md).
|
||||
|
||||
## Storage isolation
|
||||
|
||||
- Per-server data directory on node disk: `/var/lib/hgc-node/servers/{serverId}/`
|
||||
- Path traversal prevented server-side; symlinks rejected on archive extract
|
||||
- Backups uploaded to object storage — not readable by other tenants
|
||||
|
||||
## Image policy
|
||||
|
||||
- Only catalog-approved runtime images (digest-pinned)
|
||||
- Customers cannot push custom images
|
||||
- Periodic image vulnerability scan in CI (Phase 9)
|
||||
|
||||
## Multi-tenant on one node
|
||||
|
||||
The scheduler enforces RAM and server count limits per node. There is no shared filesystem between server containers except the read-only image layers.
|
||||
|
||||
## Operator responsibilities
|
||||
|
||||
| Task | Frequency |
|
||||
|------|-----------|
|
||||
| Docker security updates on nodes | Monthly |
|
||||
| Review AppArmor/seccomp profiles after Minecraft/Java major bumps | Per release |
|
||||
| Audit `docker ps` for unexpected privileged containers | Weekly |
|
||||
|
||||
Bootstrap hardening via `deploy/ansible/game-node.yml`.
|
||||
|
||||
## Verification
|
||||
|
||||
- Attempt cross-container network scan from test server (should fail to reach agent port)
|
||||
- Confirm `docker inspect` shows `Privileged: false`
|
||||
- Penetration test before production go-live
|
||||
|
||||
## Related
|
||||
|
||||
- [Threat model](threat-model.md)
|
||||
- [Game node operations](../operations/game-node.md)
|
||||
- [Secrets](secrets.md)
|
||||
66
docs/security/data-retention.md
Normal file
66
docs/security/data-retention.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Data retention
|
||||
|
||||
Retention periods and deletion procedures for HexaHost GameCloud customer and operational data.
|
||||
|
||||
## Policy summary
|
||||
|
||||
| Data type | Retention | Deletion trigger |
|
||||
|-----------|-----------|------------------|
|
||||
| Account profile | Life of account + 90 days | Account deletion request |
|
||||
| Game server world (live) | Life of service | Terminate in WHMCS / admin |
|
||||
| Automated backups | Per plan (7–30 days default) | Lifecycle job + S3 expiry |
|
||||
| Manual backup downloads | Link valid 24 h; object 7 days | Worker cleanup |
|
||||
| Audit log | 24 months | Scheduled purge job |
|
||||
| Application logs (Loki) | 30 days (`720h` in loki-config) | Loki compactor |
|
||||
| Session tokens | 7 days idle / 30 days max | Redis TTL |
|
||||
| WHMCS sync events | 90 days acknowledged | Addon retention SQL |
|
||||
| DNS record history | 12 months | DB maintenance |
|
||||
| Metering / usage samples | 13 months (billing) | Aggregated then purged |
|
||||
|
||||
Adjust periods in contracts and WHMCS product terms. Document customer-facing retention in your privacy policy (German: *Datenschutzerklärung*).
|
||||
|
||||
## Backup retention
|
||||
|
||||
Backup objects live under `s3://{bucket}/backups/{serverId}/`. The worker applies plan-based retention:
|
||||
|
||||
- Free/starter plans: 7 daily slots
|
||||
- Pro plans: 14 daily + 4 weekly
|
||||
- Enterprise: configurable via admin
|
||||
|
||||
Expired backups are deleted from object storage; metadata rows in PostgreSQL are soft-deleted then purged after 7 days.
|
||||
|
||||
## Termination flow
|
||||
|
||||
When WHMCS calls `TerminateAccount`:
|
||||
|
||||
1. Server stopped on node
|
||||
2. Final backup optional (plan-dependent)
|
||||
3. World data on node deleted within 24 h
|
||||
4. S3 prefix `backups/{serverId}/` deleted within 7 days
|
||||
5. PostgreSQL server row anonymised or hard-deleted per legal requirement
|
||||
|
||||
## GDPR / DSGVO considerations
|
||||
|
||||
- **Right to erasure:** Export then delete user row; cascade removes owned servers
|
||||
- **Data portability:** World export ZIP + backup download via panel
|
||||
- **Processor agreement:** Required between you (controller) and HexaHost GameCloud operator if different entity
|
||||
|
||||
Logs may contain IP addresses and user IDs — treat as personal data where applicable.
|
||||
|
||||
## Operational data
|
||||
|
||||
| Store | Purge method |
|
||||
|-------|--------------|
|
||||
| PostgreSQL audit | `DELETE FROM audit_events WHERE created_at < NOW() - INTERVAL '24 months'` (automated job) |
|
||||
| Redis | TTL-based; no long-term PII |
|
||||
| MinIO access logs | Provider lifecycle rule |
|
||||
|
||||
## Legal hold
|
||||
|
||||
Suspend automated deletion for accounts under litigation hold. Flag in admin metadata; worker skips purge for affected `serverId`.
|
||||
|
||||
## Related
|
||||
|
||||
- [Backup and restore](../operations/backup-restore.md)
|
||||
- [Object storage](../operations/object-storage.md)
|
||||
- [Threat model](threat-model.md) — T16 backup integrity
|
||||
95
docs/security/secrets.md
Normal file
95
docs/security/secrets.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# Secrets management
|
||||
|
||||
Guidelines for generating, storing, and rotating secrets in HexaHost GameCloud deployments.
|
||||
|
||||
## Classification
|
||||
|
||||
| Secret | Location | Rotation |
|
||||
|--------|----------|----------|
|
||||
| `SESSION_SECRET` | `.env.prod` on control plane | Quarterly; invalidates sessions |
|
||||
| `ENCRYPTION_KEY` | `.env.prod` | Annually; requires re-encryption plan |
|
||||
| `POSTGRES_PASSWORD` | `.env.prod`, compose | Annually |
|
||||
| `S3_ACCESS_KEY` / `S3_SECRET_KEY` | `.env.prod`, MinIO IAM | Quarterly |
|
||||
| `WHMCS_API_SECRET` | GameCloud `.env.prod` + WHMCS addon | On compromise; per installation |
|
||||
| `WHMCS_WEBHOOK_SECRET` | Both sides | On compromise |
|
||||
| `NODE_TOKEN` | Per-node enrollment | One-time at enroll; rotate on rebuild |
|
||||
| Node mTLS keys | `/etc/hgc-node/` on game nodes | Before cert expiry |
|
||||
| `EDGE_INTERNAL_API_KEY` | Edge gateway + API | Quarterly |
|
||||
| `RFC2136_KEY_SECRET` | API/worker env | Annually |
|
||||
| `STRIPE_*` | API env (if used) | Per Stripe dashboard policy |
|
||||
| Traefik `acme.json` | `/letsencrypt/` | Auto-renewed; backup only |
|
||||
|
||||
## Generation
|
||||
|
||||
```bash
|
||||
# 32-byte secrets (SESSION_SECRET, ENCRYPTION_KEY, API secrets)
|
||||
openssl rand -base64 32
|
||||
|
||||
# WHMCS integration — minimum 32 characters
|
||||
openssl rand -hex 24
|
||||
```
|
||||
|
||||
Never use development defaults from `.env.example` in production.
|
||||
|
||||
## Storage rules
|
||||
|
||||
1. **Never commit** `.env`, `.env.prod`, or key material to git
|
||||
2. Restrict file permissions: `chmod 600 .env.prod`, owner `gamecloud`
|
||||
3. Prefer secret manager (HashiCorp Vault, SOPS, cloud provider SM) over plain files for multi-host
|
||||
4. Ansible: use `ansible-vault` for inventory secrets referenced in `deploy/ansible/`
|
||||
|
||||
## Distribution
|
||||
|
||||
| From | To | Channel |
|
||||
|------|-----|---------|
|
||||
| Operator | Control plane | SSH + encrypted archive |
|
||||
| Control plane | WHMCS admin | Out-of-band (password manager share) |
|
||||
| Control plane | Game node | Enrollment token via secure ticket |
|
||||
|
||||
WHMCS **Integration ID** is not secret but must match exactly on both sides.
|
||||
|
||||
## Rotation procedures
|
||||
|
||||
### SESSION_SECRET
|
||||
|
||||
1. Generate new value
|
||||
2. Update `.env.prod`, restart `api` and `web`
|
||||
3. All users must log in again
|
||||
|
||||
### WHMCS_API_SECRET
|
||||
|
||||
1. Update GameCloud `.env.prod` and restart API
|
||||
2. Update WHMCS addon **API Secret** immediately after — expect brief auth failures
|
||||
3. No WHMCS module reinstall required
|
||||
|
||||
### Database password
|
||||
|
||||
1. `ALTER USER gamecloud PASSWORD '...'` in PostgreSQL
|
||||
2. Update `DATABASE_URL` / `POSTGRES_PASSWORD` in `.env.prod`
|
||||
3. Restart `api`, `worker`
|
||||
|
||||
### Node token compromise
|
||||
|
||||
1. Revoke token in admin API for affected `NODE_ID`
|
||||
2. Issue new enrollment token
|
||||
3. Reinstall node-agent with new token and fresh mTLS cert
|
||||
|
||||
## Logging and redaction
|
||||
|
||||
- Structured logs must not print env dumps or Authorization headers
|
||||
- WHMCS module calls redact `password`, `secret`, `apiSecret` in module logs
|
||||
- OpenTelemetry spans must not include query strings with tokens
|
||||
|
||||
## Development vs production
|
||||
|
||||
| Variable | Development | Production |
|
||||
|----------|-------------|------------|
|
||||
| `INTEGRATION_MTLS_ENABLED` | `false` | `true` (recommended) |
|
||||
| `NODE_TLS_SKIP_VERIFY` | `true` | `false` |
|
||||
| Default MinIO credentials | Allowed | **Forbidden** |
|
||||
|
||||
## Related
|
||||
|
||||
- [Threat model](threat-model.md)
|
||||
- [WHMCS security](../integrations/whmcs/security.md)
|
||||
- [Data retention](data-retention.md)
|
||||
Reference in New Issue
Block a user