Skip to content

security(compose): loopback-bind control-center in release configs - #45

Merged
man4ish merged 1 commit into
mainfrom
security/control-center-loopback-binding
Aug 14, 2026
Merged

security(compose): loopback-bind control-center in release configs#45
man4ish merged 1 commit into
mainfrom
security/control-center-loopback-binding

Conversation

@man4ish

@man4ish man4ish commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Follow-up audit to PR #44's release-compose hardening (${HOST_IP:-0.0.0.0} exposure review).

  • SECURITY-COMPOSE-HARDENING.md §7 item 1 already claimed control-center was loopback-only alongside lims and nginx-router. Re-verified against current code and found that claim was only true of docker-compose.yml (dev, hardcoded 127.0.0.1:7070:7070 with an explicit comment) — both release files (docker-compose.release.yml, docker-compose-release.yml) had drifted to ${HOST_IP:-0.0.0.0}:7070:7070.
  • Fixed both release files to 127.0.0.1:7070:7070, matching the dev file and the doc's own description.
  • Not a live authentication-bypass fix. control-center's /docker, /services, /summary, /config routes are independently gated by require_permission("platform.manage_infra") at the FastAPI app level (omnibioai-control-center, commit 8720377, already merged) regardless of this host-port binding — confirmed by reading main.py's include_router(..., dependencies=[Depends(require_permission(...))]) wiring and core/auth.py's independent JWT verification. This closes an unintended defense-in-depth gap and a doc/code inaccuracy, not a live exposure.
  • Docker-to-Docker networking (nginx-router's upstream control { server control-center:7070; }) is untouched — internal Docker networking never depended on the host port binding.
  • The broader question — whether workbench/tes/auth-service/rag/model-registry should also move off ${HOST_IP:-0.0.0.0} — remains open and explicitly not addressed here. It's a materially larger change (removes the direct-LAN-access path HOST_IP exists to support) that needs a product/deployment decision, per SECURITY-COMPOSE-HARDENING.md §7 item 1's own existing text.
  • Also found, explicitly not fixed here (out of scope for this task): docker-compose-release.yml's lims block runs DJANGO_DEBUG: "true" while publishing on ${HOST_IP:-0.0.0.0}:7000:7000 (the dot-named shipped file correctly uses DJANGO_DEBUG: "false" + 127.0.0.1:7000:7000). Flagging for a future LIMS-focused task.

Test plan

  • tests/test_compose_network_exposure.py: 2 new tests (test_control_center_is_loopback_bound_in_release_configs parametrized over both release files, test_dev_compose_control_center_still_loopback_bound) — pin the binding so it can't silently drift again in either direction
  • Full file: 61/61 passed (58 pre-existing + 3 new, including the doc-referenced permission check comment)
  • tests/test_compose_release_config.py + tests/test_compose_network_exposure.py together: 71/71 passed
  • docker compose config (both release files, dummy secrets): resolves control-center to host_ip: '127.0.0.1' as expected
  • Full repo test suite: 173 passed / 51 failed / 22 errors / 24 skipped / 5 xpassed — byte-identical failure/error set vs. clean origin/main (diff exit 0), all pre-existing live-service integration tests unrelated to this change

🤖 Generated with Claude Code

Follow-up to PR #44's release-compose hardening. SECURITY-COMPOSE-HARDENING.md
already claimed control-center was loopback-only alongside lims and
nginx-router -- a re-audit of the remaining ${HOST_IP:-0.0.0.0} bindings found
that was only true of docker-compose.yml (dev); both release files had
drifted to ${HOST_IP:-0.0.0.0}:7070:7070.

Not a live authentication bypass: control-center's /docker, /services,
/summary, /config routes are independently gated by
require_permission("platform.manage_infra") at the FastAPI app level
(omnibioai-control-center@8720377) regardless of this binding. This restores
the documented/intended defense-in-depth binding and closes the doc/code
inaccuracy.

The broader question -- whether workbench/tes/auth-service/rag/model-registry
should also move off ${HOST_IP:-0.0.0.0} -- remains open per
SECURITY-COMPOSE-HARDENING.md SS7 item 1: it requires a product/deployment
decision (would remove the direct-LAN-access path HOST_IP exists for) and is
explicitly not made in this change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@man4ish
man4ish merged commit d809a0a into main Aug 14, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant