Skip to content

Commit

Permalink
New resource: azurerm_sentinel_alert_rule_nrt (#15999)
Browse files Browse the repository at this point in the history
  • Loading branch information
magodo authored Aug 30, 2022
1 parent 8733bfe commit 0901fb2
Show file tree
Hide file tree
Showing 9 changed files with 1,371 additions and 293 deletions.
1 change: 1 addition & 0 deletions internal/services/sentinel/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource {
"azurerm_sentinel_alert_rule_machine_learning_behavior_analytics": resourceSentinelAlertRuleMLBehaviorAnalytics(),
"azurerm_sentinel_alert_rule_ms_security_incident": resourceSentinelAlertRuleMsSecurityIncident(),
"azurerm_sentinel_alert_rule_scheduled": resourceSentinelAlertRuleScheduled(),
"azurerm_sentinel_alert_rule_nrt": resourceSentinelAlertRuleNrt(),
"azurerm_sentinel_data_connector_aws_cloud_trail": resourceSentinelDataConnectorAwsCloudTrail(),
"azurerm_sentinel_data_connector_azure_active_directory": resourceSentinelDataConnectorAzureActiveDirectory(),
"azurerm_sentinel_data_connector_azure_advanced_threat_protection": resourceSentinelDataConnectorAzureAdvancedThreatProtection(),
Expand Down
311 changes: 311 additions & 0 deletions internal/services/sentinel/sentinel_alert_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/sentinel/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func alertRuleID(rule securityinsight.BasicAlertRule) *string {
Expand All @@ -23,6 +24,8 @@ func alertRuleID(rule securityinsight.BasicAlertRule) *string {
return rule.ID
case securityinsight.MLBehaviorAnalyticsAlertRule:
return rule.ID
case securityinsight.NrtAlertRule:
return rule.ID
default:
return nil
}
Expand Down Expand Up @@ -59,9 +62,317 @@ func assertAlertRuleKind(rule securityinsight.BasicAlertRule, expectKind securit
kind = securityinsight.AlertRuleKindMicrosoftSecurityIncidentCreation
case securityinsight.ScheduledAlertRule:
kind = securityinsight.AlertRuleKindScheduled
case securityinsight.NrtAlertRule:
kind = securityinsight.AlertRuleKindNRT
}
if expectKind != kind {
return fmt.Errorf("Sentinel Alert Rule has mismatched kind, expected: %q, got %q", expectKind, kind)
}
return nil
}

func expandAlertRuleTactics(input []interface{}) *[]securityinsight.AttackTactic {
result := make([]securityinsight.AttackTactic, 0)

for _, e := range input {
result = append(result, securityinsight.AttackTactic(e.(string)))
}

return &result
}

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

output := make([]interface{}, 0)

for _, e := range *input {
output = append(output, string(e))
}

return output
}

func expandAlertRuleIncidentConfiguration(input []interface{}, createIncidentKey string, withGroupByPrefix bool) *securityinsight.IncidentConfiguration {
if len(input) == 0 || input[0] == nil {
return nil
}

raw := input[0].(map[string]interface{})

output := &securityinsight.IncidentConfiguration{
CreateIncident: utils.Bool(raw[createIncidentKey].(bool)),
GroupingConfiguration: expandAlertRuleGrouping(raw["grouping"].([]interface{}), withGroupByPrefix),
}

return output
}

func flattenAlertRuleIncidentConfiguration(input *securityinsight.IncidentConfiguration, createIncidentKey string, withGroupByPrefix bool) []interface{} {
if input == nil {
return []interface{}{}
}

createIncident := false
if input.CreateIncident != nil {
createIncident = *input.CreateIncident
}

return []interface{}{
map[string]interface{}{
createIncidentKey: createIncident,
"grouping": flattenAlertRuleGrouping(input.GroupingConfiguration, withGroupByPrefix),
},
}
}

func expandAlertRuleGrouping(input []interface{}, withGroupPrefix bool) *securityinsight.GroupingConfiguration {
if len(input) == 0 || input[0] == nil {
return nil
}

raw := input[0].(map[string]interface{})

output := &securityinsight.GroupingConfiguration{
Enabled: utils.Bool(raw["enabled"].(bool)),
ReopenClosedIncident: utils.Bool(raw["reopen_closed_incidents"].(bool)),
LookbackDuration: utils.String(raw["lookback_duration"].(string)),
MatchingMethod: securityinsight.MatchingMethod(raw["entity_matching_method"].(string)),
}

key := "by_entities"
if withGroupPrefix {
key = "group_" + key
}
groupByEntitiesList := raw[key].([]interface{})
groupByEntities := make([]securityinsight.EntityMappingType, len(groupByEntitiesList))
for idx, t := range groupByEntitiesList {
groupByEntities[idx] = securityinsight.EntityMappingType(t.(string))
}
output.GroupByEntities = &groupByEntities

key = "by_alert_details"
if withGroupPrefix {
key = "group_" + key
}
groupByAlertDetailsList := raw[key].([]interface{})
groupByAlertDetails := make([]securityinsight.AlertDetail, len(groupByAlertDetailsList))
for idx, t := range groupByAlertDetailsList {
groupByAlertDetails[idx] = securityinsight.AlertDetail(t.(string))
}
output.GroupByAlertDetails = &groupByAlertDetails

key = "by_custom_details"
if withGroupPrefix {
key = "group_" + key
}
output.GroupByCustomDetails = utils.ExpandStringSlice(raw[key].([]interface{}))

return output
}

func flattenAlertRuleGrouping(input *securityinsight.GroupingConfiguration, withGroupPrefix bool) []interface{} {
if input == nil {
return []interface{}{}
}

enabled := false
if input.Enabled != nil {
enabled = *input.Enabled
}

lookbackDuration := ""
if input.LookbackDuration != nil {
lookbackDuration = *input.LookbackDuration
}

reopenClosedIncidents := false
if input.ReopenClosedIncident != nil {
reopenClosedIncidents = *input.ReopenClosedIncident
}

var groupByEntities []interface{}
if input.GroupByEntities != nil {
for _, entity := range *input.GroupByEntities {
groupByEntities = append(groupByEntities, string(entity))
}
}

var groupByAlertDetails []interface{}
if input.GroupByAlertDetails != nil {
for _, detail := range *input.GroupByAlertDetails {
groupByAlertDetails = append(groupByAlertDetails, string(detail))
}
}

var groupByCustomDetails []interface{}
if input.GroupByCustomDetails != nil {
for _, detail := range *input.GroupByCustomDetails {
groupByCustomDetails = append(groupByCustomDetails, detail)
}
}

var (
k1 = "by_entities"
k2 = "by_alert_details"
k3 = "by_custom_details"
)

if withGroupPrefix {
k1 = "group_" + k1
k2 = "group_" + k2
k3 = "group_" + k3
}
return []interface{}{
map[string]interface{}{
"enabled": enabled,
"lookback_duration": lookbackDuration,
"reopen_closed_incidents": reopenClosedIncidents,
"entity_matching_method": string(input.MatchingMethod),
k1: groupByEntities,
k2: groupByAlertDetails,
k3: groupByCustomDetails,
},
}
}

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

b := input[0].(map[string]interface{})
output := &securityinsight.AlertDetailsOverride{}

if v := b["description_format"]; v != "" {
output.AlertDescriptionFormat = utils.String(v.(string))
}
if v := b["display_name_format"]; v != "" {
output.AlertDisplayNameFormat = utils.String(v.(string))
}
if v := b["severity_column_name"]; v != "" {
output.AlertSeverityColumnName = utils.String(v.(string))
}
if v := b["tactics_column_name"]; v != "" {
output.AlertTacticsColumnName = utils.String(v.(string))
}

return output
}

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

var descriptionFormat string
if input.AlertDescriptionFormat != nil {
descriptionFormat = *input.AlertDescriptionFormat
}

var displayNameFormat string
if input.AlertDisplayNameFormat != nil {
displayNameFormat = *input.AlertDisplayNameFormat
}

var severityColumnName string
if input.AlertSeverityColumnName != nil {
severityColumnName = *input.AlertSeverityColumnName
}

var tacticsColumnName string
if input.AlertTacticsColumnName != nil {
tacticsColumnName = *input.AlertTacticsColumnName
}

return []interface{}{
map[string]interface{}{
"description_format": descriptionFormat,
"display_name_format": displayNameFormat,
"severity_column_name": severityColumnName,
"tactics_column_name": tacticsColumnName,
},
}
}

func expandAlertRuleEntityMapping(input []interface{}) *[]securityinsight.EntityMapping {
if len(input) == 0 {
return nil
}

result := make([]securityinsight.EntityMapping, 0)

for _, e := range input {
b := e.(map[string]interface{})
result = append(result, securityinsight.EntityMapping{
EntityType: securityinsight.EntityMappingType(b["entity_type"].(string)),
FieldMappings: expandAlertRuleFieldMapping(b["field_mapping"].([]interface{})),
})
}

return &result
}

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

output := make([]interface{}, 0)

for _, e := range *input {
output = append(output, map[string]interface{}{
"entity_type": string(e.EntityType),
"field_mapping": flattenAlertRuleFieldMapping(e.FieldMappings),
})
}

return output
}

func expandAlertRuleFieldMapping(input []interface{}) *[]securityinsight.FieldMapping {
if len(input) == 0 {
return nil
}

result := make([]securityinsight.FieldMapping, 0)

for _, e := range input {
b := e.(map[string]interface{})
result = append(result, securityinsight.FieldMapping{
Identifier: utils.String(b["identifier"].(string)),
ColumnName: utils.String(b["column_name"].(string)),
})
}

return &result
}

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

output := make([]interface{}, 0)

for _, e := range *input {
var identifier string
if e.Identifier != nil {
identifier = *e.Identifier
}

var columnName string
if e.ColumnName != nil {
columnName = *e.ColumnName
}

output = append(output, map[string]interface{}{
"identifier": identifier,
"column_name": columnName,
})
}

return output
}
Loading

0 comments on commit 0901fb2

Please sign in to comment.