Compare commits

...

1 Commits

Author SHA1 Message Date
Max Kotliar
beeea77690 app/vmauth: allow logging unauthorized requests to access log
Allow `unauthorized_user` to be configured without `URLPrefix` or
`URLMaps`. Previously either was required; now both are optional. This
enables the following minimal config:

```yaml
unauthorized_user:
  access_log: {}
```

When set, vmauth logs all requests with missing or invalid auth tokens
to the access log, including `remote_addr`. This helps identify and
block IPs performing brute-force attacks.

Fixes https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11180
2026-07-02 14:56:05 +03:00
5 changed files with 34 additions and 7 deletions

View File

@@ -118,9 +118,10 @@ type AccessLogFilters struct {
}
func (ui *UserInfo) logRequest(r *http.Request, userName string, statusCode int, duration time.Duration) {
if ui.AccessLog == nil {
if ui == nil || ui.AccessLog == nil {
return
}
filters := ui.AccessLog.Filters
if filters != nil && len(filters.SkipStatusCodes) > 0 {
if slices.Contains(filters.SkipStatusCodes, statusCode) {
@@ -134,6 +135,17 @@ func (ui *UserInfo) logRequest(r *http.Request, userName string, statusCode int,
r.Host, requestURI, statusCode, remoteAddr, r.UserAgent(), r.Referer(), duration.Milliseconds(), userName)
}
// haveURLs reports whether ui has at least one URL route configured.
// It is used for validating unauthorized_user config, since other users
// must always have either URLPrefix or URLMaps set.
func (ui *UserInfo) haveURLs() bool {
if ui == nil {
return false
}
return ui.URLPrefix != nil || len(ui.URLMaps) > 0 || ui.DefaultURL != nil
}
// HeadersConf represents config for request and response headers.
type HeadersConf struct {
RequestHeaders []*Header `yaml:"headers,omitempty"`
@@ -983,8 +995,11 @@ func parseAuthConfig(data []byte) (*AuthConfig, error) {
if err := parseJWTPlaceholdersForUserInfo(ui, false); err != nil {
return nil, err
}
if err := ui.initURLs(); err != nil {
return nil, err
if ui.URLPrefix != nil || len(ui.URLMaps) > 0 || ui.DefaultURL != nil {
if err := ui.initURLs(); err != nil {
return nil, err
}
}
metricLabels, err := ui.getMetricLabels()

View File

@@ -175,11 +175,12 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
if len(ats) == 0 {
// Process requests for unauthorized users
ui := authConfig.Load().UnauthorizedUser
if ui != nil {
if ui.haveURLs() {
processUserRequest(w, r, ui, nil)
return true
}
ui.logRequest(r, ``, http.StatusUnauthorized, 0)
handleMissingAuthorizationError(w)
return true
}
@@ -193,6 +194,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
logger.Panicf("BUG: unexpected nil jwt token for user %q", ui.name())
}
if !tkn.HasVMAccessClaim() && ui.JWT.DefaultVMAccessClaim == nil {
ui.logRequest(r, ``, http.StatusUnauthorized, 0)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return true
}
@@ -202,13 +204,14 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
}
uu := authConfig.Load().UnauthorizedUser
if uu != nil {
if uu.haveURLs() {
processUserRequest(w, r, uu, nil)
return true
}
invalidAuthTokenRequests.Inc()
slowdownUnauthorizedResponse(r)
uu.logRequest(r, ``, http.StatusUnauthorized, 0)
if *logInvalidAuthTokens {
err := fmt.Errorf("cannot authorize request with auth tokens %q", ats)
err = &httpserver.ErrorWithStatusCode{

0
auth.yaml Normal file
View File

View File

@@ -34,6 +34,7 @@ See also [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-rel
* FEATURE: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/), `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) and [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/): introduce `64KiB` size limit for `metric metadata` fields - `Unit`, `Help` and `MetricFamilyName`. See [#11128](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11128).
* FEATURE: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): add `optimize_repeated_binary_op_subexprs=1` query arg to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query) for executing binary operator sides sequentially when they share the same optimized aggregate rollup result expression. This allows the second side to reuse rollup result cache populated by the first side. See [#10575](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10575). Thanks to @xhebox for the contribution.
* FEATURE: [vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/): prevent possible password brute-force attacks with an artificial 2-3 second delay as recommended by [OWASP](https://owasp.org/Top10/2025/A07_2025-Authentication_Failures). See [#11180](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11180).
* FEATURE: [vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/): allow log requests with missing or invalid auth tokens to [access log](https://docs.victoriametrics.com/victoriametrics/vmauth/#access-log). This is useful for identifying `remote_addr` IPs performing brute-force attacks. See [#11180](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11180).
* BUGFIX: all VictoriaMetrics components: cancel in-flight HTTP requests shortly before `-http.maxGracefulShutdownDuration` elapses during graceful shutdown, so they can drain and the shutdown completes cleanly within that window instead of timing out and exiting via `logger.Fatalf` -> `os.Exit`. This prevents skipping the storage flush and losing in-memory data when long-lived requests are in flight (such as VictoriaLogs live tailing). See [#1502](https://github.com/VictoriaMetrics/VictoriaLogs/issues/1502).
* BUGFIX: `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): fixes unexpected rare rerouting. See [#11162](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11162).

View File

@@ -1323,9 +1323,17 @@ unauthorized_user:
vmauth allows configuring access logs {{% available_from "v1.138.0" %}} printing per-user:
```yaml
users:
- username: foo
password: bar
url_prefix: 'http://localhost:8428/'
# Log all requests to this user
access_log: {}
```
If you want to log requests with missing or invalid auth tokens, use unauthorized_user without configuring any URL routes{{% available_from "#" %}}:
```yaml
unauthorized_user:
url_prefix: 'http://localhost:8428/'
# Log all requests to this user
access_log: {}
```