c0re: bind dashboard to 127.0.0.1 only (#652)
This commit is contained in:
parent
85790b0cca
commit
c5d466c5c5
2 changed files with 26 additions and 12 deletions
|
|
@ -92,9 +92,16 @@ pub async fn serve(port: u16, coord: Arc<Coordinator>) -> Result<()> {
|
|||
// /static/dashboard.css → dist/static/dashboard.css, etc.).
|
||||
.fallback_service(ServeDir::new(&static_dir))
|
||||
.with_state(AppState { coord });
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
||||
// Bind loopback-only (#652). External access funnels through
|
||||
// hive-gateway (in-host-netns nginx container), which proxies
|
||||
// `/` → `127.0.0.1:<dashboardPort>` upstream. Operators who opt
|
||||
// out of the gateway lose remote dashboard access — that's by
|
||||
// design; the c0re HTTP surface is privileged (approve / deny /
|
||||
// destroy, etc.) and any external exposure needs to pass through
|
||||
// a real reverse proxy with auth.
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], port));
|
||||
let listener = bind_with_retry(addr).await?;
|
||||
tracing::info!(%port, "dashboard listening");
|
||||
tracing::info!(%addr, "dashboard listening");
|
||||
axum::serve(listener, app).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -194,21 +194,28 @@ in
|
|||
managerToplevel
|
||||
];
|
||||
|
||||
# Dashboard + per-container web UIs share the host's network namespace and
|
||||
# need their ports reachable when there's no gateway in front. Dashboard:
|
||||
# `cfg.dashboardPort` (default 7000). Manager: 8000. Sub-agents: 8100..8999
|
||||
# (deterministic hash; see `lifecycle::agent_web_port`).
|
||||
# Per-container web UIs share the host's network namespace and need
|
||||
# their ports reachable when there's no gateway in front. Manager:
|
||||
# 8000. Sub-agents: 8100..8999 (deterministic hash; see
|
||||
# `lifecycle::agent_web_port`).
|
||||
#
|
||||
# The dashboard port (`cfg.dashboardPort`, default 7000) is *not*
|
||||
# listed here — since #652 the dashboard binds `127.0.0.1` only,
|
||||
# so opening the firewall hole would be a no-op. Remote dashboard
|
||||
# access flows through hive-gateway (default-on); operators who
|
||||
# opt out of the gateway lose external dashboard reach by design —
|
||||
# the surface is privileged (approve / deny / destroy) and must
|
||||
# not be exposed without a real reverse proxy in front.
|
||||
#
|
||||
# When `services.hyperhive.gateway.enable = true` (the default), the
|
||||
# gateway nginx is the sole external entry point and proxies to
|
||||
# `127.0.0.1:7000` etc. internally — leaving the direct ports open
|
||||
# in the host firewall would defeat the gateway's "single front
|
||||
# door" story (closes #621). Operators who opt out of the gateway
|
||||
# still get the direct ports opened so the legacy
|
||||
# `http://<host>:7000/` flow works.
|
||||
# `127.0.0.1:7000` etc. internally — leaving the per-agent ports
|
||||
# open in the host firewall would defeat the gateway's "single
|
||||
# front door" story (closes #621). Operators who opt out of the
|
||||
# gateway still get those direct ports opened so the legacy
|
||||
# `http://<host>:8100/` flow works.
|
||||
networking.firewall = lib.mkIf (!config.services.hyperhive.gateway.enable) {
|
||||
allowedTCPPorts = [
|
||||
cfg.dashboardPort
|
||||
8000
|
||||
];
|
||||
allowedTCPPortRanges = [
|
||||
|
|
|
|||
Loading…
Reference in a new issue