Alerting: Add OAuth2 Support for Webhook Receiver (#106302)

* Add to available channels

* Export

* Fix bug in deeply nested secrets

BE: Slice re-use bug when traversing deeply.

FE: Only at most one level of nesting was being taken into account
when determining secureFields keys. This change adds a new field on
NotificationChannelOption: secureFieldKey. This is populated on API GET via
transform. This change gives us the option to hardcode secureFieldKey in the
backend and no longer calculate the key via settings topology.

* Update grafana/alerting to 3e20fda3b872

* Prettier

* Linting

* Fix IntegrationConfig test to catch secure field mismatch
This commit is contained in:
Matthew Jacobson
2025-06-12 23:00:09 +02:00
committed by GitHub
parent 5135d5c87d
commit 0016b57486
16 changed files with 697 additions and 82 deletions
@@ -113,6 +113,163 @@ func GetAvailableNotifiers() []*NotifierPlugin {
},
}
tlsSubformOptions := func() []NotifierOption {
return []NotifierOption{
{
Label: "Disable certificate verification",
Element: ElementTypeCheckbox,
Description: "Do not verify the server's certificate chain and host name.",
PropertyName: "insecureSkipVerify",
Required: false,
},
{
Label: "CA Certificate",
Element: ElementTypeTextArea,
Description: "Certificate in PEM format to use when verifying the server's certificate chain.",
InputType: InputTypeText,
PropertyName: "caCertificate",
Required: false,
Secure: true,
},
{
Label: "Client Certificate",
Element: ElementTypeTextArea,
Description: "Client certificate in PEM format to use when connecting to the server.",
InputType: InputTypeText,
PropertyName: "clientCertificate",
Required: false,
Secure: true,
},
{
Label: "Client Key",
Element: ElementTypeTextArea,
Description: "Client key in PEM format to use when connecting to the server.",
InputType: InputTypeText,
PropertyName: "clientKey",
Required: false,
Secure: true,
},
}
}
proxyOption := func() NotifierOption {
return NotifierOption{ // New in 12.1.
Label: "Proxy Config",
PropertyName: "proxy_config",
Description: "Optional proxy configuration.",
Element: ElementTypeSubform,
SubformOptions: []NotifierOption{
{
Label: "Proxy URL",
PropertyName: "proxy_url",
Description: "HTTP proxy server to use to connect to the targets.",
Element: ElementTypeInput,
InputType: InputTypeText,
Placeholder: "https://proxy.example.com",
Required: false,
Secure: false,
},
{
Label: "Proxy from environment",
PropertyName: "proxy_from_environment",
Description: "Use environment HTTP_PROXY, HTTPS_PROXY and NO_PROXY to determine proxies.",
Element: ElementTypeCheckbox,
Required: false,
Secure: false,
},
{
Label: "No Proxy",
PropertyName: "no_proxy",
Description: "Comma-separated list of addresses that should not use a proxy.",
Element: ElementTypeInput,
InputType: InputTypeText,
Placeholder: "example.com,1.2.3.4",
Required: false,
Secure: false,
},
{
Label: "Proxy Connect Header",
PropertyName: "proxy_connect_header",
Description: "Optional headers to send to proxies during CONNECT requests.",
Element: ElementTypeKeyValueMap,
InputType: InputTypeText,
Required: false,
Secure: false,
},
},
}
}
commonHttpClientOption := func() NotifierOption {
return NotifierOption{ // New in 12.1.
Label: "HTTP Config",
PropertyName: "http_config",
Description: "Common HTTP client options.",
Element: ElementTypeSubform,
SubformOptions: []NotifierOption{
{ // New in 12.1.
Label: "OAuth2",
PropertyName: "oauth2",
Description: "OAuth2 configuration options",
Element: ElementTypeSubform,
SubformOptions: []NotifierOption{
{
Label: "Token URL",
PropertyName: "token_url",
Element: ElementTypeInput,
Description: "URL for the access token endpoint.",
InputType: InputTypeText,
Required: true,
Secure: false,
},
{
Label: "Client ID",
PropertyName: "client_id",
Element: ElementTypeInput,
Description: "Client ID to use when authenticating.",
InputType: InputTypeText,
Required: true,
Secure: false,
},
{
Label: "Client Secret",
PropertyName: "client_secret",
Element: ElementTypeInput,
Description: "Client secret to use when authenticating.",
InputType: InputTypeText,
Required: true,
Secure: true,
},
{
Label: "Scopes",
PropertyName: "scopes",
Element: ElementStringArray,
Description: "Optional scopes to request when obtaining an access token.",
Required: false,
Secure: false,
},
{
Label: "Endpoint Parameters",
PropertyName: "endpoint_params",
Element: ElementTypeKeyValueMap,
Description: "Optional parameters to append to the access token request.",
Required: false,
Secure: false,
},
{
Label: "TLS",
PropertyName: "tls_config",
Description: "Optional TLS configuration options for OAuth2 requests.",
Element: ElementTypeSubform,
SubformOptions: tlsSubformOptions(),
},
proxyOption(),
},
},
},
}
}
return []*NotifierPlugin{
{
Type: "dingding",
@@ -1006,46 +1163,11 @@ func GetAvailableNotifiers() []*NotifierPlugin {
},
{
Label: "TLS",
PropertyName: "tlsConfig",
Description: "TLS configuration options",
Element: ElementTypeSubform,
SubformOptions: []NotifierOption{
{
Label: "Disable certificate verification",
Element: ElementTypeCheckbox,
Description: "Do not verify the server's certificate chain and host name.",
PropertyName: "insecureSkipVerify",
Required: false,
},
{
Label: "CA Certificate",
Element: ElementTypeTextArea,
Description: "Certificate in PEM format to use when verifying the server's certificate chain.",
InputType: InputTypeText,
PropertyName: "caCertificate",
Required: false,
Secure: true,
},
{
Label: "Client Certificate",
Element: ElementTypeTextArea,
Description: "Client certificate in PEM format to use when connecting to the server.",
InputType: InputTypeText,
PropertyName: "clientCertificate",
Required: false,
Secure: true,
},
{
Label: "Client Key",
Element: ElementTypeTextArea,
Description: "Client key in PEM format to use when connecting to the server.",
InputType: InputTypeText,
PropertyName: "clientKey",
Required: false,
Secure: true,
},
},
Label: "TLS",
PropertyName: "tlsConfig",
Description: "TLS configuration options",
Element: ElementTypeSubform,
SubformOptions: tlsSubformOptions(),
},
{
Label: "HMAC Signature",
@@ -1083,6 +1205,7 @@ func GetAvailableNotifiers() []*NotifierPlugin {
},
},
},
commonHttpClientOption(), // New in 12.1.
},
},
{
@@ -22,7 +22,18 @@ func TestGetSecretKeysForContactPointType(t *testing.T) {
{receiverType: "sensugo", expectedSecretFields: []string{"apikey"}},
{receiverType: "teams", expectedSecretFields: []string{}},
{receiverType: "telegram", expectedSecretFields: []string{"bottoken"}},
{receiverType: "webhook", expectedSecretFields: []string{"password", "authorization_credentials", "tlsConfig.caCertificate", "tlsConfig.clientCertificate", "tlsConfig.clientKey", "hmacConfig.secret"}},
{receiverType: "webhook", expectedSecretFields: []string{
"password",
"authorization_credentials",
"tlsConfig.caCertificate",
"tlsConfig.clientCertificate",
"tlsConfig.clientKey",
"hmacConfig.secret",
"http_config.oauth2.client_secret",
"http_config.oauth2.tls_config.caCertificate",
"http_config.oauth2.tls_config.clientCertificate",
"http_config.oauth2.tls_config.clientKey",
}},
{receiverType: "wecom", expectedSecretFields: []string{"url", "secret"}},
{receiverType: "prometheus-alertmanager", expectedSecretFields: []string{"basicAuthPassword"}},
{receiverType: "discord", expectedSecretFields: []string{"url"}},