diff --git a/sysdig/data_source_sysdig_secure_malware_policy.go b/sysdig/data_source_sysdig_secure_malware_policy.go index 37a0aeba..790520e7 100644 --- a/sysdig/data_source_sysdig_secure_malware_policy.go +++ b/sysdig/data_source_sysdig_secure_malware_policy.go @@ -57,8 +57,11 @@ func createMalwarePolicyDataSourceSchema() map[string]*schema.Schema { "tags": TagsSchema(), "version": VersionSchema(), "use_managed_hashes": BoolComputedSchema(), - "additional_hashes": HashesComputedSchema(), - "ignore_hashes": HashesComputedSchema(), + "use_yara_rules": BoolComputedSchema(), + "additional_hashes": StringListComputedSchema(), + "ignore_hashes": StringListComputedSchema(), + "use_regex": BoolComputedSchema(), + "ignore_paths": StringListComputedSchema(), }, }, }, diff --git a/sysdig/data_source_sysdig_secure_malware_policy_test.go b/sysdig/data_source_sysdig_secure_malware_policy_test.go index aeca1de8..47ff38c0 100644 --- a/sysdig/data_source_sysdig_secure_malware_policy_test.go +++ b/sysdig/data_source_sysdig_secure_malware_policy_test.go @@ -32,6 +32,9 @@ func TestAccMalwarePolicyDataSource(t *testing.T) { { Config: malwarePolicyDataSource(rText), }, + { + Config: malwarePolicyWithAdditionalFieldsDataSource(rText), + }, }, }) } @@ -49,13 +52,13 @@ resource "sysdig_secure_malware_policy" "policy_1" { use_managed_hashes = true - additional_hashes { - hash = "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" - } + additional_hashes = [ + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" + ] - ignore_hashes { - hash = "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" - } + ignore_hashes = [ + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" + ] } actions { @@ -69,3 +72,38 @@ data "sysdig_secure_malware_policy" "policy_2" { } `, name, name) } + +func malwarePolicyWithAdditionalFieldsDataSource(name string) string { + return fmt.Sprintf(` +resource "sysdig_secure_malware_policy" "policy_3" { + name = "Test Malware Policy 2 %s" + description = "Test Malware Policy Description %s" + enabled = true + severity = 4 + + rule { + description = "Test Malware Rule Description" + + use_managed_hashes = true + use_yara_rules = true + use_regex = true + + additional_hashes = [ + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6", + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae7" + ] + + ignore_hashes = [ + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e", + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0f" + ] + + ignore_paths = ["/usr/bin/curl", "/usr/bin/sh"] + } +} + +data "sysdig_secure_malware_policy" "policy_4" { + name = sysdig_secure_malware_policy.policy_3.name +} +`, name, name) +} diff --git a/sysdig/internal/client/v2/model.go b/sysdig/internal/client/v2/model.go index 11ae15b7..db241d49 100644 --- a/sysdig/internal/client/v2/model.go +++ b/sysdig/internal/client/v2/model.go @@ -397,8 +397,11 @@ func (p MLRuleDetails) GetRuleType() ElementType { type MalwareRuleDetails struct { RuleType ElementType `json:"ruleType"` UseManagedHashes bool `json:"useManagedHashes"` + UseYaraRules bool `json:"usePolymorphicRules"` AdditionalHashes map[string][]string `json:"additionalHashes"` IgnoreHashes map[string][]string `json:"ignoreHashes"` + UseRegex bool `json:"useRegex"` + IgnorePaths map[string][]string `json:"ignorePaths"` Details `json:"-"` } diff --git a/sysdig/resource_sysdig_secure_malware_policy.go b/sysdig/resource_sysdig_secure_malware_policy.go index 364ec673..ce050e9c 100644 --- a/sysdig/resource_sysdig_secure_malware_policy.go +++ b/sysdig/resource_sysdig_secure_malware_policy.go @@ -54,6 +54,7 @@ func resourceSysdigSecureMalwarePolicy() *schema.Resource { "rule": { Type: schema.TypeList, Required: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": ReadOnlyIntSchema(), @@ -64,8 +65,11 @@ func resourceSysdigSecureMalwarePolicy() *schema.Resource { "tags": TagsSchema(), "version": VersionSchema(), "use_managed_hashes": BoolSchema(), - "additional_hashes": HashesSchema(), - "ignore_hashes": HashesSchema(), + "use_yara_rules": BoolSchema(), + "additional_hashes": StringListSchema(), + "ignore_hashes": StringListSchema(), + "use_regex": BoolSchema(), + "ignore_paths": StringListSchema(), }, }, }, diff --git a/sysdig/resource_sysdig_secure_malware_policy_test.go b/sysdig/resource_sysdig_secure_malware_policy_test.go index 1e64efd3..c3e51864 100644 --- a/sysdig/resource_sysdig_secure_malware_policy_test.go +++ b/sysdig/resource_sysdig_secure_malware_policy_test.go @@ -42,6 +42,9 @@ func TestAccMalwarePolicy(t *testing.T) { { Config: malwarePolicyWithoutNotificationChannel(rText()), }, + { + Config: malwarePolicyWithAdditionalFields(rText()), + }, }, }) } @@ -61,13 +64,13 @@ resource "sysdig_secure_malware_policy" "sample" { use_managed_hashes = true - additional_hashes { - hash = "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" - } + additional_hashes = [ + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" + ] - ignore_hashes { - hash = "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" - } + ignore_hashes = [ + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" + ] } actions { @@ -96,9 +99,9 @@ resource "sysdig_secure_malware_policy" "sample" { use_managed_hashes = true - ignore_hashes { - hash = "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" - } + ignore_hashes = [ + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" + ] } actions { @@ -127,9 +130,9 @@ resource "sysdig_secure_malware_policy" "sample" { use_managed_hashes = true - additional_hashes { - hash = "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" - } + additional_hashes = [ + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" + ] } actions { @@ -183,13 +186,13 @@ resource "sysdig_secure_malware_policy" "sample" { use_managed_hashes = true - additional_hashes { - hash = "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" - } + additional_hashes = [ + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" + ] - ignore_hashes { - hash = "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" - } + ignore_hashes = [ + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" + ] } actions { @@ -222,13 +225,51 @@ resource "sysdig_secure_malware_policy" "sample" { use_managed_hashes = true - additional_hashes { - hash = "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" - } + additional_hashes = [ + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" + ] - ignore_hashes { - hash = "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" - } + ignore_hashes = [ + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" + ] + } + + actions { + prevent_malware = true + container = "stop" + } + +} + +`, name) +} + +func malwarePolicyWithAdditionalFields(name string) string { + return fmt.Sprintf(` +resource "sysdig_secure_malware_policy" "sample" { + name = "Test Malware Policy %s" + description = "Test Malware Policy Description" + enabled = true + severity = 4 + + rule { + description = "Test Malware Rule Description" + + use_managed_hashes = true + use_yara_rules = true + use_regex = true + + additional_hashes = [ + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6", + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae7" + ] + + ignore_hashes = [ + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e", + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0f" + ] + + ignore_paths = ["/usr/bin/curl", "/usr/bin/sh"] } actions { diff --git a/sysdig/schema.go b/sysdig/schema.go index de31a66d..c083ae56 100644 --- a/sysdig/schema.go +++ b/sysdig/schema.go @@ -326,6 +326,26 @@ func HashesComputedSchema() *schema.Schema { } } +func StringListSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + } +} + +func StringListComputedSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + } +} + func TagsSchema() *schema.Schema { // Tags are always set automatically by Sysdig return &schema.Schema{ diff --git a/sysdig/tfresource.go b/sysdig/tfresource.go index f0068985..4a6e5a5c 100644 --- a/sysdig/tfresource.go +++ b/sysdig/tfresource.go @@ -2,6 +2,7 @@ package sysdig import ( "errors" + "slices" "strconv" "strings" @@ -109,19 +110,25 @@ func setTFResourcePolicyRulesMalware(d *schema.ResourceData, policy v2.PolicyRul rules := []map[string]any{} for _, rule := range policy.Rules { - additionalHashes := []map[string]any{} - for k := range rule.Details.(*v2.MalwareRuleDetails).AdditionalHashes { - additionalHashes = append(additionalHashes, map[string]any{ - "hash": k, - }) + malwareRuleDetails := rule.Details.(*v2.MalwareRuleDetails) + + additionalHashes := []string{} + for k := range malwareRuleDetails.AdditionalHashes { + additionalHashes = append(additionalHashes, k) + } + slices.Sort(additionalHashes) + + ignoreHashes := []string{} + for k := range malwareRuleDetails.IgnoreHashes { + ignoreHashes = append(ignoreHashes, k) } + slices.Sort(ignoreHashes) - ignoreHashes := []map[string]any{} - for k := range rule.Details.(*v2.MalwareRuleDetails).IgnoreHashes { - ignoreHashes = append(ignoreHashes, map[string]any{ - "hash": k, - }) + ignorePaths := []string{} + for k := range malwareRuleDetails.IgnorePaths { + ignorePaths = append(ignorePaths, k) } + slices.Sort(ignorePaths) rules = append(rules, map[string]any{ "id": rule.ID, @@ -129,9 +136,12 @@ func setTFResourcePolicyRulesMalware(d *schema.ResourceData, policy v2.PolicyRul "description": rule.Description, "version": rule.Version, "tags": rule.Tags, - "use_managed_hashes": rule.Details.(*v2.MalwareRuleDetails).UseManagedHashes, + "use_managed_hashes": malwareRuleDetails.UseManagedHashes, + "use_yara_rules": malwareRuleDetails.UseYaraRules, "additional_hashes": additionalHashes, "ignore_hashes": ignoreHashes, + "use_regex": malwareRuleDetails.UseRegex, + "ignore_paths": ignorePaths, }) } @@ -420,9 +430,8 @@ func setPolicyRulesMalware(policy *v2.PolicyRulesComposite, d *schema.ResourceDa additionalHashes := map[string][]string{} if items, ok := d.GetOk("rule.0.additional_hashes"); ok { // TODO: Do not hardcode the indexes for _, item := range items.([]any) { - item := item.(map[string]any) - k := item["hash"].(string) - additionalHashes[k] = []string{} + hash := item.(string) + additionalHashes[hash] = []string{} } } @@ -430,9 +439,8 @@ func setPolicyRulesMalware(policy *v2.PolicyRulesComposite, d *schema.ResourceDa ignoreHashes := map[string][]string{} if items, ok := d.GetOk("rule.0.ignore_hashes"); ok { // TODO: Do not hardcode the indexes for _, item := range items.([]any) { - item := item.(map[string]any) - k := item["hash"].(string) - ignoreHashes[k] = []string{} + hash := item.(string) + ignoreHashes[hash] = []string{} } } @@ -442,6 +450,14 @@ func setPolicyRulesMalware(policy *v2.PolicyRulesComposite, d *schema.ResourceDa tags = []string{defaultMalwareTag} } + ignorePaths := map[string][]string{} + if items, ok := d.GetOk("rule.0.ignore_paths"); ok { // TODO: Do not hardcode the indexes + for _, item := range items.([]any) { + path := item.(string) + ignorePaths[path] = []string{} + } + } + rule := &v2.RuntimePolicyRule{ // TODO: Do not hardcode the indexes Name: d.Get("rule.0.name").(string), @@ -450,8 +466,11 @@ func setPolicyRulesMalware(policy *v2.PolicyRulesComposite, d *schema.ResourceDa Details: v2.MalwareRuleDetails{ RuleType: v2.ElementType("MALWARE"), // TODO: Use const UseManagedHashes: d.Get("rule.0.use_managed_hashes").(bool), + UseYaraRules: d.Get("rule.0.use_yara_rules").(bool), AdditionalHashes: additionalHashes, IgnoreHashes: ignoreHashes, + UseRegex: d.Get("rule.0.use_regex").(bool), + IgnorePaths: ignorePaths, }, } diff --git a/website/docs/d/secure_malware_policy.md b/website/docs/d/secure_malware_policy.md index 591d1e9c..b3b8ff9e 100644 --- a/website/docs/d/secure_malware_policy.md +++ b/website/docs/d/secure_malware_policy.md @@ -71,9 +71,10 @@ The actions block is optional and supports: The rule block is required and supports: * `description` - (Required) The description of the malware rule. -* `use_managed_hashes` - (Required) Should Sysdig's managed hashes be used? The possible values are `true` or `false`. -* `additional_hashes` - (Optional) The block contains a single hash that should be matched. - * `hash` - (Required) The hash value that should be matched. -* `ignore_hashes` - (Optional) The block contains a single hash that should be matched. - * `hash` - (Required) The hash value that should be matched. +* `use_managed_hashes` - (Optional) Should Sysdig's managed hashes be used? The possible values are `true` or `false`. +* `use_yara_rules` - (Optional) Should use Sysdig's managed YARA rules to detect malware and malicious scripts? The possible values are `true` or `false`. +* `additional_hashes` - (Optional) List of additional hashes that should be matched. +* `ignore_hashes` - (Optional) List of hashes that should be ignored. +* `use_regex` - (Optional) Should use regex for ignore_paths matching? The possible values are `true` or `false`. +* `ignore_paths` - (Optional) The list of file paths to be excluded from malware matching diff --git a/website/docs/r/secure_malware_policy.md b/website/docs/r/secure_malware_policy.md index baf2159f..ac7df86d 100644 --- a/website/docs/r/secure_malware_policy.md +++ b/website/docs/r/secure_malware_policy.md @@ -12,6 +12,21 @@ Retrieves the information of an existing Sysdig Secure Malware Policy. -> **Note:** Sysdig Terraform Provider is under rapid development at this point. If you experience any issue or discrepancy while using it, please make sure you have the latest version. If the issue persists, or you have a Feature Request to support an additional set of resources, please open a [new issue](https://github.com/sysdiglabs/terraform-provider-sysdig/issues/new) in the GitHub repository. +## Migration/Troubleshooting + +-> **Note:** Due to a bug in the schema for `additional_hashes` and `ignore_hashes`, you might have faced issues with multiple hash values for these fields with the older version of the provider. After updating to the latest provider version, please update the `additional_hashes` and `ignore_hashes` fields in the malware policy definition in your terraform files to use a list of hashes like shown below, which should now allow multiple hashes: +``` +additional_hashes = { + hash = "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" +} + +to + +additional_hashes = [ + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" +] +``` + ## Example Usage ```terraform @@ -34,13 +49,17 @@ resource "sysdig_secure_malware_policy" "prevent_malware" { description = "Test Malware Rule Description" use_managed_hashes = true - additional_hashes { - hash = "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6" + additional_hashes = [ + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae6", + "304ef4cdda3463b24bf53f9cdd69ad3ecdab0842e7e70e2f3cfbb9f14e1c4ae7" } - ignore_hashes { - hash = "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e" - } + ignore_hashes = [ + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0e", + "6ac3c336e4094835293a3fed8a4b5fedde1b5e2626d9838fed50693bba00af0f" + ] + + ignore_paths = ["/usr/lib/abc", "/usr/bin/bcd"] } actions { @@ -109,7 +128,8 @@ The rule block is required and supports: * `description` - (Required) The description of the malware rule. * `use_managed_hashes` - (Required) Should Sysdig's managed hashes be used? The possible values are `true` or `false`. -* `additional_hashes` - (Optional) The block contains a single hash that should be matched. - * `hash` - (Required) The hash value that should be matched. -* `ignore_hashes` - (Optional) The block contains a single hash that should be matched. - * `hash` - (Required) The hash value that should be matched. +* `use_yara_rules` - (Optional) Should use Sysdig's managed YARA rules to detect malware and malicious scripts? The possible values are `true` or `false`. +* `additional_hashes` - (Optional) List of additional hashes that should be matched. +* `ignore_hashes` - (Optional) List of hashes that should be ignored. +* `use_regex` - (Optional) Should use regex for ignore_paths matching? The possible values are `true` or `false`. +* `ignore_paths` - (Optional) The list of file paths to be excluded from malware matching