Skip to content

Commit

Permalink
Add support for event_grouping_setting of azurerm_sentinel_alert_rule…
Browse files Browse the repository at this point in the history
…_scheduled (#10078)

fixes #9725

Currently azurerm_sentinel_alert_rule_scheduled doesn't support grouping the events. So this PR is to implement it.

The EventGroupingSettings in rest api spec:
Azure/azure-rest-api-specs@96ba256/specification/securityinsights/resource-manager/Microsoft.SecurityInsights/preview/2019-01-01-preview/SecurityInsights.json#L9262
  • Loading branch information
Neil Ye authored Jan 19, 2021
1 parent 7b120be commit ef7f03d
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,24 @@ func resourceSentinelAlertRuleScheduled() *schema.Resource {
ValidateFunc: validation.StringIsNotEmpty,
},

"event_grouping": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"aggregation_method": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
string(securityinsight.AlertPerResult),
string(securityinsight.SingleAlert),
}, false),
},
},
},
},

"tactics": {
Type: schema.TypeSet,
Optional: true,
Expand Down Expand Up @@ -302,6 +320,10 @@ func resourceSentinelAlertRuleScheduledCreateUpdate(d *schema.ResourceData, meta
param.ScheduledAlertRuleProperties.AlertRuleTemplateName = utils.String(v.(string))
}

if v, ok := d.GetOk("event_grouping"); ok {
param.ScheduledAlertRuleProperties.EventGroupingSettings = expandAlertRuleScheduledEventGroupingSetting(v.([]interface{}))
}

// Service avoid concurrent update of this resource via checking the "etag" to guarantee it is the same value as last Read.
if !d.IsNewResource() {
resp, err := client.Get(ctx, workspaceID.ResourceGroup, "Microsoft.OperationalInsights", workspaceID.WorkspaceName, name)
Expand Down Expand Up @@ -380,6 +402,10 @@ func resourceSentinelAlertRuleScheduledRead(d *schema.ResourceData, meta interfa
d.Set("suppression_enabled", prop.SuppressionEnabled)
d.Set("suppression_duration", prop.SuppressionDuration)
d.Set("alert_rule_template_guid", prop.AlertRuleTemplateName)

if err := d.Set("event_grouping", flattenAlertRuleScheduledEventGroupingSetting(prop.EventGroupingSettings)); err != nil {
return fmt.Errorf("setting `event_grouping`: %+v", err)
}
}

return nil
Expand Down Expand Up @@ -483,6 +509,21 @@ func expandAlertRuleScheduledGrouping(input []interface{}) *securityinsight.Grou
return output
}

func expandAlertRuleScheduledEventGroupingSetting(input []interface{}) *securityinsight.EventGroupingSettings {
if len(input) == 0 || input[0] == nil {
return nil
}

v := input[0].(map[string]interface{})
result := securityinsight.EventGroupingSettings{}

if aggregationKind := v["aggregation_method"].(string); aggregationKind != "" {
result.AggregationKind = securityinsight.EventGroupingAggregationKind(aggregationKind)
}

return &result
}

func flattenAlertRuleScheduledGrouping(input *securityinsight.GroupingConfiguration) []interface{} {
if input == nil {
return []interface{}{}
Expand Down Expand Up @@ -520,3 +561,20 @@ func flattenAlertRuleScheduledGrouping(input *securityinsight.GroupingConfigurat
},
}
}

func flattenAlertRuleScheduledEventGroupingSetting(input *securityinsight.EventGroupingSettings) []interface{} {
if input == nil {
return []interface{}{}
}

var aggregationKind string
if input.AggregationKind != "" {
aggregationKind = string(input.AggregationKind)
}

return []interface{}{
map[string]interface{}{
"aggregation_method": aggregationKind,
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,28 @@ func TestAccSentinelAlertRuleScheduled_withAlertRuleTemplateGuid(t *testing.T) {
})
}

func TestAccSentinelAlertRuleScheduled_updateEventGroupingSetting(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_sentinel_alert_rule_scheduled", "test")
r := SentinelAlertRuleScheduledResource{}

data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.eventGroupingSetting(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.updateEventGroupingSetting(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func (t SentinelAlertRuleScheduledResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) {
id, err := parse.AlertRuleID(state.ID)
if err != nil {
Expand Down Expand Up @@ -217,6 +239,54 @@ QUERY
`, r.template(data), data.RandomInteger)
}

func (r SentinelAlertRuleScheduledResource) eventGroupingSetting(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_sentinel_alert_rule_scheduled" "test" {
name = "acctest-SentinelAlertRule-Sche-%d"
log_analytics_workspace_id = azurerm_log_analytics_workspace.test.id
display_name = "Some Rule"
severity = "Low"
alert_rule_template_guid = "65360bb0-8986-4ade-a89d-af3cf44d28aa"
query = <<QUERY
AzureActivity |
where OperationName == "Create or Update Virtual Machine" or OperationName =="Create Deployment" |
where ActivityStatus == "Succeeded" |
make-series dcount(ResourceId) default=0 on EventSubmissionTimestamp in range(ago(7d), now(), 1d) by Caller
QUERY
event_grouping {
aggregation_method = "SingleAlert"
}
}
`, r.template(data), data.RandomInteger)
}

func (r SentinelAlertRuleScheduledResource) updateEventGroupingSetting(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_sentinel_alert_rule_scheduled" "test" {
name = "acctest-SentinelAlertRule-Sche-%d"
log_analytics_workspace_id = azurerm_log_analytics_workspace.test.id
display_name = "Some Rule"
severity = "Low"
alert_rule_template_guid = "65360bb0-8986-4ade-a89d-af3cf44d28aa"
query = <<QUERY
AzureActivity |
where OperationName == "Create or Update Virtual Machine" or OperationName =="Create Deployment" |
where ActivityStatus == "Succeeded" |
make-series dcount(ResourceId) default=0 on EventSubmissionTimestamp in range(ago(7d), now(), 1d) by Caller
QUERY
event_grouping {
aggregation_method = "AlertPerResult"
}
}
`, r.template(data), data.RandomInteger)
}

func (SentinelAlertRuleScheduledResource) template(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
8 changes: 8 additions & 0 deletions website/docs/r/sentinel_alert_rule_scheduled.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ The following arguments are supported:

* `enabled` - (Optional) Should the Sentinel Scheduled Alert Rule be enabled? Defaults to `true`.

* `event_grouping` - (Optional) A `event_grouping` block as defined below.

* `incident_configuration` - (Optional) A `incident_configuration` block as defined below.

* `query_frequency` - (Optional) The ISO 8601 timespan duration between two consecutive queries. Defaults to `PT5H`.
Expand All @@ -87,6 +89,12 @@ The following arguments are supported:

---

A `event_grouping` block supports the following:

* `aggregation_method` - (Required) The aggregation type of grouping the events.

---

A `incident_configuration` block supports the following:

* `create_incident` - (Required) Whether to create an incident from alerts triggered by this Sentinel Scheduled Alert Rule?
Expand Down

0 comments on commit ef7f03d

Please sign in to comment.