From 73e22dcf8115d1f1e445eafe35780976f3f4decf Mon Sep 17 00:00:00 2001 From: Alexander Marshalov <_@marshalov.org> Date: Mon, 24 Apr 2023 14:57:13 +0200 Subject: [PATCH] added `unauthorized_user` field in vmauth users config (#4083) (#4157) added `unauthorized_user` field in vmauth users config (#4083) --------- Signed-off-by: Alexander Marshalov <_@marshalov.org> --- app/vmauth/README.md | 18 ++++++++++++++++++ app/vmauth/auth_config.go | 15 ++++++++++++++- app/vmauth/main.go | 18 +++++++++++++++--- docs/vmauth.md | 18 ++++++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/app/vmauth/README.md b/app/vmauth/README.md index 3f14986e8..e1f0da86f 100644 --- a/app/vmauth/README.md +++ b/app/vmauth/README.md @@ -62,6 +62,10 @@ The following [metrics](#monitoring) related to concurrency limits are exposed b - `vmauth_user_concurrent_requests_current{username="..."}` - the current number of concurrent requests for the given `username`. - `vmauth_user_concurrent_requests_limit_reached_total{username="foo"}` - the number of requests rejected with `429 Too Many Requests` error 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 of the concurrency limit has been reached for unauthorized users (if `unauthorized_user` section is used). ## Auth config @@ -152,6 +156,18 @@ users: url_prefix: "http://vminsert:8480/insert/42/prometheus" headers: - "X-Scope-OrgID: abc" + +# This requests will be executed for requests without Authorization header. +# For instance, http://vmauth:8427/api/v1/query will be proxied to http://vmselect1:8481/select/0/prometheus/api/v1/query +unauthorized_user: + url_map: + - src_paths: + - /health + - /api/v1/query/ + - /api/v1/query_range + url_prefix: + - http://vmselect1:8481/select/0/prometheus + - http://vmselect2:8481/select/0/prometheus ``` The config may contain `%{ENV_VAR}` placeholders, which are substituted by the corresponding `ENV_VAR` environment variable values. @@ -194,6 +210,8 @@ users: # other config options here ``` +For unauthorized users `vmauth` exports `vmauth_unauthorized_user_requests_total` metric without label (if `unauthorized_user` section of config is used). + ## How to build from sources It is recommended using [binary releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases) - `vmauth` is located in `vmutils-*` archives there. diff --git a/app/vmauth/auth_config.go b/app/vmauth/auth_config.go index 3a4737c16..d85912c07 100644 --- a/app/vmauth/auth_config.go +++ b/app/vmauth/auth_config.go @@ -31,7 +31,8 @@ var ( // AuthConfig represents auth config. type AuthConfig struct { - Users []UserInfo `yaml:"users,omitempty"` + Users []UserInfo `yaml:"users,omitempty"` + UnauthorizedUser *UserInfo `yaml:"unauthorized_user,omitempty"` } // UserInfo is user information read from authConfigPath @@ -374,6 +375,18 @@ func parseAuthConfig(data []byte) (*AuthConfig, error) { if err = yaml.UnmarshalStrict(data, &ac); err != nil { return nil, fmt.Errorf("cannot unmarshal AuthConfig data: %w", err) } + ui := ac.UnauthorizedUser + if ui != nil { + ui.requests = metrics.GetOrCreateCounter(`vmauth_unauthorized_user_requests_total`) + ui.concurrencyLimitCh = make(chan struct{}, ui.getMaxConcurrentRequests()) + ui.concurrencyLimitReached = metrics.GetOrCreateCounter(`vmauth_unauthorized_user_concurrent_requests_limit_reached_total`) + _ = metrics.GetOrCreateGauge(`vmauth_unauthorized_user_concurrent_requests_capacity`, func() float64 { + return float64(cap(ui.concurrencyLimitCh)) + }) + _ = metrics.GetOrCreateGauge(`vmauth_unauthorized_user_concurrent_requests_current`, func() float64 { + return float64(len(ui.concurrencyLimitCh)) + }) + } return &ac, nil } diff --git a/app/vmauth/main.go b/app/vmauth/main.go index 7281527c8..fee5fdbc2 100644 --- a/app/vmauth/main.go +++ b/app/vmauth/main.go @@ -84,6 +84,13 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { } authToken := r.Header.Get("Authorization") if authToken == "" { + // Process requests for unauthorized users + ui := authConfig.Load().UnauthorizedUser + if ui != nil { + processUserRequest(w, r, ui) + return true + } + w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) http.Error(w, "missing `Authorization` request header", http.StatusUnauthorized) return true @@ -110,6 +117,12 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { } return true } + + processUserRequest(w, r, ui) + return true +} + +func processUserRequest(w http.ResponseWriter, r *http.Request, ui *UserInfo) { ui.requests.Inc() // Limit the concurrency of requests to backends @@ -119,18 +132,17 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { if err := ui.beginConcurrencyLimit(); err != nil { handleConcurrencyLimitError(w, r, err) <-concurrencyLimitCh - return true + return } default: concurrentRequestsLimitReached.Inc() err := fmt.Errorf("cannot serve more than -maxConcurrentRequests=%d concurrent requests", cap(concurrencyLimitCh)) handleConcurrencyLimitError(w, r, err) - return true + return } processRequest(w, r, ui) ui.endConcurrencyLimit() <-concurrencyLimitCh - return true } func processRequest(w http.ResponseWriter, r *http.Request, ui *UserInfo) { diff --git a/docs/vmauth.md b/docs/vmauth.md index 1ec339b69..066b51c4e 100644 --- a/docs/vmauth.md +++ b/docs/vmauth.md @@ -66,6 +66,10 @@ The following [metrics](#monitoring) related to concurrency limits are exposed b - `vmauth_user_concurrent_requests_current{username="..."}` - the current number of concurrent requests for the given `username`. - `vmauth_user_concurrent_requests_limit_reached_total{username="foo"}` - the number of requests rejected with `429 Too Many Requests` error 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 of the concurrency limit has been reached for unauthorized users (if `unauthorized_user` section is used). ## Auth config @@ -156,6 +160,18 @@ users: url_prefix: "http://vminsert:8480/insert/42/prometheus" headers: - "X-Scope-OrgID: abc" + +# This requests will be executed for requests without Authorization header. +# For instance, http://vmauth:8427/api/v1/query will be proxied to http://vmselect1:8481/select/0/prometheus/api/v1/query +unauthorized_user: + url_map: + - src_paths: + - /health + - /api/v1/query/ + - /api/v1/query_range + url_prefix: + - http://vmselect1:8481/select/0/prometheus + - http://vmselect2:8481/select/0/prometheus ``` The config may contain `%{ENV_VAR}` placeholders, which are substituted by the corresponding `ENV_VAR` environment variable values. @@ -198,6 +214,8 @@ users: # other config options here ``` +For unauthorized users `vmauth` exports `vmauth_unauthorized_user_requests_total` metric without label (if `unauthorized_user` section of config is used). + ## How to build from sources It is recommended using [binary releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases) - `vmauth` is located in `vmutils-*` archives there.