Skip to content

Commit

Permalink
ruler: Support OAuth2 and proxies in Alertmanager client (#9945)
Browse files Browse the repository at this point in the history
* Support for proxies

* Flesh out oauth config

* Tests for proxy_url

* Tests for OAuth2 config options

* Reject multiple auth schemes at the same time

* Generate docs

* Make reference-help

* Fix descriptions

* Make reference-help

* changelog

* Add comma and regenerate

* Migrate to StringSliceCSV as it seems to be the standard and StringSlice seems incomplete

* Remake docs and reference help
  • Loading branch information
alexweav authored Nov 26, 2024
1 parent 96e0160 commit c178c83
Show file tree
Hide file tree
Showing 7 changed files with 367 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
* [ENHANCEMENT] Distributor: Initialize ha_tracker cache before ha_tracker and distributor reach running state and begin serving writes. #9826 #9976
* [ENHANCEMENT] Ingester: `-ingest-storage.kafka.max-buffered-bytes` to limit the memory for buffered records when using concurrent fetching. #9892
* [ENHANCEMENT] Querier: improve performance and memory consumption of queries that select many series. #9914
* [ENHANCEMENT] Ruler: Support OAuth2 and proxies in Alertmanager client #9945
* [BUGFIX] Fix issue where functions such as `rate()` over native histograms could return incorrect values if a float stale marker was present in the selected range. #9508
* [BUGFIX] Fix issue where negation of native histograms (eg. `-some_native_histogram_series`) did nothing. #9508
* [BUGFIX] Fix issue where `metric might not be a counter, name does not end in _total/_sum/_count/_bucket` annotation would be emitted even if `rate` or `increase` did not have enough samples to compute a result. #9508
Expand Down
61 changes: 61 additions & 0 deletions cmd/mimir/config-descriptor.json
Original file line number Diff line number Diff line change
Expand Up @@ -12347,6 +12347,67 @@
"fieldDefaultValue": "",
"fieldFlag": "ruler.alertmanager-client.basic-auth-password",
"fieldType": "string"
},
{
"kind": "block",
"name": "oauth2",
"required": false,
"desc": "",
"blockEntries": [
{
"kind": "field",
"name": "client_id",
"required": false,
"desc": "OAuth2 client ID. Enables the use of OAuth2 for authenticating with Alertmanager.",
"fieldValue": null,
"fieldDefaultValue": "",
"fieldFlag": "ruler.alertmanager-client.oauth.client_id",
"fieldType": "string"
},
{
"kind": "field",
"name": "client_secret",
"required": false,
"desc": "OAuth2 client secret.",
"fieldValue": null,
"fieldDefaultValue": "",
"fieldFlag": "ruler.alertmanager-client.oauth.client_secret",
"fieldType": "string"
},
{
"kind": "field",
"name": "token_url",
"required": false,
"desc": "Endpoint used to fetch access token.",
"fieldValue": null,
"fieldDefaultValue": "",
"fieldFlag": "ruler.alertmanager-client.oauth.token_url",
"fieldType": "string"
},
{
"kind": "field",
"name": "scopes",
"required": false,
"desc": "Optional scopes to include with the token request.",
"fieldValue": null,
"fieldDefaultValue": "",
"fieldFlag": "ruler.alertmanager-client.oauth.scopes",
"fieldType": "string"
}
],
"fieldValue": null,
"fieldDefaultValue": null
},
{
"kind": "field",
"name": "proxy_url",
"required": false,
"desc": "Optional HTTP, HTTPS via CONNECT, or SOCKS5 proxy URL to route requests through. Applies to all requests, including auxiliary traffic, such as OAuth token requests.",
"fieldValue": null,
"fieldDefaultValue": "",
"fieldFlag": "ruler.alertmanager-client.proxy-url",
"fieldType": "string",
"fieldCategory": "advanced"
}
],
"fieldValue": null,
Expand Down
10 changes: 10 additions & 0 deletions cmd/mimir/help-all.txt.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2821,6 +2821,16 @@ Usage of ./cmd/mimir/mimir:
HTTP Basic authentication password. It overrides the password set in the URL (if any).
-ruler.alertmanager-client.basic-auth-username string
HTTP Basic authentication username. It overrides the username set in the URL (if any).
-ruler.alertmanager-client.oauth.client_id string
OAuth2 client ID. Enables the use of OAuth2 for authenticating with Alertmanager.
-ruler.alertmanager-client.oauth.client_secret string
OAuth2 client secret.
-ruler.alertmanager-client.oauth.scopes comma-separated-list-of-strings
Optional scopes to include with the token request.
-ruler.alertmanager-client.oauth.token_url string
Endpoint used to fetch access token.
-ruler.alertmanager-client.proxy-url string
Optional HTTP, HTTPS via CONNECT, or SOCKS5 proxy URL to route requests through. Applies to all requests, including auxiliary traffic, such as OAuth token requests.
-ruler.alertmanager-client.tls-ca-path string
Path to the CA certificates to validate server certificate against. If not set, the host's root CA certificates are used.
-ruler.alertmanager-client.tls-cert-path string
Expand Down
8 changes: 8 additions & 0 deletions cmd/mimir/help.txt.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,14 @@ Usage of ./cmd/mimir/mimir:
HTTP Basic authentication password. It overrides the password set in the URL (if any).
-ruler.alertmanager-client.basic-auth-username string
HTTP Basic authentication username. It overrides the username set in the URL (if any).
-ruler.alertmanager-client.oauth.client_id string
OAuth2 client ID. Enables the use of OAuth2 for authenticating with Alertmanager.
-ruler.alertmanager-client.oauth.client_secret string
OAuth2 client secret.
-ruler.alertmanager-client.oauth.scopes comma-separated-list-of-strings
Optional scopes to include with the token request.
-ruler.alertmanager-client.oauth.token_url string
Endpoint used to fetch access token.
-ruler.alertmanager-url string
Comma-separated list of URL(s) of the Alertmanager(s) to send notifications to. Each URL is treated as a separate group. Multiple Alertmanagers in HA per group can be supported by using DNS service discovery format, comprehensive of the scheme. Basic auth is supported as part of the URL.
-ruler.enable-api
Expand Down
24 changes: 24 additions & 0 deletions docs/sources/mimir/configure/configuration-parameters/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1951,6 +1951,30 @@ alertmanager_client:
# CLI flag: -ruler.alertmanager-client.basic-auth-password
[basic_auth_password: <string> | default = ""]
oauth2:
# OAuth2 client ID. Enables the use of OAuth2 for authenticating with
# Alertmanager.
# CLI flag: -ruler.alertmanager-client.oauth.client_id
[client_id: <string> | default = ""]
# OAuth2 client secret.
# CLI flag: -ruler.alertmanager-client.oauth.client_secret
[client_secret: <string> | default = ""]
# Endpoint used to fetch access token.
# CLI flag: -ruler.alertmanager-client.oauth.token_url
[token_url: <string> | default = ""]
# Optional scopes to include with the token request.
# CLI flag: -ruler.alertmanager-client.oauth.scopes
[scopes: <string> | default = ""]
# (advanced) Optional HTTP, HTTPS via CONNECT, or SOCKS5 proxy URL to route
# requests through. Applies to all requests, including auxiliary traffic, such
# as OAuth token requests.
# CLI flag: -ruler.alertmanager-client.proxy-url
[proxy_url: <string> | default = ""]
# (advanced) Max time to tolerate outage for restoring "for" state of alert.
# CLI flag: -ruler.for-outage-tolerance
[for_outage_tolerance: <duration> | default = 1h]
Expand Down
59 changes: 58 additions & 1 deletion pkg/ruler/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/grafana/dskit/cache"
"github.com/grafana/dskit/cancellation"
"github.com/grafana/dskit/crypto/tls"
"github.com/grafana/dskit/flagext"
config_util "github.com/prometheus/common/config"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/config"
Expand All @@ -27,18 +28,43 @@ import (
"github.com/grafana/mimir/pkg/util"
)

var errRulerNotifierStopped = cancellation.NewErrorf("rulerNotifier stopped")
var (
errRulerNotifierStopped = cancellation.NewErrorf("rulerNotifier stopped")
errRulerSimultaneousBasicAuthAndOAuth = errors.New("cannot use both Basic Auth and OAuth2 simultaneously")
)

type NotifierConfig struct {
TLSEnabled bool `yaml:"tls_enabled" category:"advanced"`
TLS tls.ClientConfig `yaml:",inline"`
BasicAuth util.BasicAuth `yaml:",inline"`
OAuth2 OAuth2Config `yaml:"oauth2"`
ProxyURL string `yaml:"proxy_url" category:"advanced"`
}

func (cfg *NotifierConfig) RegisterFlags(f *flag.FlagSet) {
f.BoolVar(&cfg.TLSEnabled, "ruler.alertmanager-client.tls-enabled", true, "Enable TLS for gRPC client connecting to alertmanager.")
cfg.TLS.RegisterFlagsWithPrefix("ruler.alertmanager-client", f)
cfg.BasicAuth.RegisterFlagsWithPrefix("ruler.alertmanager-client.", f)
cfg.OAuth2.RegisterFlagsWithPrefix("ruler.alertmanager-client.oauth.", f)
f.StringVar(&cfg.ProxyURL, "ruler.alertmanager-client.proxy-url", "", "Optional HTTP, HTTPS via CONNECT, or SOCKS5 proxy URL to route requests through. Applies to all requests, including auxiliary traffic, such as OAuth token requests.")
}

type OAuth2Config struct {
ClientID string `yaml:"client_id"`
ClientSecret flagext.Secret `yaml:"client_secret"`
TokenURL string `yaml:"token_url"`
Scopes flagext.StringSliceCSV `yaml:"scopes,omitempty"`
}

func (cfg *OAuth2Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) {
f.StringVar(&cfg.ClientID, prefix+"client_id", "", "OAuth2 client ID. Enables the use of OAuth2 for authenticating with Alertmanager.")
f.Var(&cfg.ClientSecret, prefix+"client_secret", "OAuth2 client secret.")
f.StringVar(&cfg.TokenURL, prefix+"token_url", "", "Endpoint used to fetch access token.")
f.Var(&cfg.Scopes, prefix+"scopes", "Optional scopes to include with the token request.")
}

func (cfg *OAuth2Config) IsEnabled() bool {
return cfg.ClientID != "" || cfg.TokenURL != ""
}

// rulerNotifier bundles a notifier.Manager together with an associated
Expand Down Expand Up @@ -176,6 +202,37 @@ func amConfigWithSD(rulerConfig *Config, url *url.URL, sdConfig discovery.Config
}
}

// Whether to use an optional HTTP, HTTP+CONNECT, or SOCKS5 proxy.
if rulerConfig.Notifier.ProxyURL != "" {
url, err := url.Parse(rulerConfig.Notifier.ProxyURL)
if err != nil {
return nil, err
}
amConfig.HTTPClientConfig.ProxyURL = config_util.URL{URL: url}
}

// Whether to use OAuth2 or not.
if rulerConfig.Notifier.OAuth2.IsEnabled() {
if amConfig.HTTPClientConfig.BasicAuth != nil {
return nil, errRulerSimultaneousBasicAuthAndOAuth
}

amConfig.HTTPClientConfig.OAuth2 = &config_util.OAuth2{
ClientID: rulerConfig.Notifier.OAuth2.ClientID,
ClientSecret: config_util.Secret(rulerConfig.Notifier.OAuth2.ClientSecret.String()),
TokenURL: rulerConfig.Notifier.OAuth2.TokenURL,
Scopes: rulerConfig.Notifier.OAuth2.Scopes,
}

if rulerConfig.Notifier.ProxyURL != "" {
url, err := url.Parse(rulerConfig.Notifier.ProxyURL)
if err != nil {
return nil, err
}
amConfig.HTTPClientConfig.OAuth2.ProxyURL = config_util.URL{URL: url}
}
}

// Whether to use TLS or not.
if rulerConfig.Notifier.TLSEnabled {
if rulerConfig.Notifier.TLS.Reader == nil {
Expand Down
Loading

0 comments on commit c178c83

Please sign in to comment.