diff --git a/lifecycle-and-vulnerability-management.md b/lifecycle-and-vulnerability-management.md new file mode 100644 index 0000000..7757ea5 --- /dev/null +++ b/lifecycle-and-vulnerability-management.md @@ -0,0 +1,144 @@ +# Internet-Facing Stack Lifecycle & Vulnerability Management + +_Last updated: 2026-04-07 (UTC)_ + +## 1) Internet-facing application inventory (app, version, image digest) + +> Source of truth for internet-facing targets: `results/*` host folders and their WhatWeb outputs. +> Operational owner must replace all `TBD` digest values with runtime evidence from `docker image inspect`/`docker ps --no-trunc`. + +| Host/FQDN | Product/App | Deployed version evidence | Container image (repo:tag) | Image digest (sha256) | Evidence source | +|---|---|---|---|---|---| +| auth.lan.ddnsgeek.com | Authelia (auth portal) | Version not fingerprinted from external scan | TBD | TBD | `results/auth.../tcp_443_https_whatweb.txt` | +| edge.lan.ddnsgeek.com | Edge reverse-proxy/app entrypoint | Version not fingerprinted from external scan | TBD | TBD | `results/edge.../tcp_443_https_whatweb.txt` | +| familytree.lan.ddnsgeek.com | FamilyTree app (gunicorn-backed) | gunicorn detected, app version not fingerprinted | TBD | TBD | `results/familytree.../tcp_443_https_whatweb.txt` | +| gitea.lan.ddnsgeek.com | Gitea | Gitea detected; exact version not fingerprinted | TBD | TBD | `results/gitea.../tcp_443_https_whatweb.txt` | +| gotify.lan.ddnsgeek.com | Gotify | Version not fingerprinted from external scan | TBD | TBD | `results/gotify.../tcp_443_https_whatweb.txt` | +| grafana.lan.ddnsgeek.com | Grafana | Grafana login redirect observed; exact version not fingerprinted | TBD | TBD | `results/grafana.../tcp_443_https_whatweb.txt` | +| influxdb.lan.ddnsgeek.com | InfluxDB (behind auth) | Version not fingerprinted from external scan | TBD | TBD | `results/influxdb.../tcp_443_https_whatweb.txt` | +| kuma.lan.ddnsgeek.com | Uptime Kuma | Dashboard redirect observed; exact version not fingerprinted | TBD | TBD | `results/kuma.../tcp_443_https_whatweb.txt` | +| monitor-kuma.lan.ddnsgeek.com | Uptime Kuma (monitoring endpoint) | Dashboard redirect observed; exact version not fingerprinted | TBD | TBD | `results/monitor-kuma.../tcp_443_https_whatweb.txt` | +| nextcloud.lan.ddnsgeek.com | Nextcloud (Apache/PHP stack) | Apache 2.4.66, PHP 8.3.30 | TBD | TBD | `results/nextcloud.../tcp_443_https_whatweb.txt` | +| node-red.lan.ddnsgeek.com | Node-RED (behind auth) | Version not fingerprinted from external scan | TBD | TBD | `results/node-red.../tcp_443_https_whatweb.txt` | +| passbolt.lan.ddnsgeek.com | Passbolt | NGINX detected; exact Passbolt version not fingerprinted | TBD | TBD | `results/passbolt.../tcp_443_https_whatweb.txt` | +| portainer.lan.ddnsgeek.com | Portainer | Portainer detected; exact version not fingerprinted | TBD | TBD | `results/portainer.../tcp_443_https_whatweb.txt` | +| prometheus.lan.ddnsgeek.com | Prometheus (behind auth) | Version not fingerprinted from external scan | TBD | TBD | `results/prometheus.../tcp_443_https_whatweb.txt` | +| searxng.lan.ddnsgeek.com | SearXNG | `searxng/2026.4.5+474b0a55b` detected | TBD | TBD | `results/searxng.../tcp_443_https_whatweb.txt` | +| shifts.lan.ddnsgeek.com | Shifts app (nginx front-end) | nginx 1.29.7 | TBD | TBD | `results/shifts.../tcp_443_https_whatweb.txt` | +| stockfill.lan.ddnsgeek.com | Stockfill app (nginx front-end) | nginx 1.27.5 | TBD | TBD | `results/stockfill.../tcp_443_https_whatweb.txt` | +| traefik.lan.ddnsgeek.com | Traefik (behind auth) | Version not fingerprinted from external scan | TBD | TBD | `results/traefik.../tcp_443_https_whatweb.txt` | + +### Required evidence commands (run on Docker host) + +```bash +# Capture deployed containers with immutable image digest references +sudo docker ps --format '{{.Names}}\t{{.Image}}' --no-trunc + +# Resolve image digests for inventory table +sudo docker image inspect --format '{{index .RepoDigests 0}}' + +# Optional: export inventory as CSV for compliance tracking +sudo docker ps --format '{{.Names}},{{.Image}}' --no-trunc > internet-facing-runtime-images.csv +``` + +--- + +## 2) Monthly update window definition + +## Standard cadence +- **Window:** Second Tuesday of every month, **02:00–06:00 UTC**. +- **Fallback window:** Second Wednesday of every month, **02:00–06:00 UTC**. +- **Emergency patch window (critical CVE only):** within **48 hours** of advisory triage. + +## Scope per window +1. **OS packages** (host + VM base images): apply security and bugfix updates. +2. **Container base images**: rebuild/pull fresh immutable digests. +3. **Application releases**: patch/minor upgrades for internet-facing apps. + +## Freeze and exception policy +- No deferral beyond one cycle without documented risk acceptance. +- Critical internet-facing CVEs (remote exploitable) cannot wait for the next regular window. + +--- + +## 3) Pre-production smoke checks for critical apps + +All updates must be promoted through pre-prod first. Minimum smoke checks: + +### Nextcloud +- Login page loads. +- Test user login succeeds. +- File upload + download round trip succeeds. +- Background jobs/cron status healthy. + +### Passbolt +- Login page loads. +- Browser extension/API auth succeeds. +- Secret create/read/update works for test vault. +- Email/notification queue healthy. + +### Gitea +- Login succeeds. +- Repository clone + push with test repo succeeds. +- Webhook test delivery succeeds. +- Actions/runner (if enabled) executes sample workflow. + +### Grafana +- Login succeeds. +- Datasource health checks pass. +- Key dashboards render without panel errors. +- Alert rule evaluation pipeline healthy. + +### Shared gate for all critical apps +- HTTPS endpoint returns expected status. +- No new high/critical findings in pre-prod vulnerability scan. +- Error budget/SLO smoke threshold respected for 30 minutes post-deploy. + +--- + +## 4) CVE advisory tracking mapped to deployed versions + +Create/maintain a single register (`cve-register.csv` or ticket board) with these required fields: + +- Product +- Deployed version +- Deployed image digest +- CVE ID +- CVSS score/severity +- Advisory source URL +- Affected version range +- Exploit status (known exploited: yes/no) +- Mitigation owner +- Target fix version +- Due date +- Status (Open / In-progress / Pending validation / Resolved) + +### Advisory sources (minimum) +- Vendor advisories/release notes for each product (Nextcloud, Passbolt, Gitea, Grafana, etc.) +- NVD +- CISA KEV catalog (for known exploited CVEs) + +### Mapping rule +A CVE can only be marked “Not Affected” when the deployed version + digest is proven outside vulnerable ranges with evidence attached. + +--- + +## 5) Closure evidence requirement (hard gate) + +A vulnerability ticket is only closed when **both** conditions are met: + +1. **Version or digest changed in production** + - Before/after evidence attached (`docker image inspect`, deployment manifest diff, or SBOM diff). +2. **Post-update scan is clean for that CVE** + - Re-scan target service and attach artifact proving CVE no longer detected. + +### Mandatory closure artifacts +- Screenshot/export of runtime version and image digest after deployment. +- Linked change request/deployment ID. +- Post-update vulnerability scan report. +- Smoke-test checklist execution evidence. + +### Status workflow +`Open -> Planned -> In Progress -> Pending Validation -> Resolved` + +`Resolved` is prohibited unless both hard-gate conditions above are satisfied.