-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
azurerm_sentinel_alert_rule_scheduled - support for
group_by_{alert|custom}_details,
alert_details_override,
entity_mapping,
custom_details`
#15901
Changes from 1 commit
4c584cb
d574567
24b9bb3
9ce9714
0b122f5
f13d3ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,26 @@ var entityMatchingMethodMap = map[string]string{ | |
} | ||
|
||
func resourceSentinelAlertRuleScheduled() *pluginsdk.Resource { | ||
var entityMappingTypes = []string{ | ||
string(securityinsight.EntityMappingTypeAccount), | ||
string(securityinsight.EntityMappingTypeAzureResource), | ||
string(securityinsight.EntityMappingTypeCloudApplication), | ||
string(securityinsight.EntityMappingTypeDNS), | ||
string(securityinsight.EntityMappingTypeFile), | ||
string(securityinsight.EntityMappingTypeFileHash), | ||
string(securityinsight.EntityMappingTypeHost), | ||
string(securityinsight.EntityMappingTypeIP), | ||
string(securityinsight.EntityMappingTypeMailbox), | ||
string(securityinsight.EntityMappingTypeMailCluster), | ||
string(securityinsight.EntityMappingTypeMailMessage), | ||
string(securityinsight.EntityMappingTypeMalware), | ||
string(securityinsight.EntityMappingTypeProcess), | ||
string(securityinsight.EntityMappingTypeRegistryKey), | ||
string(securityinsight.EntityMappingTypeRegistryValue), | ||
string(securityinsight.EntityMappingTypeSecurityGroup), | ||
string(securityinsight.EntityMappingTypeSubmissionMail), | ||
string(securityinsight.EntityMappingTypeURL), | ||
} | ||
return &pluginsdk.Resource{ | ||
Create: resourceSentinelAlertRuleScheduledCreateUpdate, | ||
Read: resourceSentinelAlertRuleScheduledRead, | ||
|
@@ -74,6 +94,12 @@ func resourceSentinelAlertRuleScheduled() *pluginsdk.Resource { | |
ValidateFunc: validation.IsUUID, | ||
}, | ||
|
||
"alert_rule_template_version": { | ||
Type: pluginsdk.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"description": { | ||
Type: pluginsdk.TypeString, | ||
Optional: true, | ||
|
@@ -184,30 +210,31 @@ func resourceSentinelAlertRuleScheduled() *pluginsdk.Resource { | |
}, | ||
}, | ||
"group_by": { | ||
Type: pluginsdk.TypeSet, | ||
Optional: true, | ||
Elem: &pluginsdk.Schema{ | ||
Type: pluginsdk.TypeString, | ||
ValidateFunc: validation.StringInSlice(entityMappingTypes, false), | ||
}, | ||
}, | ||
"group_by_alert_details": { | ||
Type: pluginsdk.TypeSet, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (as below) a GroupBy would be an order-statement in other cases, so is order relevant here/should this be a List? |
||
Optional: true, | ||
Elem: &pluginsdk.Schema{ | ||
Type: pluginsdk.TypeString, | ||
ValidateFunc: validation.StringInSlice([]string{ | ||
string(securityinsight.EntityMappingTypeAccount), | ||
string(securityinsight.EntityMappingTypeAzureResource), | ||
string(securityinsight.EntityMappingTypeCloudApplication), | ||
string(securityinsight.EntityMappingTypeDNS), | ||
string(securityinsight.EntityMappingTypeFile), | ||
string(securityinsight.EntityMappingTypeFileHash), | ||
string(securityinsight.EntityMappingTypeHost), | ||
string(securityinsight.EntityMappingTypeIP), | ||
string(securityinsight.EntityMappingTypeMailbox), | ||
string(securityinsight.EntityMappingTypeMailCluster), | ||
string(securityinsight.EntityMappingTypeMailMessage), | ||
string(securityinsight.EntityMappingTypeMalware), | ||
string(securityinsight.EntityMappingTypeProcess), | ||
string(securityinsight.EntityMappingTypeRegistryKey), | ||
string(securityinsight.EntityMappingTypeRegistryValue), | ||
string(securityinsight.EntityMappingTypeSecurityGroup), | ||
string(securityinsight.EntityMappingTypeSubmissionMail), | ||
string(securityinsight.EntityMappingTypeURL), | ||
}, false), | ||
string(securityinsight.AlertDetailDisplayName), | ||
string(securityinsight.AlertDetailSeverity), | ||
}, | ||
false), | ||
}, | ||
}, | ||
"group_by_custom_details": { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. given this is a GroupBy, this'd be implicitly ordered - so should this be a List? |
||
Type: pluginsdk.TypeSet, | ||
Optional: true, | ||
Elem: &pluginsdk.Schema{ | ||
Type: pluginsdk.TypeString, | ||
ValidateFunc: validation.StringIsNotEmpty, | ||
}, | ||
}, | ||
}, | ||
|
@@ -284,6 +311,75 @@ func resourceSentinelAlertRuleScheduled() *pluginsdk.Resource { | |
Default: "PT5H", | ||
ValidateFunc: validate.ISO8601DurationBetween("PT5M", "PT24H"), | ||
}, | ||
"alert_details_override": { | ||
Type: pluginsdk.TypeList, | ||
Optional: true, | ||
Elem: &pluginsdk.Resource{ | ||
Schema: map[string]*pluginsdk.Schema{ | ||
"description_format": { | ||
Type: pluginsdk.TypeString, | ||
Optional: true, | ||
ValidateFunc: validation.StringIsNotEmpty, | ||
}, | ||
"display_name_format": { | ||
Type: pluginsdk.TypeString, | ||
Optional: true, | ||
ValidateFunc: validation.StringIsNotEmpty, | ||
}, | ||
"severity_column_name": { | ||
Type: pluginsdk.TypeString, | ||
Optional: true, | ||
ValidateFunc: validation.StringIsNotEmpty, | ||
}, | ||
"tactics_column_name": { | ||
Type: pluginsdk.TypeString, | ||
Optional: true, | ||
ValidateFunc: validation.StringIsNotEmpty, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"custom_details": { | ||
Type: pluginsdk.TypeMap, | ||
Optional: true, | ||
Elem: &pluginsdk.Schema{ | ||
Type: pluginsdk.TypeString, | ||
ValidateFunc: validation.StringIsNotEmpty, | ||
}, | ||
}, | ||
"entity_mapping": { | ||
Type: pluginsdk.TypeList, | ||
Optional: true, | ||
MaxItems: 5, | ||
Elem: &pluginsdk.Resource{ | ||
Schema: map[string]*pluginsdk.Schema{ | ||
"entity_type": { | ||
Type: pluginsdk.TypeString, | ||
Required: true, | ||
ValidateFunc: validation.StringInSlice(entityMappingTypes, false), | ||
}, | ||
"field_mapping": { | ||
Type: pluginsdk.TypeList, | ||
MaxItems: 3, | ||
Required: true, | ||
Elem: &pluginsdk.Resource{ | ||
Schema: map[string]*pluginsdk.Schema{ | ||
"identifier": { | ||
Type: pluginsdk.TypeString, | ||
Required: true, | ||
ValidateFunc: validation.StringIsNotEmpty, | ||
}, | ||
"column_name": { | ||
Type: pluginsdk.TypeString, | ||
Required: true, | ||
ValidateFunc: validation.StringIsNotEmpty, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
@@ -358,10 +454,21 @@ func resourceSentinelAlertRuleScheduledCreateUpdate(d *pluginsdk.ResourceData, m | |
if v, ok := d.GetOk("alert_rule_template_guid"); ok { | ||
param.ScheduledAlertRuleProperties.AlertRuleTemplateName = utils.String(v.(string)) | ||
} | ||
|
||
if v, ok := d.GetOk("alert_rule_template_version"); ok { | ||
param.ScheduledAlertRuleProperties.TemplateVersion = utils.String(v.(string)) | ||
} | ||
if v, ok := d.GetOk("event_grouping"); ok { | ||
param.ScheduledAlertRuleProperties.EventGroupingSettings = expandAlertRuleScheduledEventGroupingSetting(v.([]interface{})) | ||
} | ||
if v, ok := d.GetOk("alert_details_override"); ok { | ||
param.ScheduledAlertRuleProperties.AlertDetailsOverride = expandAlertRuleScheduledAlertDetailsOverride(v.([]interface{})) | ||
} | ||
if v, ok := d.GetOk("custom_details"); ok { | ||
param.ScheduledAlertRuleProperties.CustomDetails = utils.ExpandMapStringPtrString(v.(map[string]interface{})) | ||
} | ||
if v, ok := d.GetOk("entity_mapping"); ok { | ||
param.ScheduledAlertRuleProperties.EntityMappings = expandAlertRuleScheduledEntityMapping(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() { | ||
|
@@ -441,10 +548,20 @@ func resourceSentinelAlertRuleScheduledRead(d *pluginsdk.ResourceData, meta inte | |
d.Set("suppression_enabled", prop.SuppressionEnabled) | ||
d.Set("suppression_duration", prop.SuppressionDuration) | ||
d.Set("alert_rule_template_guid", prop.AlertRuleTemplateName) | ||
d.Set("alert_rule_template_version", prop.TemplateVersion) | ||
|
||
if err := d.Set("event_grouping", flattenAlertRuleScheduledEventGroupingSetting(prop.EventGroupingSettings)); err != nil { | ||
return fmt.Errorf("setting `event_grouping`: %+v", err) | ||
} | ||
if err := d.Set("alert_details_override", flattenAlertRuleScheduledAlertDetailsOverride(prop.AlertDetailsOverride)); err != nil { | ||
return fmt.Errorf("setting `alert_details_override`: %+v", err) | ||
} | ||
if err := d.Set("custom_details", utils.FlattenMapStringPtrString(prop.CustomDetails)); err != nil { | ||
return fmt.Errorf("setting `custom_details`: %+v", err) | ||
} | ||
if err := d.Set("entity_mapping", flattenAlertRuleScheduledEntityMapping(prop.EntityMappings)); err != nil { | ||
return fmt.Errorf("setting `entity_mapping`: %+v", err) | ||
} | ||
} | ||
|
||
return nil | ||
|
@@ -549,6 +666,15 @@ func expandAlertRuleScheduledGrouping(input []interface{}) *securityinsight.Grou | |
} | ||
output.GroupByEntities = &groupByEntities | ||
|
||
groupByAlertDetailsSet := raw["group_by_alert_details"].(*pluginsdk.Set).List() | ||
groupByAlertDetails := make([]securityinsight.AlertDetail, len(groupByAlertDetailsSet)) | ||
for idx, t := range groupByAlertDetailsSet { | ||
groupByAlertDetails[idx] = securityinsight.AlertDetail(t.(string)) | ||
} | ||
output.GroupByAlertDetails = &groupByAlertDetails | ||
|
||
output.GroupByCustomDetails = utils.ExpandStringSlice(raw["group_by_custom_details"].(*pluginsdk.Set).List()) | ||
|
||
return output | ||
} | ||
|
||
|
@@ -594,13 +720,29 @@ func flattenAlertRuleScheduledGrouping(input *securityinsight.GroupingConfigurat | |
} | ||
} | ||
|
||
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, string(detail)) | ||
} | ||
} | ||
|
||
return []interface{}{ | ||
map[string]interface{}{ | ||
"enabled": enabled, | ||
"lookback_duration": lookbackDuration, | ||
"reopen_closed_incidents": reopenClosedIncidents, | ||
"entity_matching_method": string(input.MatchingMethod), | ||
"group_by": groupByEntities, | ||
"group_by_alert_details": groupByAlertDetails, | ||
"group_by_custom_details": groupByCustomDetails, | ||
}, | ||
} | ||
} | ||
|
@@ -621,3 +763,142 @@ func flattenAlertRuleScheduledEventGroupingSetting(input *securityinsight.EventG | |
}, | ||
} | ||
} | ||
|
||
func expandAlertRuleScheduledAlertDetailsOverride(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 flattenAlertRuleScheduledAlertDetailsOverride(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 expandAlertRuleScheduledEntityMapping(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: expandAlertRuleScheduledFieldMapping(b["field_mapping"].([]interface{})), | ||
}) | ||
} | ||
|
||
return &result | ||
} | ||
|
||
func flattenAlertRuleScheduledEntityMapping(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": flattenAlertRuleScheduledFieldMapping(e.FieldMappings), | ||
}) | ||
} | ||
|
||
return output | ||
} | ||
|
||
func expandAlertRuleScheduledFieldMapping(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 flattenAlertRuleScheduledFieldMapping(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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(as below) a GroupBy would be an order-statement in other cases, so is order relevant here/should this be a List?