authelia has listened on 127.0.0.1:9091 since it was stood up, with
nothing proxying to it — so `auth.<swarm.domain>` resolved and then
refused the connection. This is the vhost that was never written.
Follows forge and matrix exactly: one `optionalAttrs` attrset merged into
`virtualHosts`, TLS chosen by `vhostTlsFor` (the swarm-services leaf
already names it, since `swarm.serviceDomains` includes
`authelia.domain`), and the same four wiring sites those two occupy —
vhost, dnsmasq address, local-dev `/etc/hosts`, and the arg lists that
feed both files.
Gated on this host running the container, not on authelia being
configured: every hive knows the swarm's `authelia.url`, but only the one
serving it may claim the name. A client hive declaring this vhost would
answer for a service it does not run.
Two things that are deliberate rather than incidental:
`X-Forwarded-{Proto,Host,Uri,For}` are set because authelia decides by
the *original* request — the login redirect and the session cookie's
domain both derive from them. Without them every request looks like it
arrived at 127.0.0.1 over plain http.
And no `auth_basic`. Applying the gateway's basic-auth block to the SSO
provider would put the login page behind the login mechanism it exists to
replace.
83 lines
4 KiB
Nix
83 lines
4 KiB
Nix
# Hive-internal DNS resolver + DHCP, co-located in the gateway
|
|
# container — single front-door for both DNS and HTTP, saves a
|
|
# sibling container. Listens on the bridge interface from
|
|
# `services.hyperhive.network`; authoritative for the hive domain +
|
|
# sub-domains, forwards everything else upstream. Returns the
|
|
# `services.dnsmasq` value for the container config (see
|
|
# ./default.nix); the DHCP pool bounds are computed by hive-network.
|
|
{
|
|
lib,
|
|
networkCfg,
|
|
forgeCfg,
|
|
matrixCfg,
|
|
autheliaCfg,
|
|
hyperhiveDomain,
|
|
}:
|
|
{
|
|
enable = true;
|
|
# Don't substitute the container's /etc/resolv.conf — the gateway
|
|
# uses the host's resolver for its own outbound traffic; dnsmasq is
|
|
# purely for incoming queries from agent containers.
|
|
resolveLocalQueries = false;
|
|
settings = {
|
|
# Bind only on the bridge interface (and lo for health-checks).
|
|
# Outside hosts can't even see the listener.
|
|
interface = [
|
|
networkCfg.bridgeName
|
|
"lo"
|
|
];
|
|
bind-interfaces = true;
|
|
port = 53;
|
|
# Authoritative for the hive domain via the `address` rules below —
|
|
# must not fall back to the host's /etc/hosts. dnsmasq reads
|
|
# /etc/hosts by default, and `gateway.localHostsEntry` populates it
|
|
# with 127.0.0.1 for every hive name (host-side dev convenience,
|
|
# see default.nix). Since #3088 moved dnsmasq onto the host, that
|
|
# file is now the *same* /etc/hosts dnsmasq reads for agent queries
|
|
# — its entries win over `address=`, so every agent resolves the
|
|
# hive's own domains back to itself (127.0.0.1 in its own netns)
|
|
# instead of the bridge IP, and can't reach the forge, matrix, or
|
|
# dashboard at all. `no-hosts = true` keeps the authoritative
|
|
# `address=` rules in charge for containers while leaving
|
|
# `networking.hosts` (the actual /etc/hosts entries) untouched for
|
|
# host-side browsing.
|
|
no-hosts = true;
|
|
# Hive authoritative records — answer queries for the hive domain
|
|
# + its sub-domains with the bridge IP, where nginx is reachable
|
|
# from every container netns.
|
|
#
|
|
# The forge / matrix entries are redundant in the common case
|
|
# where `forge.domain` / `matrix.gatewayHost` are sub-domains of
|
|
# `hyperhive.domain` — dnsmasq's `/<domain>/` rule already matches
|
|
# sub-domains. Kept explicit because operators can override either
|
|
# to a cross-domain hostname (e.g. `forge.domain =
|
|
# "git.example.com"`); listing them explicitly keeps that case
|
|
# routed without needing an extra config block.
|
|
address = [
|
|
"/${hyperhiveDomain}/${networkCfg.bridgeIp}"
|
|
]
|
|
++ lib.optional ((forgeCfg.behindGateway or false)) "/${forgeCfg.domain}/${networkCfg.bridgeIp}"
|
|
++ lib.optional (
|
|
matrixCfg.enable && matrixCfg.gatewayHost != null
|
|
) "/${matrixCfg.gatewayHost}/${networkCfg.bridgeIp}"
|
|
++ lib.optional autheliaCfg.enable "/${autheliaCfg.domain}/${networkCfg.bridgeIp}";
|
|
# DHCP pool covering all usable host addresses on the bridge
|
|
# subnet — bounds computed by hive-network.nix from
|
|
# bridgeIp/bridgePrefixLength. All containers (agents and service
|
|
# containers such as hive-ci) receive their IPs dynamically.
|
|
dhcp-range = "${networkCfg.dhcpRangeStart},${networkCfg.dhcpRangeEnd},1h";
|
|
dhcp-leasefile = "/var/lib/dnsmasq/dnsmasq.leases";
|
|
# No explicit upstream: non-hive queries follow dnsmasq's
|
|
# resolv.conf default — the gateway container's `/etc/resolv.conf`,
|
|
# which nixos-container copies from the host at every start, so the
|
|
# hive always uses the host's resolvers. resolvconf is disabled in
|
|
# the container (see ./default.nix) so nothing regenerates that
|
|
# copy; the host-side `hive-gateway-resolv` path unit (also in
|
|
# ./default.nix) pushes in a fresh copy and reloads dnsmasq whenever
|
|
# the host's resolvers change, so the copy can't go stale under a
|
|
# network switch. Deliberately no fallback `server=`: dnsmasq queries
|
|
# all known upstreams in parallel, so a hardcoded public resolver
|
|
# would take a share of *normal* traffic, not just fill in when the
|
|
# host file is empty.
|
|
};
|
|
}
|