From 4577a1d7e4225fc5d59e3556c8311508e97bf4e9 Mon Sep 17 00:00:00 2001 From: Username Date: Wed, 24 Dec 2025 20:05:30 +0100 Subject: [PATCH] docs: update for systemd and rate limit headers --- PROJECT.md | 6 ++-- ROADMAP.md | 14 +++++--- TODO.md | 5 +-- documentation/deployment.md | 71 ++++++++++++++++++++++--------------- 4 files changed, 57 insertions(+), 39 deletions(-) diff --git a/PROJECT.md b/PROJECT.md index 523716a..540de09 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -81,7 +81,6 @@ A self-hosted pastebin API that: - Syntax highlighting - Paste forking / versioning - Public paste listing / discovery -- Rate limiting per IP (delegated to reverse proxy) - Multi-node clustering / distributed storage - Alternative storage backends (S3, PostgreSQL) @@ -135,7 +134,7 @@ A self-hosted pastebin API that: │ Content-hash deduplication │ Complete │ Proof-of-work │ Complete │ Anti-flood (dynamic PoW) │ Complete -│ IP-based rate limiting │ Complete +│ IP-based rate limiting │ Complete (with X-RateLimit-* headers) │ URL prefix support │ Complete │ /client endpoint │ Complete │ E2E encryption (CLI) │ Complete @@ -151,6 +150,7 @@ A self-hosted pastebin API that: │ CLI paste listing/search │ Complete │ Public certificate registration │ Complete │ CLI register command │ Complete -│ Test suite │ 216 tests passing +│ systemd deployment │ Complete (security-hardened) +│ Test suite │ 284 tests passing └─────────────────────────────────┴────────────────────────────────────────────┘ ``` diff --git a/ROADMAP.md b/ROADMAP.md index f69a859..70243c0 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,7 +12,7 @@ FlaskPaste v1.5.0 is deployed with comprehensive security hardening and abuse pr - Content-hash deduplication (abuse prevention) - Proof-of-work spam prevention - Anti-flood system (dynamic PoW difficulty under load) -- IP-based rate limiting (configurable per-IP limits) +- IP-based rate limiting with X-RateLimit-* headers - Entropy enforcement (require encrypted uploads) - E2E encryption in CLI (AES-256-GCM, key in URL fragment) - URL prefix support for reverse proxy deployments @@ -23,12 +23,13 @@ FlaskPaste v1.5.0 is deployed with comprehensive security hardening and abuse pr - Scheduled cleanup (pastes, hashes, rate limits) - Security headers and request tracing - Container deployment support +- systemd service unit with security hardening - Security tooling (ruff, bandit, mypy, pip-audit) - CI/CD pipeline with lint, security, and test jobs - CLI with list, search, update, export commands - Public certificate registration (PoW-protected) - CLI register command for certificate enrollment -- Comprehensive test suite (283 tests) +- Comprehensive test suite (284 tests) - PKI audit logging (certificate lifecycle events) - Request duration metrics (Prometheus histogram) - Memory leak detection in CI pipeline @@ -119,9 +120,10 @@ Focus: Integration with external systems. ├───┼─────────────────────────────────┼────────────────────────────────────┤ │ 1 │ CLI client (fpaste) │ Done (with E2E + PKI) │ 2 │ /client endpoint │ Done (downloadable CLI) -│ 3 │ Ansible deployment role │ Planned -│ 4 │ Kubernetes manifests │ Planned -│ 5 │ Shell aliases/functions │ Planned +│ 3 │ systemd service unit │ Done (with security hardening) +│ 4 │ Ansible deployment role │ Planned +│ 5 │ Kubernetes manifests │ Planned +│ 6 │ Shell aliases/functions │ Planned └───┴─────────────────────────────────┴────────────────────────────────────┘ ``` @@ -184,6 +186,8 @@ These features will not be implemented: | 2024-12 | PKI audit logging | Full certificate lifecycle traceability | 2024-12 | Request duration metrics | Prometheus histogram for observability | 2024-12 | Memory leak CI job | tracemalloc-based leak detection in CI +| 2024-12 | systemd service unit | Security-hardened deployment example +| 2024-12 | Rate limit headers | X-RateLimit-* on 201/429 responses ## Review Schedule diff --git a/TODO.md b/TODO.md index f4df872..c72bbc2 100644 --- a/TODO.md +++ b/TODO.md @@ -6,7 +6,6 @@ Unstructured intake buffer for ideas, issues, and observations. Items here are r ## Ideas -- Rate limit headers in responses (X-RateLimit-*) - Paste compression for large text content - ETag support for conditional requests - Neovim/Vim plugin for editor integration @@ -27,6 +26,8 @@ Unstructured intake buffer for ideas, issues, and observations. Items here are r - PKI audit events now logged: CERT_ISSUED, CERT_REVOKED, AUTH_FAILURE - Request duration metrics recorded via Prometheus histogram - Memory leak tests use tracemalloc to detect leaks (CI job) +- Rate limit headers (X-RateLimit-*) on both 201 and 429 responses +- systemd service unit with security hardening in examples/ ## Questions @@ -40,7 +41,7 @@ Unstructured intake buffer for ideas, issues, and observations. Items here are r ## Debt - Mypy has pre-existing type errors (runs with --ignore-missing-imports) -- Could add more deployment examples (Kubernetes, systemd) +- Could add more deployment examples (Kubernetes, Ansible role) ## External Dependencies diff --git a/documentation/deployment.md b/documentation/deployment.md index 194477f..dbc3b71 100644 --- a/documentation/deployment.md +++ b/documentation/deployment.md @@ -58,38 +58,37 @@ gunicorn \ ### Systemd Service -Create `/etc/systemd/system/flaskpaste.service`: - -```ini -[Unit] -Description=FlaskPaste Pastebin Service -After=network.target - -[Service] -Type=notify -User=flaskpaste -Group=flaskpaste -RuntimeDirectory=flaskpaste -WorkingDirectory=/opt/flaskpaste -Environment="FLASK_ENV=production" -Environment="FLASKPASTE_DB=/var/lib/flaskpaste/pastes.db" -ExecStart=/opt/flaskpaste/venv/bin/gunicorn \ - --workers 4 \ - --bind unix:/run/flaskpaste/gunicorn.sock \ - wsgi:app -ExecReload=/bin/kill -s HUP $MAINPID -Restart=on-failure -RestartSec=5 - -[Install] -WantedBy=multi-user.target -``` +Use the provided examples in `examples/`: ```bash +# Create service user +sudo useradd -r -s /sbin/nologin flaskpaste + +# Copy application +sudo mkdir -p /opt/flaskpaste/data +sudo cp -r . /opt/flaskpaste/ +sudo chown -R flaskpaste:flaskpaste /opt/flaskpaste + +# Copy service unit (with security hardening) +sudo cp examples/flaskpaste.service /etc/systemd/system/ + +# Copy and secure environment file +sudo mkdir -p /etc/flaskpaste +sudo cp examples/flaskpaste.env /etc/flaskpaste/env +sudo chmod 600 /etc/flaskpaste/env + +# Enable and start sudo systemctl daemon-reload sudo systemctl enable --now flaskpaste ``` +The provided service unit includes security hardening: +- `NoNewPrivileges`, `PrivateTmp`, `ProtectSystem=strict` +- `MemoryDenyWriteExecute`, `RestrictNamespaces` +- Resource limits and restart policies + +See `examples/flaskpaste.service` for the full configuration. + --- ## Production: Container Deployment @@ -277,6 +276,8 @@ podman run --rm \ ## Environment Variables +See `examples/flaskpaste.env` for a complete template. + | Variable | Default | Description | |----------|---------|-------------| | `FLASK_ENV` | `development` | Set to `production` in production | @@ -284,15 +285,23 @@ podman run --rm \ | `FLASKPASTE_ID_LENGTH` | `12` | Paste ID length (hex chars) | | `FLASKPASTE_MAX_ANON` | `3145728` | Max anonymous paste (bytes) | | `FLASKPASTE_MAX_AUTH` | `52428800` | Max authenticated paste (bytes) | -| `FLASKPASTE_EXPIRY` | `432000` | Paste expiry (seconds) | -| `FLASKPASTE_PROXY_SECRET` | (empty) | Shared secret for proxy trust validation | +| `FLASKPASTE_EXPIRY_ANON` | `86400` | Anonymous paste expiry (1 day) | +| `FLASKPASTE_EXPIRY_UNTRUSTED` | `604800` | Untrusted cert expiry (7 days) | +| `FLASKPASTE_EXPIRY_TRUSTED` | `2592000` | PKI-registered expiry (30 days) | +| `FLASKPASTE_PROXY_SECRET` | (empty) | Shared secret for proxy trust | +| `FLASKPASTE_POW_DIFFICULTY` | `20` | PoW difficulty (0=disabled) | +| `FLASKPASTE_RATE_LIMIT` | `1` | Enable IP-based rate limiting | +| `FLASKPASTE_RATE_MAX` | `10` | Max requests per window (anon) | +| `FLASKPASTE_RATE_AUTH_MULT` | `5` | Multiplier for authenticated users | +| `FLASKPASTE_ANTIFLOOD` | `1` | Enable dynamic PoW under attack | +| `FLASKPASTE_PKI_ENABLED` | `0` | Enable built-in PKI | --- ## Security Checklist - [ ] Run behind reverse proxy with TLS -- [ ] Use non-root user in containers +- [ ] Use non-root user (or systemd security hardening) - [ ] Set appropriate file permissions on database - [ ] Configure firewall (only expose reverse proxy) - [ ] Set `FLASK_ENV=production` @@ -300,6 +309,10 @@ podman run --rm \ - [ ] Set `FLASKPASTE_PROXY_SECRET` for defense-in-depth - [ ] Configure proxy to send `X-Proxy-Secret` header - [ ] Configure proxy to pass/generate `X-Request-ID` +- [ ] Enable rate limiting (`FLASKPASTE_RATE_LIMIT=1`) +- [ ] Enable anti-flood (`FLASKPASTE_ANTIFLOOD=1`) +- [ ] Enable PoW (`FLASKPASTE_POW_DIFFICULTY=20`) - [ ] Set up log rotation - [ ] Enable automatic backups - [ ] Monitor disk usage (paste storage) +- [ ] Monitor rate limit headers (`X-RateLimit-*`)