docs: record internal port loopback hardening
Some checks failed
pre-commit / pre-commit (push) Failing after 38s

This commit is contained in:
Hermes VM 2026-05-27 21:25:38 +00:00
parent 2fc23d6baa
commit d60c81ebda
2 changed files with 30 additions and 5 deletions

View File

@ -69,7 +69,7 @@ These listeners were bound on `0.0.0.0` and/or `[::]` during review.
| `3070` | `localmemgpt-web` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | none found in Caddy | `needs-decision` | Unhealthy; classify as private/admin or retire |
| `3075` | `llmlab-dashboard` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | `llmlab.bytelyst.com` | `private-admin` with direct bypass | Dashboard unhealthy; gate or retire |
| `3085` | `invttrdg-web` | `/opt/bytelyst/learning_ai_invt_trdg/docker-compose.yml` | `invttrdg.bytelyst.com` | `public-caddy` with direct bypass | Bind loopback or remove host port after Caddy smoke |
| `3100` | `loki` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | none found in Caddy | `private-admin` | Remove public host bind; keep Docker/internal or Tailscale only |
| `3100` | `loki` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | none found in Caddy | `loopback-only` | Bound to `127.0.0.1` on 2026-05-27 |
| `3300` | `gitea-npm-registry` | non-Compose container labels absent | `gitea.bytelyst.com` | `public-caddy` with direct bypass | Bind loopback or private; keep Caddy route |
| `4004` | `devops-backend` | `/opt/bytelyst/learning_ai_devops_tools/dashboard/docker-compose.yml` | `api.bytelyst.com/devops/*` | `private-admin` with direct bypass | Bind loopback/private |
| `4010` | `peakpulse-backend` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | `api.bytelyst.com/peakpulse/*` | `public-caddy` with direct bypass | Bind loopback or remove host port after Caddy smoke |
@ -83,10 +83,10 @@ These listeners were bound on `0.0.0.0` and/or `[::]` during review.
| `4019` | `localmemgpt-backend` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | `api.bytelyst.com/localmemgpt/*` | `public-caddy` with direct bypass | Bind loopback or remove host port after Caddy smoke |
| `4020` | `actiontrail-backend` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | `api.bytelyst.com/actiontrail/*` | `public-caddy` with direct bypass | Bind loopback or remove host port after Caddy smoke |
| `4025` | `invttrdg-backend` | `/opt/bytelyst/learning_ai_invt_trdg/docker-compose.yml` | `api.bytelyst.com/invttrdg/*` | `public-caddy` with direct bypass | Bind loopback or remove host port after Caddy smoke |
| `1025` | `mailpit` SMTP | `/root/bytelyst.ai/repos/learning_ai_common_plat/docker-compose.yml` | none found in Caddy | `private-admin` / `docker-internal` | Remove public host bind |
| `8025` | `mailpit` UI | `/root/bytelyst.ai/repos/learning_ai_common_plat/docker-compose.yml` | none found in Caddy | `private-admin` | Bind loopback/Tailscale or remove |
| `10000` | `azurite` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | none found in Caddy | `docker-internal` | Remove public host bind |
| `1234`, `8081` | `cosmos-emulator` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | none found in Caddy | `docker-internal` | Remove public host bind |
| `1025` | `mailpit` SMTP | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | none found in Caddy | `loopback-only` | Bound to `127.0.0.1` on 2026-05-27 |
| `8025` | `mailpit` UI | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | none found in Caddy | `loopback-only` | Bound to `127.0.0.1` on 2026-05-27 |
| `10000` | `azurite` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | none found in Caddy | `loopback-only` | Bound to `127.0.0.1` on 2026-05-27 |
| `1234`, `8081` | `cosmos-emulator` | `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` | none found in Caddy | `loopback-only` | Bound to `127.0.0.1` on 2026-05-27 |
| `11434` | `ollama` host process | host service | `ollama.bytelyst.com` | `private-admin` | Bind loopback/private or auth-gate; do not leave raw public |
## Non-Public / Internal Listeners

View File

@ -181,6 +181,7 @@ Effective `sshd -T` settings showed:
- [ ] Create a canonical exposure inventory: service, container, host port, public hostname, required audience, auth requirement.
- [ ] For each service, decide one of: public via Caddy, private via Tailscale/SSH, loopback-only host port, Docker-internal only, or remove.
- [ ] Bind non-public Compose ports to `127.0.0.1` or remove host port mapping entirely.
- [x] Internal emulator/mail/observability ports `1025`, `8025`, `10000`, `1234`, `8081`, and `3100` are loopback-bound.
- [ ] Add a `DOCKER-USER` chain policy to drop unsolicited traffic to non-approved published ports before Docker's accept rules.
- [ ] Keep only `80/443` and intentionally public SSH exposed at the provider/firewall layer.
- [ ] Add a recurring check that compares `ss -ltn` and Docker published ports against the approved inventory.
@ -389,6 +390,7 @@ Effective `sshd -T` settings showed:
### Phase 1 — Immediate security hardening
- [ ] Close or loopback-bind non-public Docker host ports.
- [x] Loopback-bound internal emulator/mail/observability ports `1025`, `8025`, `10000`, `1234`, `8081`, and `3100`.
- [ ] Add `DOCKER-USER` default-deny rules for non-approved ports.
- [ ] Harden SSH root/password access after key-based access is verified.
- [ ] Put `ollama.bytelyst.com`, admin dashboards, and dev tooling behind private/auth-gated access unless explicitly approved as public.
@ -540,6 +542,29 @@ Minimum post-checks for Phase 1:
- Local Gitea mirror push for `learning_ai_common_plat` failed at Git HTTP transport even though fetch and health checks work; retry/fix mirror push separately.
- This fixed health state, not public exposure. Several direct published ports remain to be loopback-bound or blocked in Phase 1.
### 2026-05-27 — Phase 1 internal port loopback
**Changed:**
- Updated `/opt/bytelyst/learning_ai_common_plat/docker-compose.ecosystem.yml` so `cosmos-emulator`, `azurite`, `mailpit`, and `loki` publish host ports only on `127.0.0.1`.
- Recreated only `cosmos-emulator`, `azurite`, `mailpit`, and `loki` with `docker compose ... up -d --no-build`.
**Verified:**
- `docker compose -f docker-compose.ecosystem.yml --env-file .env.ecosystem config --quiet` passed.
- Docker reports the target services healthy.
- `ss -ltnp` shows `1025`, `8025`, `10000`, `1234`, `8081`, and `3100` listening on `127.0.0.1` only, with no `0.0.0.0` or IPv6 wildcard bind for that group.
- Local smoke checks returned HTTP `200` for Mailpit UI, Loki readiness, and Cosmos explorer. Azurite returned HTTP `400` on the raw blob endpoint while its container healthcheck remained healthy, which is expected for an unauthenticated root request.
**Committed/pushed:**
- `learning_ai_common_plat`: `1c09e479` (`fix: bind internal infra ports to loopback`) pushed to GitHub.
**Residual risk:**
- Public direct bypass remains for app/API ports, Gitea direct port `3300`, devops/admin surfaces, and Ollama `11434`.
- Add a `DOCKER-USER` fallback policy after the remaining allowlist is reviewed.
## Do Not Start With
- Rootless Docker migration.