Watch
0
0
Fork
You've already forked hyperhive
0

gateway: serve the hive dashboard on <hive>.hives.<swarm> behind authelia, drop htpasswd

The dashboard, its API, the swagger UI and the agent routes move to their
own vhost, `swarm.dashboardDomain` = `<hive>.hives.<swarm.domain>`, under
the swarm domain so authelia's session cookie reaches it. `/`, `/api/` and
`/api/docs/` ask authelia through `auth_request`, and authelia's
`operatorsOnly` rule for each hive's dashboard name lets only the admins
group in. The hive domain keeps matrix discovery and redirects every other
path to the new name.

The name rides as a SAN on the hive's own gateway leaf: the per-hive bao
role allows it, and hive-tls asks for it and checks coverage.

HTTP Basic auth is gone: the htpasswd writer and its test, the
`hivectl gateway` verbs and host-socket requests, the `gateway.auth`
options (now a removed-option error), the unauthorized page and the bcrypt
dependency. tmpfiles deletes a leftover gateway.htpasswd, which held
bcrypt hashes at 0644.

c0re hands out dashboard and agent URLs on the new name
(HYPERHIVE_DASHBOARD_DOMAIN), and the swarm controller's hive roster
carries each hive's dashboard name for the swarm UI's hive list.

Closes #3469
This commit is contained in:
atlas 2026-10-15 20:19:23 +02:00 • committed by mara
commit 92559af8e7
47 changed files with 351 additions and 623 deletions

View file

@ -1,6 +1,6 @@
//! Shared helpers used across hivectl's command handling: daemon
//! request/response plumbing (`daemon_request`, `render`,
//! `render_lifecycle`) and password input (`resolve_password`).
//! `render_lifecycle`).
use std::path::Path;
@ -18,7 +18,7 @@ pub(crate) fn parse_ident(name: &str) -> Result<hive_types::Ident> {
/// Send a provisioning request to the daemon and print its result lines.
/// The daemon owns the provisioning logic; hivectl just relays the outcome,
/// prefixing any error with `label` (e.g. `forge` / `gateway`).
/// prefixing any error with `label` (e.g. `forge` / `quota`).
pub(crate) async fn daemon_request(
socket: &Path,
req: hive_host_sock::HostRequest,
@ -40,35 +40,6 @@ pub(crate) async fn daemon_request(
Ok(())
}
/// Resolve the password the caller asked for, or return `None` to fall
/// back to a random throwaway. `--password <PW>` wins outright;
/// `--password-stdin` reads one line off stdin (trailing newline
/// stripped). Empty stdin is treated as an error so the caller doesn't
/// silently provision an empty-password account.
pub(crate) fn resolve_password(
password: Option<&str>,
password_stdin: bool,
) -> Result<Option<String>> {
if let Some(p) = password {
return Ok(Some(p.to_owned()));
}
if password_stdin {
use std::io::BufRead as _;
let stdin = std::io::stdin();
let mut line = String::new();
stdin
.lock()
.read_line(&mut line)
.context("read password from stdin")?;
let trimmed = line.trim_end_matches(['\r', '\n']).to_owned();
if trimmed.is_empty() {
bail!("--password-stdin: empty input");
}
return Ok(Some(trimmed));
}
Ok(None)
}
/// Pretty-print a `HostResponse` as JSON and bail on failure. Used by the
/// agent-lifecycle verbs that just relay a daemon result verbatim.
pub(crate) fn render(resp: hive_host_sock::HostResponse) -> Result<()> {