Skip to content

Commit

Permalink
fix: deprecate alert_rule event_categories attribute (#545)
Browse files Browse the repository at this point in the history
* fix: deprecate alert_rule event_categories attribute

Signed-off-by: Darren Murray <darren.murray@lacework.net>

* fix: deprecate alert_rule event_categories attribute

Signed-off-by: Darren Murray <darren.murray@lacework.net>

* refactor: code review comments

Signed-off-by: Darren Murray <darren.murray@lacework.net>

* refactor: code review comments

Signed-off-by: Darren Murray <darren.murray@lacework.net>

* refactor: code review comments

Signed-off-by: Darren Murray <darren.murray@lacework.net>

* refactor: code review comments

Signed-off-by: Darren Murray <darren.murray@lacework.net>

* refactor: code review comments

Signed-off-by: Darren Murray <darren.murray@lacework.net>

---------

Signed-off-by: Darren Murray <darren.murray@lacework.net>
  • Loading branch information
dmurray-lacework authored Aug 30, 2023
1 parent 5ece5b1 commit e9231c9
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 29 deletions.
31 changes: 18 additions & 13 deletions docs/resources/alert_rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ resource "lacework_alert_channel_slack" "ops_critical" {
}
resource "lacework_alert_rule" "example" {
name = "My Alert Rule"
description = "This is an example alert rule"
alert_channels = [lacework_alert_channel_slack.ops_critical.id]
severities = ["Critical"]
event_categories = ["Compliance"]
alert_categories = ["Policy"]
name = "My Alert Rule"
description = "This is an example alert rule"
alert_channels = [lacework_alert_channel_slack.ops_critical.id]
severities = ["Critical"]
alert_subcategories = ["Compliance"]
alert_categories = ["Policy"]
}
```

Expand All @@ -45,12 +45,12 @@ resource "lacework_resource_group_gcp" "all_gcp_projects" {
}
resource "lacework_alert_rule" "example" {
name = "My Alert Rule"
description = "This is an example alert rule"
alert_channels = [lacework_alert_channel_slack.ops_critical.id]
severities = ["Critical"]
event_categories = ["Compliance"]
resource_groups = [lacework_resource_group_gcp.all_gcp_projects.id]
name = "My Alert Rule"
description = "This is an example alert rule"
alert_channels = [lacework_alert_channel_slack.ops_critical.id]
severities = ["Critical"]
alert_subcategories = ["Compliance"]
resource_groups = [lacework_resource_group_gcp.all_gcp_projects.id]
}
```

Expand All @@ -63,12 +63,17 @@ The following arguments are supported:
* `severities` - (Required) The list of the severities that the rule will apply. Valid severities include:
`Critical`, `High`, `Medium`, `Low` and `Info`.
* `description` - (Optional) The description of the alert rule.
* `event_categories` - (Optional) The list of event categories the rule will apply to. Valid categories include:
* `alert_subcategories` - (Optional) The list of alert subcategories the rule will apply to. Valid categories include:
`Compliance`, `App`, `Cloud`, `File`, `Machine`, `User`, `Platform`, `K8sActivity`, `Registry` `SystemCall`.
* `alert_categories` - (Optional) The alert categories that will use this rule for alert routing. Valid categories include:
`Anomaly`, `Policy`, `Composite`.
* `resource_groups` - (Optional) The list of resource groups the rule will apply to.
* `enabled` - (Optional) The state of the external integration. Defaults to `true`.
* `event_categories` - (Optional, **Deprecated**) The list of event categories the rule will apply to. Valid categories include:
`Compliance`, `App`, `Cloud`, `File`, `Machine`, `User`, `Platform`, `K8sActivity`, `Registry` `SystemCall`.
This attribute is deprecated use `alert_subcategories` instead.



## Import

Expand Down
85 changes: 85 additions & 0 deletions examples/resource_lacework_alert_rule/current/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
terraform {
required_providers {
lacework = {
source = "lacework/lacework"
}
}
}

resource "lacework_alert_rule" "example" {
name = var.name
description = var.description
alert_channels = var.channels
severities = var.severities
alert_subcategories = var.alert_subcategories
alert_categories = var.alert_categories
resource_groups = [lacework_resource_group_aws.example.id]
}

resource "lacework_resource_group_aws" "example" {
name = var.resource_group_name
accounts = ["*"]
}

variable "resource_group_name" {
type = string
default = "Users for Alert Rules Testing example"
}

variable "name" {
type = string
default = "Alert Rule"
}

variable "description" {
type = string
default = "Alert Rule created by Terraform"
}

variable "channels" {
type = list(string)
default = ["TECHALLY_013F08F1B3FA97E7D54463DECAEEACF9AEA3AEACF863F76"]
}

variable "severities" {
type = list(string)
default = ["High", "Medium"]
}

variable "alert_subcategories" {
type = list(string)
default = ["Compliance", "Platform", "User", "Cloud"]
}

variable "alert_categories" {
type = list(string)
default = ["Policy"]
}

output "name" {
value = lacework_alert_rule.example.name
}

output "description" {
value = lacework_alert_rule.example.description
}

output "channels" {
value = lacework_alert_rule.example.alert_channels
}

output "severities" {
value = lacework_alert_rule.example.severities
}

output "alert_subcategories" {
value = lacework_alert_rule.example.alert_subcategories
}

output "alert_categories" {
value = lacework_alert_rule.example.alert_categories
}

output "resource_group_id" {
value = lacework_resource_group_aws.example.id
}
66 changes: 57 additions & 9 deletions integration/resource_lacework_alert_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import (
func TestAlertRuleCreate(t *testing.T) {
name := fmt.Sprintf("Alert Rule - %s", time.Now())
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/resource_lacework_alert_rule",
TerraformDir: "../examples/resource_lacework_alert_rule/current",
EnvVars: tokenEnvVar,
Vars: map[string]interface{}{
"name": name,
"description": "Alert Rule created by Terraform",
"channels": []string{"TECHALLY_013F08F1B3FA97E7D54463DECAEEACF9AEA3AEACF863F76"},
"severities": []string{"Critical"},
"event_categories": []string{"Compliance"},
"alert_subcategories": []string{"Compliance"},
"resource_group_name": fmt.Sprintf("Used for Alert Rule Test - %s", time.Now()),
},
})
Expand All @@ -41,7 +41,7 @@ func TestAlertRuleCreate(t *testing.T) {
actualDescription := terraform.Output(t, terraformOptions, "description")
actualChannels := terraform.Output(t, terraformOptions, "channels")
actualSeverities := terraform.Output(t, terraformOptions, "severities")
actualEventCategories := terraform.Output(t, terraformOptions, "event_categories")
actualEventCategories := terraform.Output(t, terraformOptions, "alert_subcategories")
actualResourceGroupID := terraform.Output(t, terraformOptions, "resource_group_id")

assert.Equal(t, "Alert Rule created by Terraform", createProps.Data.Filter.Description)
Expand All @@ -63,7 +63,7 @@ func TestAlertRuleCreate(t *testing.T) {
"channels": []string{"TECHALLY_01BA9DCAF34B654254D6BF92E5C24023951C3F812B07527",
"TECHALLY_013F08F1B3FA97E7D54463DECAEEACF9AEA3AEACF863F76"},
"severities": []string{"High", "Medium"},
"event_categories": []string{"Compliance", "User", "Platform"},
"alert_subcategories": []string{"Compliance", "User", "Platform"},
"resource_group_name": fmt.Sprintf("Used for Alert Rule Test - %s", time.Now()),
}

Expand All @@ -72,7 +72,7 @@ func TestAlertRuleCreate(t *testing.T) {
actualDescription = terraform.Output(t, terraformOptions, "description")
actualChannels = terraform.Output(t, terraformOptions, "channels")
actualSeverities = terraform.Output(t, terraformOptions, "severities")
actualEventCategories = terraform.Output(t, terraformOptions, "event_categories")
actualEventCategories = terraform.Output(t, terraformOptions, "alert_subcategories")
actualResourceGroupID = terraform.Output(t, terraformOptions, "resource_group_id")

assert.Equal(t, "Updated Alert Rule created by Terraform", updateProps.Data.Filter.Description)
Expand All @@ -91,7 +91,7 @@ func TestAlertRuleCreate(t *testing.T) {
func TestAlertRuleSeverities(t *testing.T) {
name := fmt.Sprintf("Alert Rule - %s", time.Now())
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/resource_lacework_alert_rule",
TerraformDir: "../examples/resource_lacework_alert_rule/current",
EnvVars: tokenEnvVar,
Vars: map[string]interface{}{
"name": name,
Expand All @@ -114,7 +114,7 @@ func TestAlertRuleSeverities(t *testing.T) {
assert.Equal(t, "[Critical High Medium Low]", actualSeverities)

invalidOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/resource_lacework_alert_rule",
TerraformDir: "../examples/resource_lacework_alert_rule/current",
Vars: map[string]interface{}{
"name": name,
"severities": []string{"INVALID"},
Expand All @@ -134,7 +134,55 @@ func TestAlertRuleSeverities(t *testing.T) {
func TestAlertRuleCategories(t *testing.T) {
name := fmt.Sprintf("Alert Rule - %s", time.Now())
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/resource_lacework_alert_rule",
TerraformDir: "../examples/resource_lacework_alert_rule/current",
EnvVars: tokenEnvVar,
Vars: map[string]interface{}{
"name": name,
"alert_subcategories": []string{"Compliance", "App", "Cloud", "File", "Machine",
"User", "Platform", "K8sActivity", "Registry", "SystemCall"},
"alert_categories": []string{"Policy"},
"resource_group_name": fmt.Sprintf("Used for Alert Rule Test - %s", time.Now()),
},
})
defer terraform.Destroy(t, terraformOptions)

terraformOptions.TimeBetweenRetries = 2 * time.Second
create := terraform.InitAndApplyAndIdempotent(t, terraformOptions)
createProps := GetAlertRuleProps(create)

actualCategories := terraform.Output(t, terraformOptions, "alert_subcategories")
actualAlertCategories := terraform.Output(t, terraformOptions, "alert_categories")

assert.ElementsMatch(t, []string{"Compliance", "App", "Cloud", "File", "Machine",
"User", "Platform", "K8sActivity", "Registry", "SystemCall"}, createProps.Data.Filter.EventCategories)
assert.ElementsMatch(t, []string{"Policy"}, createProps.Data.Filter.AlertCategories)

assert.Equal(t, "[App Cloud Compliance File K8sActivity Machine Platform Registry SystemCall User]",
actualCategories)
assert.Equal(t, "[Policy]", actualAlertCategories)

invalidOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/resource_lacework_alert_rule/current",
Vars: map[string]interface{}{
"name": name,
"alert_subcategories": []string{"INVALID"},
"resource_group_name": fmt.Sprintf("Used for Alert Rule Test - %s", time.Now()),
},
})

_, err := terraform.ApplyE(t, invalidOptions)
if assert.Error(t, err) {
assert.Contains(t,
err.Error(),
"expected alert_subcategories.0 to be one of [Compliance App Cloud File Machine User Platform K8sActivity Registry SystemCall]",
)
}
}

func TestAlertRuleDeprecatedEventCategories(t *testing.T) {
name := fmt.Sprintf("Alert Rule - %s", time.Now())
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/resource_lacework_alert_rule/deprecated",
EnvVars: tokenEnvVar,
Vars: map[string]interface{}{
"name": name,
Expand Down Expand Up @@ -162,7 +210,7 @@ func TestAlertRuleCategories(t *testing.T) {
assert.Equal(t, "[Policy]", actualAlertCategories)

invalidOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/resource_lacework_alert_rule",
TerraformDir: "../examples/resource_lacework_alert_rule/deprecated",
Vars: map[string]interface{}{
"name": name,
"event_categories": []string{"INVALID"},
Expand Down
45 changes: 38 additions & 7 deletions lacework/resource_lacework_alert_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,9 @@ func resourceLaceworkAlertRule() *schema.Resource {
},
},
"event_categories": {
Type: schema.TypeSet,
Optional: true,
Type: schema.TypeSet,
Optional: true,
Deprecated: "This attribute is deprecated and has been replaced by `alert_subcategories`",
Description: fmt.Sprintf("List of event categories for the alert rule. Valid categories are: %s",
strings.Join(api.AlertRuleSubCategories, ", ")),
Elem: &schema.Schema{
Expand All @@ -114,6 +115,20 @@ func resourceLaceworkAlertRule() *schema.Resource {
ValidateFunc: validation.StringInSlice(api.AlertRuleSubCategories, false),
},
},
"alert_subcategories": {
Type: schema.TypeSet,
Optional: true,
ConflictsWith: []string{"event_categories"},
Description: fmt.Sprintf("List of alert subcategories for the alert rule. Valid categories are: %s",
strings.Join(api.AlertRuleSubCategories, ", ")),
Elem: &schema.Schema{
Type: schema.TypeString,
StateFunc: func(val interface{}) string {
return strings.TrimSpace(val.(string))
},
ValidateFunc: validation.StringInSlice(api.AlertRuleSubCategories, false),
},
},
"guid": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -140,18 +155,24 @@ func resourceLaceworkAlertRuleCreate(d *schema.ResourceData, meta interface{}) e
alertChannels = d.Get("alert_channels").(*schema.Set).List()
}

var alertSubcategories []interface{}
if _, ok := d.GetOk("alert_subcategories"); ok {
alertSubcategories = d.Get("alert_subcategories").(*schema.Set).List()
} else if _, ok := d.GetOk("event_categories"); ok {
alertSubcategories = d.Get("event_categories").(*schema.Set).List()
}

var (
lacework = meta.(*api.Client)
resourceGroups = d.Get("resource_groups").(*schema.Set).List()
eventCategories = d.Get("event_categories").(*schema.Set).List()
alertCategories = d.Get("alert_categories").(*schema.Set).List()
severities = api.NewAlertRuleSeverities(castAttributeToStringSlice(d, "severities"))
alertRule = api.NewAlertRule(d.Get("name").(string),
api.AlertRuleConfig{
Description: d.Get("description").(string),
Channels: castStringSlice(alertChannels),
Severities: severities,
EventCategories: castStringSlice(eventCategories),
EventCategories: castStringSlice(alertSubcategories),
AlertCategories: castStringSlice(alertCategories),
ResourceGroups: castStringSlice(resourceGroups),
},
Expand Down Expand Up @@ -202,7 +223,11 @@ func resourceLaceworkAlertRuleRead(d *schema.ResourceData, meta interface{}) err
d.Set("type_name", response.Data.Type)
d.Set("severities", api.NewAlertRuleSeveritiesFromIntSlice(response.Data.Filter.Severity).ToStringSlice())
d.Set("resource_groups", response.Data.Filter.ResourceGroups)
d.Set("event_categories", response.Data.Filter.EventCategories)
if _, ok := d.GetOk("alert_subcategories"); ok {
d.Set("alert_subcategories", response.Data.Filter.EventCategories)
} else if _, ok := d.GetOk("event_categories"); ok {
d.Set("event_categories", response.Data.Filter.EventCategories)
}
d.Set("alert_categories", response.Data.Filter.AlertCategories)
d.Set("alert_channels", response.Data.Channels)

Expand All @@ -216,18 +241,24 @@ func resourceLaceworkAlertRuleUpdate(d *schema.ResourceData, meta interface{}) e
alertChannels = d.Get("alert_channels").(*schema.Set).List()
}

var alertSubcategories []interface{}
if _, ok := d.GetOk("alert_subcategories"); ok {
alertSubcategories = d.Get("alert_subcategories").(*schema.Set).List()
} else if _, ok := d.GetOk("event_categories"); ok {
alertSubcategories = d.Get("event_categories").(*schema.Set).List()
}

var (
lacework = meta.(*api.Client)
resourceGroups = d.Get("resource_groups").(*schema.Set).List()
eventCategories = d.Get("event_categories").(*schema.Set).List()
alertCategories = d.Get("alert_categories").(*schema.Set).List()
severities = api.NewAlertRuleSeverities(castAttributeToStringSlice(d, "severities"))
alertRule = api.NewAlertRule(d.Get("name").(string),
api.AlertRuleConfig{
Description: d.Get("description").(string),
Channels: castStringSlice(alertChannels),
Severities: severities,
EventCategories: castStringSlice(eventCategories),
EventCategories: castStringSlice(alertSubcategories),
AlertCategories: castStringSlice(alertCategories),
ResourceGroups: castStringSlice(resourceGroups),
},
Expand Down

0 comments on commit e9231c9

Please sign in to comment.