authelia: allow only the collector to write to the log store's ingest path
This commit is contained in:
parent
51cc093465
commit
2489830772
3 changed files with 48 additions and 12 deletions
|
|
@ -290,8 +290,10 @@ accepts the new value within a minute.
|
|||
|
||||
The collector also scrapes this store's own metrics, at
|
||||
`https://<swarm.victorialogs.domain>/metrics`, so a collector on a host
|
||||
without the store still gets them. The gateway admits only the collector's
|
||||
client to that path; any other session gets `deny`.
|
||||
without the store still gets them. On this name the gateway admits only the
|
||||
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
# 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.
|
||||
|
|
@ -1342,6 +1352,7 @@ in
|
|||
# reasoning for both halves lives.
|
||||
metricsRules
|
||||
++ metricsStoreRules
|
||||
++ logsStoreRules
|
||||
# The swarm UI on the apex. Not keyed to a deploy flag: its
|
||||
# vhost is on the swarm controller's host, which need not
|
||||
# be this one. Guarded on the domain being set: without it
|
||||
|
|
|
|||
|
|
@ -387,8 +387,11 @@ let
|
|||
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
|
||||
# `resources` for its push route and `/metrics` together.
|
||||
metricsRules = lib.filter (r: r ? resources && r.domain != "metrics.t.local") rules;
|
||||
# `resources` for its push route and `/metrics` together. The log
|
||||
# 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;
|
||||
table = [
|
||||
{
|
||||
|
|
@ -514,10 +517,11 @@ let
|
|||
&& checksOf locs."^~ /select/logsql/" == [ "auth_request /__swarm_logs_auth;" ];
|
||||
}
|
||||
{
|
||||
# The `deny` that confines the log store's `/metrics` is scoped to that
|
||||
# path, and comes after the collector's rule: every other path on the
|
||||
# name still reaches `default_policy`, as it did with no rule at all.
|
||||
name = "authelia confines the log store's /metrics to the collector and leaves its other paths alone";
|
||||
# The `deny`s that confine the log store's `/metrics` and its `/insert/`
|
||||
# ingest prefix are each scoped to their path and come after the
|
||||
# collector's rule: every other path on the name still reaches
|
||||
# `default_policy`.
|
||||
name = "authelia confines the log store's /metrics and ingest to the collector and leaves its other paths alone";
|
||||
ok =
|
||||
let
|
||||
h = autheliaOnly.services.hyperhive;
|
||||
|
|
@ -526,19 +530,38 @@ let
|
|||
autheliaOnly.containers.swarm-authelia.config.services.authelia.instances.swarm.settings.access_control.rules;
|
||||
logsRules = lib.filter (r: r.domain == "logs.t.local") rules;
|
||||
policy = subject: autheliaPolicy autheliaOnly subject "logs.t.local";
|
||||
ingest = "/insert/opentelemetry/v1/logs";
|
||||
in
|
||||
map (r: r.policy) logsRules == [
|
||||
"one_factor"
|
||||
"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 "user:someone" "/metrics" == "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" "/select/logsql/query" == "one_factor"
|
||||
&& policy "user:someone" "/insert/opentelemetry/v1/logs" == "one_factor";
|
||||
&& policy "user:someone" "/select/logsql/query" == "one_factor";
|
||||
}
|
||||
{
|
||||
# Single host: the store is scraped once, by its published name.
|
||||
|
|
|
|||
Loading…
Reference in a new issue