mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Support tls config for webhook receiver (#93513)
Adds the ability to configure tls settings on the webhook receiver (e.g. to skip server certificate validation)
This commit is contained in:
parent
d722a25084
commit
71d04a326b
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -194,6 +194,7 @@
|
|||||||
/devenv/dev-dashboards-without-uid/ @grafana/dashboards-squad
|
/devenv/dev-dashboards-without-uid/ @grafana/dashboards-squad
|
||||||
/devenv/dev-dashboards/ @grafana/dashboards-squad
|
/devenv/dev-dashboards/ @grafana/dashboards-squad
|
||||||
/devenv/docker/blocks/alert_webhook_listener/ @grafana/alerting-backend
|
/devenv/docker/blocks/alert_webhook_listener/ @grafana/alerting-backend
|
||||||
|
/devenv/docker/blocks/caddy_tls/ @grafana/alerting-backend
|
||||||
/devenv/docker/blocks/clickhouse/ @grafana/partner-datasources
|
/devenv/docker/blocks/clickhouse/ @grafana/partner-datasources
|
||||||
/devenv/docker/blocks/collectd/ @grafana/observability-metrics
|
/devenv/docker/blocks/collectd/ @grafana/observability-metrics
|
||||||
/devenv/docker/blocks/etcd @grafana/grafana-app-platform-squad
|
/devenv/docker/blocks/etcd @grafana/grafana-app-platform-squad
|
||||||
|
33
devenv/docker/blocks/caddy_tls/README.md
Normal file
33
devenv/docker/blocks/caddy_tls/README.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# TLS Caddy Server
|
||||||
|
|
||||||
|
Starts a [Caddy server](https://caddyserver.com/) with TLS configured.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
- Caddy is setup to run on port 2081, so when configuring the webhook receiver in Grafana Alerting you should use the
|
||||||
|
following the following URL: `https://localhost:2081`
|
||||||
|
- Also, Caddy is configured to use a self-signed certificate and to check the client certificate (`require_and_verify` mode)
|
||||||
|
- Caddy is setup to log requests and has debug mode enabled to make it easier to investigate possible issues
|
||||||
|
|
||||||
|
## TLS Certificates
|
||||||
|
|
||||||
|
If you want to configure a webhook contact point in Grafana Alerting with TLS, you need to provide a certificate and key.
|
||||||
|
|
||||||
|
You can find them in `/etc/caddy` directory in the container:
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
docker exec devenv-caddy_tls-1 ls /etc/caddy/
|
||||||
|
```
|
||||||
|
|
||||||
|
### CA Certificate
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
docker exec devenv-caddy_tls-1 cat /etc/caddy/ca.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
### Client certificates
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
docker exec devenv-caddy_tls-1 cat /etc/caddy/client.pem
|
||||||
|
docker exec devenv-caddy_tls-1 cat /etc/caddy/client.key
|
||||||
|
```
|
14
devenv/docker/blocks/caddy_tls/build/Caddyfile
Normal file
14
devenv/docker/blocks/caddy_tls/build/Caddyfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
debug
|
||||||
|
}
|
||||||
|
|
||||||
|
localhost:2081 {
|
||||||
|
log
|
||||||
|
tls /etc/caddy/server.pem /etc/caddy/server.key {
|
||||||
|
ca_root /etc/caddy/ca.pem
|
||||||
|
client_auth {
|
||||||
|
mode require_and_verify
|
||||||
|
trust_pool file /etc/caddy/client.pem /etc/caddy/ca.pem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
devenv/docker/blocks/caddy_tls/build/Dockerfile
Normal file
12
devenv/docker/blocks/caddy_tls/build/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
FROM caddy:2.8.4-alpine
|
||||||
|
|
||||||
|
WORKDIR /etc/caddy
|
||||||
|
EXPOSE 2081
|
||||||
|
|
||||||
|
COPY Caddyfile ./Caddyfile
|
||||||
|
COPY san.cnf ./san.cnf
|
||||||
|
COPY gen_certs.sh ./gen_certs.sh
|
||||||
|
|
||||||
|
RUN apk update && apk upgrade --no-cache && apk add openssl
|
||||||
|
|
||||||
|
RUN ./gen_certs.sh
|
17
devenv/docker/blocks/caddy_tls/build/gen_certs.sh
Executable file
17
devenv/docker/blocks/caddy_tls/build/gen_certs.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
DAYS_VALID=3650
|
||||||
|
|
||||||
|
# Create CA certificate
|
||||||
|
openssl genpkey -algorithm RSA -out ca.key
|
||||||
|
openssl req -new -x509 -days $DAYS_VALID -key ca.key -out ca.pem -subj "/CN=My CA"
|
||||||
|
|
||||||
|
# Create server certificate
|
||||||
|
openssl genpkey -algorithm RSA -out server.key
|
||||||
|
openssl req -new -key server.key -out server.csr -subj "/CN=localhost"
|
||||||
|
openssl x509 -req -days $DAYS_VALID -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out server.pem -extfile san.cnf -extensions v3_req
|
||||||
|
|
||||||
|
# Create client key and certificate
|
||||||
|
openssl genpkey -algorithm RSA -out client.key
|
||||||
|
openssl req -new -key client.key -out client.csr -subj "/CN=Client"
|
||||||
|
openssl x509 -req -days $DAYS_VALID -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client.pem -extfile san.cnf -extensions v3_req
|
7
devenv/docker/blocks/caddy_tls/build/san.cnf
Normal file
7
devenv/docker/blocks/caddy_tls/build/san.cnf
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[ v3_req ]
|
||||||
|
subjectAltName = @alt_names
|
||||||
|
|
||||||
|
[ alt_names ]
|
||||||
|
DNS.1 = localhost
|
||||||
|
IP.1 = 127.0.0.1
|
||||||
|
IP.2 = ::1
|
5
devenv/docker/blocks/caddy_tls/docker-compose.yaml
Normal file
5
devenv/docker/blocks/caddy_tls/docker-compose.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
caddy_tls:
|
||||||
|
build:
|
||||||
|
context: docker/blocks/caddy_tls/build
|
||||||
|
ports:
|
||||||
|
- "2081:2081"
|
@ -615,11 +615,21 @@ The following sections detail the supported settings and secure settings for eac
|
|||||||
#### Alert notification `webhook`
|
#### Alert notification `webhook`
|
||||||
|
|
||||||
| Name | Secure setting |
|
| Name | Secure setting |
|
||||||
| ---------- | -------------- |
|
| ----------- | -------------- |
|
||||||
| url | |
|
| url | |
|
||||||
| httpMethod | |
|
| http_method | |
|
||||||
| username | |
|
| username | |
|
||||||
| password | yes |
|
| password | yes |
|
||||||
|
| tls_config | |
|
||||||
|
|
||||||
|
##### TLS config
|
||||||
|
|
||||||
|
| Name | Secure setting |
|
||||||
|
| ------------------ | -------------- |
|
||||||
|
| insecureSkipVerify | |
|
||||||
|
| clientCertificate | yes |
|
||||||
|
| clientKey | yes |
|
||||||
|
| caCertificate | yes |
|
||||||
|
|
||||||
#### Alert notification `googlechat`
|
#### Alert notification `googlechat`
|
||||||
|
|
||||||
|
@ -616,6 +616,16 @@ settings:
|
|||||||
authorization_credentials: abc123
|
authorization_credentials: abc123
|
||||||
# <string>
|
# <string>
|
||||||
maxAlerts: '10'
|
maxAlerts: '10'
|
||||||
|
# <map>
|
||||||
|
tlsConfig:
|
||||||
|
# <bool>
|
||||||
|
insecureSkipVerify: false
|
||||||
|
# <string>
|
||||||
|
clientCertificate: certificate in PEM format
|
||||||
|
# <string>
|
||||||
|
clientKey: key in PEM format
|
||||||
|
# <string>
|
||||||
|
caCertificate: CA certificate in PEM format
|
||||||
```
|
```
|
||||||
|
|
||||||
{{< /collapse >}}
|
{{< /collapse >}}
|
||||||
|
2
go.mod
2
go.mod
@ -72,7 +72,7 @@ require (
|
|||||||
github.com/googleapis/gax-go/v2 v2.13.0 // @grafana/grafana-backend-group
|
github.com/googleapis/gax-go/v2 v2.13.0 // @grafana/grafana-backend-group
|
||||||
github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group
|
github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group
|
||||||
github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad
|
github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad
|
||||||
github.com/grafana/alerting v0.0.0-20241010165806-807ddf183724 // @grafana/alerting-backend
|
github.com/grafana/alerting v0.0.0-20241021123319-be61d61f71e7 // @grafana/alerting-backend
|
||||||
github.com/grafana/authlib v0.0.0-20241018103850-afc1195d8240 // @grafana/identity-access-team
|
github.com/grafana/authlib v0.0.0-20241018103850-afc1195d8240 // @grafana/identity-access-team
|
||||||
github.com/grafana/authlib/claims v0.0.0-20241018085709-130ad686d80e // @grafana/identity-access-team
|
github.com/grafana/authlib/claims v0.0.0-20241018085709-130ad686d80e // @grafana/identity-access-team
|
||||||
github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad
|
github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad
|
||||||
|
4
go.sum
4
go.sum
@ -2243,8 +2243,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY
|
|||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grafana/alerting v0.0.0-20241010165806-807ddf183724 h1:u+ZM5TLkdeEoSWXgYWxc4XRfPHhXpR63MyHXJxbBLrc=
|
github.com/grafana/alerting v0.0.0-20241021123319-be61d61f71e7 h1:lsM/QscEX+ZDIJm48ynQscH+msETyGYV6ug8L4f2DtM=
|
||||||
github.com/grafana/alerting v0.0.0-20241010165806-807ddf183724/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU=
|
github.com/grafana/alerting v0.0.0-20241021123319-be61d61f71e7/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU=
|
||||||
github.com/grafana/authlib v0.0.0-20241018103850-afc1195d8240 h1:bBn6sCbBjxjYlvs5JAIGHQSOs8xbDEBWbezxarA/DDo=
|
github.com/grafana/authlib v0.0.0-20241018103850-afc1195d8240 h1:bBn6sCbBjxjYlvs5JAIGHQSOs8xbDEBWbezxarA/DDo=
|
||||||
github.com/grafana/authlib v0.0.0-20241018103850-afc1195d8240/go.mod h1:RKqhn8E5PY2k5Xo6X8FHFgP45/qt9qqfAY7YYJ2mtB8=
|
github.com/grafana/authlib v0.0.0-20241018103850-afc1195d8240/go.mod h1:RKqhn8E5PY2k5Xo6X8FHFgP45/qt9qqfAY7YYJ2mtB8=
|
||||||
github.com/grafana/authlib/claims v0.0.0-20241018085709-130ad686d80e h1:I0sSXcqdt/ttiOJ/BVhpfa2q/xAyWSweQwaypGmvLss=
|
github.com/grafana/authlib/claims v0.0.0-20241018085709-130ad686d80e h1:I0sSXcqdt/ttiOJ/BVhpfa2q/xAyWSweQwaypGmvLss=
|
||||||
|
@ -297,6 +297,7 @@ type WebhookIntegration struct {
|
|||||||
Password *Secret `json:"password,omitempty" yaml:"password,omitempty" hcl:"basic_auth_password"`
|
Password *Secret `json:"password,omitempty" yaml:"password,omitempty" hcl:"basic_auth_password"`
|
||||||
Title *string `json:"title,omitempty" yaml:"title,omitempty" hcl:"title"`
|
Title *string `json:"title,omitempty" yaml:"title,omitempty" hcl:"title"`
|
||||||
Message *string `json:"message,omitempty" yaml:"message,omitempty" hcl:"message"`
|
Message *string `json:"message,omitempty" yaml:"message,omitempty" hcl:"message"`
|
||||||
|
TLSConfig *TLSConfig `json:"tlsConfig,omitempty" yaml:"tlsConfig,omitempty" hcl:"tlsConfig,block"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WecomIntegration struct {
|
type WecomIntegration struct {
|
||||||
|
@ -964,6 +964,48 @@ func GetAvailableNotifiers() []*NotifierPlugin {
|
|||||||
PropertyName: "message",
|
PropertyName: "message",
|
||||||
Placeholder: alertingTemplates.DefaultMessageEmbed,
|
Placeholder: alertingTemplates.DefaultMessageEmbed,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ func TestGetSecretKeysForContactPointType(t *testing.T) {
|
|||||||
{receiverType: "sensugo", expectedSecretFields: []string{"apikey"}},
|
{receiverType: "sensugo", expectedSecretFields: []string{"apikey"}},
|
||||||
{receiverType: "teams", expectedSecretFields: []string{}},
|
{receiverType: "teams", expectedSecretFields: []string{}},
|
||||||
{receiverType: "telegram", expectedSecretFields: []string{"bottoken"}},
|
{receiverType: "telegram", expectedSecretFields: []string{"bottoken"}},
|
||||||
{receiverType: "webhook", expectedSecretFields: []string{"password", "authorization_credentials"}},
|
{receiverType: "webhook", expectedSecretFields: []string{"password", "authorization_credentials", "tlsConfig.caCertificate", "tlsConfig.clientCertificate", "tlsConfig.clientKey"}},
|
||||||
{receiverType: "wecom", expectedSecretFields: []string{"url", "secret"}},
|
{receiverType: "wecom", expectedSecretFields: []string{"url", "secret"}},
|
||||||
{receiverType: "prometheus-alertmanager", expectedSecretFields: []string{"basicAuthPassword"}},
|
{receiverType: "prometheus-alertmanager", expectedSecretFields: []string{"basicAuthPassword"}},
|
||||||
{receiverType: "discord", expectedSecretFields: []string{"url"}},
|
{receiverType: "discord", expectedSecretFields: []string{"url"}},
|
||||||
|
@ -22,6 +22,7 @@ func (s sender) SendWebhook(ctx context.Context, cmd *receivers.SendWebhookSetti
|
|||||||
HttpHeader: cmd.HTTPHeader,
|
HttpHeader: cmd.HTTPHeader,
|
||||||
ContentType: cmd.ContentType,
|
ContentType: cmd.ContentType,
|
||||||
Validation: cmd.Validation,
|
Validation: cmd.Validation,
|
||||||
|
TLSConfig: cmd.TLSConfig,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package notifications
|
package notifications
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@ -42,6 +43,7 @@ type SendWebhookSync struct {
|
|||||||
HttpHeader map[string]string
|
HttpHeader map[string]string
|
||||||
ContentType string
|
ContentType string
|
||||||
Validation func(body []byte, statusCode int) error
|
Validation func(body []byte, statusCode int) error
|
||||||
|
TLSConfig *tls.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
type SendResetPasswordEmailCommand struct {
|
type SendResetPasswordEmailCommand struct {
|
||||||
|
@ -120,7 +120,6 @@ func (ns *NotificationService) Run(ctx context.Context) error {
|
|||||||
select {
|
select {
|
||||||
case webhook := <-ns.webhookQueue:
|
case webhook := <-ns.webhookQueue:
|
||||||
err := ns.sendWebRequestSync(context.Background(), webhook)
|
err := ns.sendWebRequestSync(context.Background(), webhook)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ns.log.Error("Failed to send webrequest ", "error", err)
|
ns.log.Error("Failed to send webrequest ", "error", err)
|
||||||
}
|
}
|
||||||
@ -155,6 +154,7 @@ func (ns *NotificationService) SendWebhookSync(ctx context.Context, cmd *SendWeb
|
|||||||
HttpMethod: cmd.HttpMethod,
|
HttpMethod: cmd.HttpMethod,
|
||||||
HttpHeader: cmd.HttpHeader,
|
HttpHeader: cmd.HttpHeader,
|
||||||
ContentType: cmd.ContentType,
|
ContentType: cmd.ContentType,
|
||||||
|
TLSConfig: cmd.TLSConfig,
|
||||||
Validation: cmd.Validation,
|
Validation: cmd.Validation,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -211,7 +211,6 @@ func (ns *NotificationService) SendEmailCommandHandlerSync(ctx context.Context,
|
|||||||
Subject: cmd.Subject,
|
Subject: cmd.Subject,
|
||||||
ReplyTo: cmd.ReplyTo,
|
ReplyTo: cmd.ReplyTo,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -222,7 +221,6 @@ func (ns *NotificationService) SendEmailCommandHandlerSync(ctx context.Context,
|
|||||||
|
|
||||||
func (ns *NotificationService) SendEmailCommandHandler(ctx context.Context, cmd *SendEmailCommand) error {
|
func (ns *NotificationService) SendEmailCommandHandler(ctx context.Context, cmd *SendEmailCommand) error {
|
||||||
message, err := ns.buildEmailMessage(cmd)
|
message, err := ns.buildEmailMessage(cmd)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -304,7 +302,6 @@ func (ns *NotificationService) signUpStartedHandler(ctx context.Context, evt *ev
|
|||||||
"SignUpUrl": setting.ToAbsUrl(fmt.Sprintf("signup/?email=%s&code=%s", url.QueryEscape(evt.Email), url.QueryEscape(evt.Code))),
|
"SignUpUrl": setting.ToAbsUrl(fmt.Sprintf("signup/?email=%s&code=%s", url.QueryEscape(evt.Email), url.QueryEscape(evt.Code))),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,3 @@ func NewFakeDisconnectedMailer() *FakeDisconnectedMailer {
|
|||||||
func (fdm *FakeDisconnectedMailer) Send(ctx context.Context, messages ...*Message) (int, error) {
|
func (fdm *FakeDisconnectedMailer) Send(ctx context.Context, messages ...*Message) (int, error) {
|
||||||
return 0, fmt.Errorf("connect: connection refused")
|
return 0, fmt.Errorf("connect: connection refused")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetClient is used to export original in test.
|
|
||||||
var NetClient = &netClient
|
|
||||||
|
|
||||||
// SetWebhookClient is used to mock in test.
|
|
||||||
func SetWebhookClient(client WebhookClient) {
|
|
||||||
netClient = client
|
|
||||||
}
|
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
|
||||||
|
alertingReceivers "github.com/grafana/alerting/receivers"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
@ -23,6 +23,7 @@ type Webhook struct {
|
|||||||
HttpMethod string
|
HttpMethod string
|
||||||
HttpHeader map[string]string
|
HttpHeader map[string]string
|
||||||
ContentType string
|
ContentType string
|
||||||
|
TLSConfig *tls.Config
|
||||||
|
|
||||||
// Validation is a function that will validate the response body and statusCode of the webhook. Any returned error will cause the webhook request to be considered failed.
|
// Validation is a function that will validate the response body and statusCode of the webhook. Any returned error will cause the webhook request to be considered failed.
|
||||||
// This can be useful when a webhook service communicates failures in creative ways, such as using the response body instead of the status code.
|
// This can be useful when a webhook service communicates failures in creative ways, such as using the response body instead of the status code.
|
||||||
@ -34,21 +35,6 @@ type WebhookClient interface {
|
|||||||
Do(req *http.Request) (*http.Response, error)
|
Do(req *http.Request) (*http.Response, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var netTransport = &http.Transport{
|
|
||||||
TLSClientConfig: &tls.Config{
|
|
||||||
Renegotiation: tls.RenegotiateFreelyAsClient,
|
|
||||||
},
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
Dial: (&net.Dialer{
|
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
}).Dial,
|
|
||||||
TLSHandshakeTimeout: 5 * time.Second,
|
|
||||||
}
|
|
||||||
var netClient WebhookClient = &http.Client{
|
|
||||||
Timeout: time.Second * 30,
|
|
||||||
Transport: netTransport,
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ns *NotificationService) sendWebRequestSync(ctx context.Context, webhook *Webhook) error {
|
func (ns *NotificationService) sendWebRequestSync(ctx context.Context, webhook *Webhook) error {
|
||||||
if webhook.HttpMethod == "" {
|
if webhook.HttpMethod == "" {
|
||||||
webhook.HttpMethod = http.MethodPost
|
webhook.HttpMethod = http.MethodPost
|
||||||
@ -85,7 +71,7 @@ func (ns *NotificationService) sendWebRequestSync(ctx context.Context, webhook *
|
|||||||
request.Header.Set(k, v)
|
request.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := netClient.Do(request)
|
resp, err := alertingReceivers.NewTLSClient(webhook.TLSConfig).Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return redactURL(err)
|
return redactURL(err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user