Watch
0
0
Fork
You've already forked hyperhive
0

swarm-otel: routes carry a route header and the readiness probe requires it

This commit is contained in:
atlas 2026-10-24 21:19:39 +02:00 • committed by mara
commit 7680b07fcb
3 changed files with 101 additions and 15 deletions

View file

@ -949,10 +949,74 @@ let
&& !(lib.any (writes (sc // { ReadWritePaths = [ ]; })) socks)
&& !(lib.any (writes (sc // { ReadWritePaths = [ "/var/lib/opentelemetry-collector" ]; })) socks);
}
{
# The readiness unit tells a route nginx has from its catch-all 404 by
# this header, so every route carries its own name in it, `always` so a
# 4xx or 5xx from the collector carries it too. A location with an
# `add_header` inherits none of the server-scope ones, so the security
# headers have to be repeated. The catch-all carries no route header.
name = "every collector route sets its own route header and keeps the security headers";
ok =
let
host = serviceContainersWithCi;
otel = host.services.hyperhive.swarm.otel;
locs = host.services.nginx.virtualHosts.${otel.domain}.locations;
sec = host.services.hyperhive.gateway.lib.securityHeaders;
proxied = lib.filter (l: (locs.${l}.proxyPass or null) != null) (lib.attrNames locs);
nameOf = l: lib.removeSuffix "/" (lib.removePrefix "/" l);
verdict =
ls:
lib.all (
l:
let
extra = ls.${l}.extraConfig or "";
in
lib.hasInfix "add_header X-Swarm-Otel-Route ${nameOf l} always;" extra
&& lib.hasInfix "add_header X-Frame-Options" extra
) proxied;
in
lib.length proxied > 2
&& lib.hasInfix "add_header X-Frame-Options" sec
&& !(lib.hasInfix "X-Swarm-Otel-Route" (locs."/".extraConfig or ""))
&& verdict locs
&& !verdict (
locs
// {
"/h1/" = locs."/h1/" // {
extraConfig = sec;
};
}
)
&& !verdict (
locs
// {
"/h1/" = locs."/h1/" // {
extraConfig = "add_header X-Swarm-Otel-Route h1 always;";
};
}
)
&& !verdict (
locs
// {
"/h1/" = locs."/h1/" // {
extraConfig = sec + "add_header X-Swarm-Otel-Route swarm always;";
};
}
)
&& !verdict (
locs
// {
"/h1/" = locs."/h1/" // {
extraConfig = sec + "add_header X-Swarm-Otel-Route h1;";
};
}
);
}
{
# The probe loop names each gateway route, and the routes are read from
# the vhost, not from the receivers the probe is built from. A script
# missing one route, or treating 502 as a pass, is rejected.
# missing one route, treating 502 as a pass, or passing on status alone
# without the route header, is rejected.
name = "the readiness unit probes every collector route through the gateway";
ok =
let
@ -980,7 +1044,9 @@ let
probed script == routes
&& lib.hasInfix "--resolve ${otel.domain}:443:127.0.0.1" script
&& lib.hasInfix "https://${otel.domain}/$route/" script
&& lib.hasInfix "case $code in 000 | 502 | 504) ;;" script;
&& lib.hasInfix "case $code in 000 | 502 | 504) ;;" script
&& lib.hasInfix "%header{x-swarm-otel-route}" script
&& lib.hasInfix ''[ "$seen" = "$route" ] && continue 2'' script;
script = host.systemd.services.swarm-otel-sockets.script;
in
lib.length routes > 2
@ -989,7 +1055,9 @@ let
&& verdict script
&& !verdict (lib.replaceStrings [ " swarm-grafana" ] [ "" ] script)
&& !verdict (lib.replaceStrings [ "000 | 502 | 504" ] [ "000 | 504" ] script)
&& !verdict (lib.replaceStrings [ "--resolve" ] [ "--noresolve" ] script);
&& !verdict (lib.replaceStrings [ "--resolve" ] [ "--noresolve" ] script)
&& !verdict (lib.replaceStrings [ "%header{x-swarm-otel-route}" ] [ "" ] script)
&& !verdict (lib.replaceStrings [ ''[ "$seen" = "$route" ] && '' ] [ "" ] script);
}
{
# The DynamicUser layout keeps the history under /var/lib/private; the