swarm-victoriametrics: forward only the store's read API
The metrics vhost's `/` proxied every path to VictoriaMetrics with no auth_request, so anything that could reach metrics.<swarm> could write (`/api/v1/import`, `/api/v1/write`, ...) and delete (`/api/v1/admin/tsdb/delete_series`) series. Only the OTLP push route was gated. `/` now answers 403. The read routes Grafana's Prometheus datasource and vmui use are forwarded by exact or `^~` prefix location, each with the matched path as its proxy_pass URI. The bare domain, which the swarm UI's Metrics quick link opens, redirects to vmui instead of the store's index page. The OTLP push location is unchanged. Closes #5186
This commit is contained in:
parent
3464a912bf
commit
53d0d59be0
3 changed files with 94 additions and 8 deletions
|
|
@ -25,6 +25,51 @@ let
|
|||
# Shared host netns, like every sibling swarm container: the gateway
|
||||
# reaches this at 127.0.0.1:<port>.
|
||||
privateNetwork = false;
|
||||
|
||||
# The store's read API: the only part of it the vhost serves without a
|
||||
# credential. Each location's `proxy_pass` carries the path, so the store
|
||||
# receives the path nginx matched, not the caller's unnormalised spelling.
|
||||
#
|
||||
# Grafana's Prometheus datasource reads the query, series, label, metadata,
|
||||
# buildinfo, exemplar, rules and alerts routes; the store answers the last
|
||||
# three with fixed placeholders. vmui is the static files under `/vmui/`
|
||||
# plus the query API and the remaining read-only routes here. Paths read off
|
||||
# the pinned build's `app/vmselect/main.go` and vmui's `src/`.
|
||||
readPaths = [
|
||||
"/api/v1/query"
|
||||
"/api/v1/query_range"
|
||||
"/api/v1/query_exemplars"
|
||||
"/api/v1/series"
|
||||
"/api/v1/labels"
|
||||
"/api/v1/metadata"
|
||||
"/api/v1/rules"
|
||||
"/api/v1/alerts"
|
||||
"/api/v1/status/buildinfo"
|
||||
"/api/v1/export"
|
||||
"/api/v1/export/csv"
|
||||
"/api/v1/status/tsdb"
|
||||
"/api/v1/status/metric_names_stats"
|
||||
"/api/v1/status/top_queries"
|
||||
"/api/v1/status/active_queries"
|
||||
"/expand-with-exprs"
|
||||
"/prettify-query"
|
||||
"/metric-relabel-debug"
|
||||
"/vmui"
|
||||
];
|
||||
# The store serves only `<name>/values` under `/api/v1/label/`, and only
|
||||
# static files and UI config under `/vmui/`.
|
||||
readPrefixes = [
|
||||
"/api/v1/label/"
|
||||
"/vmui/"
|
||||
];
|
||||
readLocations =
|
||||
let
|
||||
to = path: { proxyPass = "http://127.0.0.1:${toString cfg.port}${path}"; };
|
||||
in
|
||||
lib.listToAttrs (
|
||||
map (p: lib.nameValuePair "= ${p}" (to p)) readPaths
|
||||
++ map (p: lib.nameValuePair "^~ ${p}" (to p)) readPrefixes
|
||||
);
|
||||
in
|
||||
{
|
||||
# What the store IS from any hive's point of view, the name it answers on and
|
||||
|
|
@ -90,14 +135,19 @@ in
|
|||
services.nginx.virtualHosts."${cfg.domain}" = (gatewayCfg.lib.tlsFor cfg.domain) // {
|
||||
listen = gatewayCfg.lib.listen;
|
||||
extraConfig = gatewayCfg.lib.securityHeaders;
|
||||
locations = {
|
||||
"/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString cfg.port}/";
|
||||
};
|
||||
locations = readLocations // {
|
||||
# Nothing reaches the store unless a location here names it. The
|
||||
# store serves writes and admin calls (`/api/v1/import`,
|
||||
# `/api/v1/admin/tsdb/delete_series`, ...) on the same listener as
|
||||
# its queries, and authenticates none of them.
|
||||
"/".return = "403";
|
||||
|
||||
# The swarm UI's quick link opens the bare domain. The store's own
|
||||
# index page links mostly to paths refused above, so send it to vmui.
|
||||
"= /".return = "302 /vmui/";
|
||||
|
||||
# The swarm collector's ingest route, and the only authenticated thing
|
||||
# on this vhost. `=` so it outranks the `/` prefix above, which would
|
||||
# otherwise carry these writes with no check at all.
|
||||
# on this vhost. `=` so it outranks the `/` prefix above.
|
||||
#
|
||||
# ⚠️ No `error_page 401 =302` here, and its absence is the point: a
|
||||
# redirect is right for a browser and wrong for a pusher, which would
|
||||
|
|
|
|||
Loading…
Reference in a new issue