Skip to content

Commit 7ec6735

Browse files
authored
Alerting: Update webhook receiver with hmac_config (#2335)
1 parent ee29cd1 commit 7ec6735

File tree

4 files changed

+144
-6
lines changed

4 files changed

+144
-6
lines changed

docs/resources/contact_point.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ Optional:
524524
- `basic_auth_user` (String) The username to use in basic auth headers attached to the request. If omitted, basic auth will not be used.
525525
- `disable_resolve_message` (Boolean) Whether to disable sending resolve messages. Defaults to `false`.
526526
- `headers` (Map of String) Custom headers to attach to the request.
527+
- `hmac_config` (Block Set, Max: 1) HMAC signature configuration options. (see [below for nested schema](#nestedblock--webhook--hmac_config))
527528
- `http_config` (Block Set, Max: 1) Common HTTP client options. (see [below for nested schema](#nestedblock--webhook--http_config))
528529
- `http_method` (String) The HTTP method to use in the request. Defaults to `POST`.
529530
- `max_alerts` (Number) The maximum number of alerts to send in a single request. This can be helpful in limiting the size of the request body. The default is 0, which indicates no limit.
@@ -537,6 +538,19 @@ Read-Only:
537538

538539
- `uid` (String) The UID of the contact point.
539540

541+
<a id="nestedblock--webhook--hmac_config"></a>
542+
### Nested Schema for `webhook.hmac_config`
543+
544+
Required:
545+
546+
- `secret` (String, Sensitive) The secret key used to generate the HMAC signature.
547+
548+
Optional:
549+
550+
- `header` (String) The header in which the HMAC signature will be included. Defaults to `X-Grafana-Alerting-Signature`.
551+
- `timestamp_header` (String) If set, the timestamp will be included in the HMAC signature. The value should be the name of the header to use.
552+
553+
540554
<a id="nestedblock--webhook--http_config"></a>
541555
### Nested Schema for `webhook.http_config`
542556

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
resource "grafana_contact_point" "receiver_types" {
2+
name = "Receiver Types since v11.6"
3+
4+
webhook {
5+
url = "http://hmac-minimal-webhook-url"
6+
hmac_config {
7+
secret = "test-hmac-minimal-secret"
8+
}
9+
}
10+
11+
webhook {
12+
url = "http://hmac-webhook-url"
13+
hmac_config {
14+
secret = "test-hmac-secret"
15+
header = "X-Grafana-Alerting-Signature"
16+
timestamp_header = "X-Grafana-Alerting-Timestamp"
17+
}
18+
}
19+
}

internal/resources/grafana/resource_alerting_contact_point_notifiers.go

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,12 +1133,14 @@ func (w webhookNotifier) meta() notifierMeta {
11331133
typeStr: "webhook",
11341134
desc: "A contact point that sends notifications to an arbitrary webhook, using the Prometheus webhook format defined here: https://prometheus.io/docs/alerting/latest/configuration/#webhook_config",
11351135
fieldMapper: withCommonHTTPConfigFieldMappers(map[string]fieldMapper{
1136-
"http_method": newKeyMapper("httpMethod"),
1137-
"basic_auth_user": newKeyMapper("username"),
1138-
"basic_auth_password": newKeyMapper("password"),
1139-
"max_alerts": newFieldMapper("maxAlerts", valueAsInt, valueAsInt),
1140-
"tls_config": newFieldMapper("tlsConfig", translateTLSConfigPack, translateTLSConfigUnpack),
1141-
"headers": omitEmptyMapper(),
1136+
"http_method": newKeyMapper("httpMethod"),
1137+
"basic_auth_user": newKeyMapper("username"),
1138+
"basic_auth_password": newKeyMapper("password"),
1139+
"max_alerts": newFieldMapper("maxAlerts", valueAsInt, valueAsInt),
1140+
"tls_config": newFieldMapper("tlsConfig", translateTLSConfigPack, translateTLSConfigUnpack),
1141+
"headers": omitEmptyMapper(),
1142+
"hmac_config": newKeyMapper("hmacConfig"),
1143+
"hmac_config.timestamp_header": newKeyMapper("timestampHeader"),
11421144
}),
11431145
}
11441146
}
@@ -1198,6 +1200,32 @@ func (w webhookNotifier) schema() *schema.Resource {
11981200
Sensitive: true,
11991201
Description: "Allows configuring TLS for the webhook notifier.",
12001202
}
1203+
r.Schema["hmac_config"] = &schema.Schema{
1204+
Type: schema.TypeSet,
1205+
Optional: true,
1206+
MaxItems: 1,
1207+
Description: "HMAC signature configuration options.",
1208+
Elem: &schema.Resource{
1209+
Schema: map[string]*schema.Schema{
1210+
"secret": {
1211+
Type: schema.TypeString,
1212+
Required: true,
1213+
Sensitive: true,
1214+
Description: "The secret key used to generate the HMAC signature.",
1215+
},
1216+
"header": {
1217+
Type: schema.TypeString,
1218+
Optional: true,
1219+
Description: "The header in which the HMAC signature will be included. Defaults to `X-Grafana-Alerting-Signature`.",
1220+
},
1221+
"timestamp_header": {
1222+
Type: schema.TypeString,
1223+
Optional: true,
1224+
Description: "If set, the timestamp will be included in the HMAC signature. The value should be the name of the header to use.",
1225+
},
1226+
},
1227+
},
1228+
}
12011229
r.Schema["headers"] = &schema.Schema{
12021230
Type: schema.TypeMap,
12031231
Optional: true,

internal/resources/grafana/resource_alerting_contact_point_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,83 @@ func TestAccContactPoint_notifiers11_4(t *testing.T) {
529529
})
530530
}
531531

532+
func TestAccContactPoint_notifiers11_6(t *testing.T) {
533+
testutils.CheckOSSTestsEnabled(t, ">=11.6.0")
534+
535+
var points models.ContactPoints
536+
537+
resource.ParallelTest(t, resource.TestCase{
538+
ProtoV5ProviderFactories: testutils.ProtoV5ProviderFactories,
539+
// Implicitly tests deletion.
540+
CheckDestroy: alertingContactPointCheckExists.destroyed(&points, nil),
541+
Steps: []resource.TestStep{
542+
// Multiple hmac_config blocks are not allowed.
543+
{
544+
Config: `
545+
resource "grafana_contact_point" "receiver_types" {
546+
name = "Receiver Types since v11.6"
547+
548+
webhook {
549+
url = "http://my-url"
550+
hmac_config {
551+
secret = "test-secret1"
552+
}
553+
hmac_config {
554+
secret = "test-secret2"
555+
}
556+
}
557+
}
558+
`,
559+
ExpectError: regexp.MustCompile(`Too many hmac_config blocks`),
560+
},
561+
// Secret field required.
562+
{
563+
Config: testutils.TestAccExampleWithReplace(t, "resources/grafana_contact_point/_acc_receiver_types_11_6.tf", map[string]string{
564+
`secret = "test-hmac-secret"`: ``,
565+
}),
566+
ExpectError: regexp.MustCompile(`Missing required argument`),
567+
},
568+
// Test creation.
569+
{
570+
Config: testutils.TestAccExample(t, "resources/grafana_contact_point/_acc_receiver_types_11_6.tf"),
571+
Check: resource.ComposeTestCheckFunc(
572+
checkAlertingContactPointExistsWithLength("grafana_contact_point.receiver_types", &points, 2),
573+
// webhook basic
574+
resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "webhook.#", "2"),
575+
resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "webhook.0.url", "http://hmac-minimal-webhook-url"),
576+
resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "webhook.1.url", "http://hmac-webhook-url"),
577+
578+
// New
579+
resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "webhook.0.hmac_config.0.secret", "test-hmac-minimal-secret"),
580+
resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "webhook.0.hmac_config.0.header", ""),
581+
resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "webhook.0.hmac_config.0.timestamp_header", ""),
582+
resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "webhook.1.hmac_config.0.secret", "test-hmac-secret"),
583+
resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "webhook.1.hmac_config.0.header", "X-Grafana-Alerting-Signature"),
584+
resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "webhook.1.hmac_config.0.timestamp_header", "X-Grafana-Alerting-Timestamp"),
585+
586+
// Ensure that we're sending the grafana-style fiel names to the API by checking the GET response.
587+
func(s *terraform.State) error {
588+
found := false
589+
for _, p := range points {
590+
hmacConfig, ok := p.Settings.(map[string]interface{})["hmacConfig"]
591+
if !ok {
592+
return fmt.Errorf("hmacConfig was not present in the settings when it should have been. value: %#v", p.Settings)
593+
}
594+
if _, ok := hmacConfig.(map[string]interface{})["timestampHeader"]; ok {
595+
found = true
596+
}
597+
}
598+
if !found {
599+
return fmt.Errorf("timestampHeader was not present in any hmacConfig when it should have been. Settings: [%v, %v]", points[0].Settings, points[1].Settings)
600+
}
601+
return nil
602+
},
603+
),
604+
},
605+
},
606+
})
607+
}
608+
532609
func TestAccContactPoint_notifiers12_0(t *testing.T) {
533610
testutils.CheckOSSTestsEnabled(t, ">=12.0.0")
534611

0 commit comments

Comments
 (0)