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
|
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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue