Watch
0
0
Fork
You've already forked hyperhive
0

authelia: allow only the collector to write to the log store's ingest path

This commit is contained in:
atlas 2026-10-17 13:31:11 +02:00
commit 2489830772
3 changed files with 48 additions and 12 deletions

View file

@ -290,8 +290,10 @@ accepts the new value within a minute.
The collector also scrapes this store's own metrics, at The collector also scrapes this store's own metrics, at
`https://<swarm.victorialogs.domain>/metrics`, so a collector on a host `https://<swarm.victorialogs.domain>/metrics`, so a collector on a host
without the store still gets them. The gateway admits only the collector's without the store still gets them. On this name the gateway admits only the
client to that path; any other session gets `deny`. collector's client to `/metrics` and the ingest route
`/insert/opentelemetry/v1/logs`; any other session gets `deny` on both. The
read side stays open to any authenticated caller.
### Telemetry collector (OTEL) ### Telemetry collector (OTEL)

View file

@ -134,6 +134,16 @@ let
} }
]; ];
# The log store's ingest routes: the collector's client, nobody else. A
# prefix rather than the one route the vhost serves, so no spelling of it,
# and no route added under `/insert/`, reaches `default_policy`. The rest of
# the name (read API, vmui) stays open to any authenticated caller; its
# `/metrics` is covered by `metricsRules`.
logsStoreRules = collectorOnly {
domain = config.services.hyperhive.swarm.victorialogs.domain;
resources = [ "^/insert/.*" ];
};
# One pair per `swarm.otel.publishedScrapeTargets` entry, read off the same # One pair per `swarm.otel.publishedScrapeTargets` entry, read off the same
# URL the collector requests and its token is minted for, so a target # URL the collector requests and its token is minted for, so a target
# cannot be published without the rules that confine it to the collector. # cannot be published without the rules that confine it to the collector.
@ -1342,6 +1352,7 @@ in
# reasoning for both halves lives. # reasoning for both halves lives.
metricsRules metricsRules
++ metricsStoreRules ++ metricsStoreRules
++ logsStoreRules
# The swarm UI on the apex. Not keyed to a deploy flag: its # The swarm UI on the apex. Not keyed to a deploy flag: its
# vhost is on the swarm controller's host, which need not # vhost is on the swarm controller's host, which need not
# be this one. Guarded on the domain being set: without it # be this one. Guarded on the domain being set: without it

View file

@ -387,8 +387,11 @@ let
rules = rules =
autheliaOnly.containers.swarm-authelia.config.services.authelia.instances.swarm.settings.access_control.rules; autheliaOnly.containers.swarm-authelia.config.services.authelia.instances.swarm.settings.access_control.rules;
# The metrics store's own name is the case above's; its rules carry # The metrics store's own name is the case above's; its rules carry
# `resources` for its push route and `/metrics` together. # `resources` for its push route and `/metrics` together. The log
metricsRules = lib.filter (r: r ? resources && r.domain != "metrics.t.local") rules; # store's `/insert/` ingest rules are the case below's.
metricsRules = lib.filter (
r: r ? resources && r.domain != "metrics.t.local" && r.resources != [ "^/insert/.*" ]
) rules;
re = lib.head (lib.head metricsRules).resources; re = lib.head (lib.head metricsRules).resources;
table = [ table = [
{ {
@ -514,10 +517,11 @@ let
&& checksOf locs."^~ /select/logsql/" == [ "auth_request /__swarm_logs_auth;" ]; && checksOf locs."^~ /select/logsql/" == [ "auth_request /__swarm_logs_auth;" ];
} }
{ {
# The `deny` that confines the log store's `/metrics` is scoped to that # The `deny`s that confine the log store's `/metrics` and its `/insert/`
# path, and comes after the collector's rule: every other path on the # ingest prefix are each scoped to their path and come after the
# name still reaches `default_policy`, as it did with no rule at all. # collector's rule: every other path on the name still reaches
name = "authelia confines the log store's /metrics to the collector and leaves its other paths alone"; # `default_policy`.
name = "authelia confines the log store's /metrics and ingest to the collector and leaves its other paths alone";
ok = ok =
let let
h = autheliaOnly.services.hyperhive; h = autheliaOnly.services.hyperhive;
@ -526,19 +530,38 @@ let
autheliaOnly.containers.swarm-authelia.config.services.authelia.instances.swarm.settings.access_control.rules; autheliaOnly.containers.swarm-authelia.config.services.authelia.instances.swarm.settings.access_control.rules;
logsRules = lib.filter (r: r.domain == "logs.t.local") rules; logsRules = lib.filter (r: r.domain == "logs.t.local") rules;
policy = subject: autheliaPolicy autheliaOnly subject "logs.t.local"; policy = subject: autheliaPolicy autheliaOnly subject "logs.t.local";
ingest = "/insert/opentelemetry/v1/logs";
in in
map (r: r.policy) logsRules == [ map (r: r.policy) logsRules == [
"one_factor" "one_factor"
"deny" "deny"
"one_factor"
"deny"
] ]
&& lib.all (r: r.resources == [ "^/metrics([?].*)?$" ]) logsRules &&
&& (lib.head logsRules).subject == [ collector ] map (r: r.resources) logsRules == [
[ "^/metrics([?].*)?$" ]
[ "^/metrics([?].*)?$" ]
[ "^/insert/.*" ]
[ "^/insert/.*" ]
]
&&
map (r: r.subject or null) logsRules == [
[ collector ]
null
[ collector ]
null
]
&& policy collector "/metrics" == "one_factor" && policy collector "/metrics" == "one_factor"
&& policy "user:someone" "/metrics" == "deny" && policy "user:someone" "/metrics" == "deny"
&& policy "user:someone" "/metrics?x=1" == "deny" && policy "user:someone" "/metrics?x=1" == "deny"
&& policy collector ingest == "one_factor"
&& policy collector "${ingest}?_msg_field=MESSAGE" == "one_factor"
&& policy "user:someone" ingest == "deny"
&& policy "user:someone" "${ingest}?_msg_field=MESSAGE" == "deny"
&& policy "user:someone" "/insert/jsonline" == "deny"
&& policy "user:someone" "/" == "one_factor" && policy "user:someone" "/" == "one_factor"
&& policy "user:someone" "/select/logsql/query" == "one_factor" && policy "user:someone" "/select/logsql/query" == "one_factor";
&& policy "user:someone" "/insert/opentelemetry/v1/logs" == "one_factor";
} }
{ {
# Single host: the store is scraped once, by its published name. # Single host: the store is scraped once, by its published name.