Skip to content

Commit 8c4b101

Browse files
alexeyovriakhkmvachhani
authored andcommitted
feat(secure): Add Malware, Drift, ML and AWS ML policy resources (#476)
* refactor: Add common schema * feat: Add composite policy resource * feat: Add composite policy data source * docs: Add docs for composite policy resource and data source * chore: Fix formatting issues * chore: Update TODO comments in composite policies client * feat: Filter policies by type and name * chore: Clean up code * chore: Update the docs * chore: Fix formatting issue * chore: Fix Sprintf args in test code * fix: Remove ability enable or disable individual rules * chore: Fix lint issues * refactor: Introduce reducer pattern * refactor: Use a consistent way to get policy ID * fix: Resolve copylock error * refactor: Rename Composite to Malware policy * chore: Fix Linter errors * Fix: Resolve compilation error * feat: Add Drift policy resource and data source * test: Update Malware policy tests * docs: Update Malware policy docs * feat: Add ML policy * fix: Ensure the version number is sent to Policies API in order to update resources * chore: Update Drift policy docs * fix: Resolve Lin issue * feat: Add AWS ML policy * chore: Fix docs typo * fix: Add AWS ML policy to TF provider * fix: Resolve "Setting state: Invalid address to set" error * fix: Resolve compilation error * fix: Skip version 0 to resolve resource update error * fix: Resolve tfproviderdocs check error * fix: Resolve "Invalid address to set" in drift policy resource * fix: Fix resource_sysdig_secure_policy_test test failure Error: expected [{pathStepImpl:{} Name:type}] to be one of [falco list_matching k8s_audit aws_cloudtrail gcp_auditlog azure_platformlogs okta github malware drift aws_machine_learning machine_learning], got awscloudtrail * fix: Fix TestAccMalwarePolicy test failure Error: Invalid argument name. Argument names must not be quoted. * fix: Fix TestAccDriftPolicy test failure * feat: Hide tags * feat: Replace Drift rule Mode attribute with a boolean Enabled attribute * fix: Fix Drift rule reducer * fix: Hide Drift rule's match_items attribute * fix: Fix "Invalid resource type" in TestAccMalwarePolicy test * refactor: Remove details block and rename rules to rule * fix: Fix "provide at least one rule name" test error * docs: Update docs to include the latest TF resource changes * test: Update tests * chore: Update schema formatting * fix: Escape query param * refactor: Use const values * tests: Generate unique policy name in data source tests * tests: Add more tests to resources * remove unnecessary changes * more small fixes * set hash alias field as optional * remove hash alias references --------- Co-authored-by: kmvachhani <krishna.vachhani@sysdig.com> Co-authored-by: kmvachhani <63314936+kmvachhani@users.noreply.github.com>
1 parent 2b2b347 commit 8c4b101

31 files changed

+4389
-103
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package sysdig
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2"
8+
"github.com/hashicorp/terraform-plugin-log/tflog"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
)
12+
13+
func dataSourceSysdigSecureAWSMLPolicy() *schema.Resource {
14+
timeout := 5 * time.Minute
15+
16+
return &schema.Resource{
17+
ReadContext: dataSourceSysdigSecureAWSMLPolicyRead,
18+
19+
Timeouts: &schema.ResourceTimeout{
20+
Read: schema.DefaultTimeout(timeout),
21+
},
22+
23+
Schema: createAWSMLPolicyDataSourceSchema(),
24+
}
25+
}
26+
27+
func dataSourceSysdigSecureAWSMLPolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
28+
return awsMLPolicyDataSourceRead(ctx, d, meta, "custom policy", isCustomCompositePolicy)
29+
}
30+
31+
func createAWSMLPolicyDataSourceSchema() map[string]*schema.Schema {
32+
return map[string]*schema.Schema{
33+
// IMPORTANT: Type is implicit: It's automatically added upon conversion to JSON
34+
"type": {
35+
Type: schema.TypeString,
36+
Computed: true,
37+
},
38+
"name": NameSchema(),
39+
"description": DescriptionComputedSchema(),
40+
"enabled": EnabledComputedSchema(),
41+
"severity": SeverityComputedSchema(),
42+
"scope": ScopeComputedSchema(),
43+
"version": VersionSchema(),
44+
"notification_channels": NotificationChannelsComputedSchema(),
45+
"runbook": RunbookComputedSchema(),
46+
"rule": {
47+
Type: schema.TypeList,
48+
Computed: true,
49+
Elem: &schema.Resource{
50+
Schema: map[string]*schema.Schema{
51+
"id": ReadOnlyIntSchema(),
52+
"name": ReadOnlyStringSchema(),
53+
"description": DescriptionComputedSchema(),
54+
"tags": TagsSchema(),
55+
"version": VersionSchema(),
56+
"anomalous_console_login": MLRuleThresholdAndSeverityComputedSchema(),
57+
},
58+
},
59+
},
60+
}
61+
}
62+
63+
func awsMLPolicyDataSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}, resourceName string, validationFunc func(v2.PolicyRulesComposite) bool) diag.Diagnostics {
64+
client, err := getSecureCompositePolicyClient(meta.(SysdigClients))
65+
if err != nil {
66+
return diag.FromErr(err)
67+
}
68+
69+
policyName := d.Get("name").(string)
70+
policyType := policyTypeAWSML
71+
72+
policies, _, err := client.FilterCompositePoliciesByNameAndType(ctx, policyType, policyName)
73+
if err != nil {
74+
return diag.FromErr(err)
75+
}
76+
77+
var policy v2.PolicyRulesComposite
78+
for _, existingPolicy := range policies {
79+
tflog.Debug(ctx, "Filtered policies", map[string]interface{}{"name": existingPolicy.Policy.Name})
80+
81+
if existingPolicy.Policy.Name == policyName && existingPolicy.Policy.Type == policyType {
82+
if !validationFunc(existingPolicy) {
83+
return diag.Errorf("policy is not a %s", resourceName)
84+
}
85+
policy = existingPolicy
86+
break
87+
}
88+
}
89+
90+
if policy.Policy == nil {
91+
return diag.Errorf("unable to find policy %s", resourceName)
92+
}
93+
94+
if policy.Policy.ID == 0 {
95+
return diag.Errorf("unable to find %s", resourceName)
96+
}
97+
98+
err = awsMLPolicyToResourceData(&policy, d)
99+
if err != nil {
100+
return diag.FromErr(err)
101+
}
102+
103+
return nil
104+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//go:build tf_acc_sysdig_secure || tf_acc_policies || tf_acc_onprem_secure
2+
3+
package sysdig_test
4+
5+
import (
6+
"fmt"
7+
"os"
8+
"testing"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
13+
14+
"github.com/draios/terraform-provider-sysdig/sysdig"
15+
)
16+
17+
func TestAccAWSMLPolicyDataSource(t *testing.T) {
18+
rText := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
19+
20+
resource.ParallelTest(t, resource.TestCase{
21+
PreCheck: func() {
22+
if v := os.Getenv("SYSDIG_SECURE_API_TOKEN"); v == "" {
23+
t.Fatal("SYSDIG_SECURE_API_TOKEN must be set for acceptance tests")
24+
}
25+
},
26+
ProviderFactories: map[string]func() (*schema.Provider, error){
27+
"sysdig": func() (*schema.Provider, error) {
28+
return sysdig.Provider(), nil
29+
},
30+
},
31+
Steps: []resource.TestStep{
32+
{
33+
Config: awsAWSMLPolicyDataSource(rText),
34+
},
35+
},
36+
})
37+
}
38+
39+
func awsAWSMLPolicyDataSource(name string) string {
40+
return fmt.Sprintf(`
41+
resource "sysdig_secure_aws_ml_policy" "policy_1" {
42+
name = "Test AWS ML Policy %s"
43+
description = "Test AWS ML Policy Description %s"
44+
enabled = true
45+
severity = 4
46+
47+
rule {
48+
description = "Test AWS ML Rule Description"
49+
50+
anomalous_console_login {
51+
enabled = true
52+
threshold = 2
53+
severity = 1
54+
}
55+
}
56+
57+
}
58+
59+
data "sysdig_secure_aws_ml_policy" "policy_2" {
60+
name = sysdig_secure_aws_ml_policy.policy_1.name
61+
depends_on = [sysdig_secure_aws_ml_policy.policy_1]
62+
}
63+
`, name, name)
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package sysdig
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2"
8+
"github.com/hashicorp/terraform-plugin-log/tflog"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
)
12+
13+
func dataSourceSysdigSecureDriftPolicy() *schema.Resource {
14+
timeout := 5 * time.Minute
15+
16+
return &schema.Resource{
17+
ReadContext: dataSourceSysdigSecureDriftPolicyRead,
18+
19+
Timeouts: &schema.ResourceTimeout{
20+
Read: schema.DefaultTimeout(timeout),
21+
},
22+
23+
Schema: createDriftPolicyDataSourceSchema(),
24+
}
25+
}
26+
27+
func dataSourceSysdigSecureDriftPolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
28+
return driftPolicyDataSourceRead(ctx, d, meta, "custom policy", isCustomCompositePolicy)
29+
}
30+
31+
func createDriftPolicyDataSourceSchema() map[string]*schema.Schema {
32+
return map[string]*schema.Schema{
33+
// IMPORTANT: Type is implicit: It's automatically added upon conversion to JSON
34+
"type": {
35+
Type: schema.TypeString,
36+
Computed: true,
37+
},
38+
"name": NameSchema(),
39+
"description": DescriptionComputedSchema(),
40+
"enabled": EnabledComputedSchema(),
41+
"severity": SeverityComputedSchema(),
42+
"scope": ScopeComputedSchema(),
43+
"version": VersionSchema(),
44+
"notification_channels": NotificationChannelsComputedSchema(),
45+
"runbook": RunbookComputedSchema(),
46+
"rule": {
47+
Type: schema.TypeList,
48+
Computed: true,
49+
Elem: &schema.Resource{
50+
Schema: map[string]*schema.Schema{
51+
"id": ReadOnlyIntSchema(),
52+
"name": ReadOnlyStringSchema(),
53+
"description": DescriptionComputedSchema(),
54+
"tags": TagsSchema(),
55+
"version": VersionSchema(),
56+
"enabled": BoolComputedSchema(),
57+
"exceptions": ExceptionsComputedSchema(),
58+
"prohibited_binaries": ExceptionsComputedSchema(),
59+
},
60+
},
61+
},
62+
"actions": {
63+
Type: schema.TypeList,
64+
Computed: true,
65+
Elem: &schema.Resource{
66+
Schema: map[string]*schema.Schema{
67+
"prevent_drift": PreventActionComputedSchema(),
68+
"container": ContainerActionComputedSchema(),
69+
"capture": CaptureActionComputedSchema(),
70+
},
71+
},
72+
},
73+
}
74+
}
75+
76+
func driftPolicyDataSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}, resourceName string, validationFunc func(v2.PolicyRulesComposite) bool) diag.Diagnostics {
77+
client, err := getSecureCompositePolicyClient(meta.(SysdigClients))
78+
if err != nil {
79+
return diag.FromErr(err)
80+
}
81+
82+
policyName := d.Get("name").(string)
83+
policyType := policyTypeDrift
84+
85+
policies, _, err := client.FilterCompositePoliciesByNameAndType(ctx, policyType, policyName)
86+
if err != nil {
87+
return diag.FromErr(err)
88+
}
89+
90+
var policy v2.PolicyRulesComposite
91+
for _, existingPolicy := range policies {
92+
tflog.Debug(ctx, "Filtered policies", map[string]interface{}{"name": existingPolicy.Policy.Name})
93+
94+
if existingPolicy.Policy.Name == policyName && existingPolicy.Policy.Type == policyType {
95+
if !validationFunc(existingPolicy) {
96+
return diag.Errorf("policy is not a %s", resourceName)
97+
}
98+
policy = existingPolicy
99+
break
100+
}
101+
}
102+
103+
if policy.Policy == nil {
104+
return diag.Errorf("unable to find policy %s", resourceName)
105+
}
106+
107+
if policy.Policy.ID == 0 {
108+
return diag.Errorf("unable to find %s", resourceName)
109+
}
110+
111+
err = driftPolicyToResourceData(&policy, d)
112+
if err != nil {
113+
return diag.FromErr(err)
114+
}
115+
116+
return nil
117+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//go:build tf_acc_sysdig_secure || tf_acc_policies || tf_acc_onprem_secure
2+
3+
package sysdig_test
4+
5+
import (
6+
"fmt"
7+
"os"
8+
"testing"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
13+
14+
"github.com/draios/terraform-provider-sysdig/sysdig"
15+
)
16+
17+
func TestAccDriftPolicyDataSource(t *testing.T) {
18+
rText := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
19+
20+
resource.ParallelTest(t, resource.TestCase{
21+
PreCheck: func() {
22+
if v := os.Getenv("SYSDIG_SECURE_API_TOKEN"); v == "" {
23+
t.Fatal("SYSDIG_SECURE_API_TOKEN must be set for acceptance tests")
24+
}
25+
},
26+
ProviderFactories: map[string]func() (*schema.Provider, error){
27+
"sysdig": func() (*schema.Provider, error) {
28+
return sysdig.Provider(), nil
29+
},
30+
},
31+
Steps: []resource.TestStep{
32+
{
33+
Config: driftPolicyDataSource(rText),
34+
},
35+
},
36+
})
37+
}
38+
39+
func driftPolicyDataSource(name string) string {
40+
return fmt.Sprintf(`
41+
resource "sysdig_secure_drift_policy" "policy_1" {
42+
name = "Test Drift Policy %s"
43+
description = "Test Drift Policy Description %s"
44+
enabled = true
45+
severity = 4
46+
47+
rule {
48+
description = "Test Drift Rule Description"
49+
enabled = true
50+
51+
exceptions {
52+
items = ["/usr/bin/sh"]
53+
}
54+
prohibited_binaries {
55+
items = ["/usr/bin/curl"]
56+
}
57+
}
58+
59+
actions {
60+
prevent_drift = true
61+
}
62+
63+
}
64+
65+
data "sysdig_secure_drift_policy" "policy_2" {
66+
name = sysdig_secure_drift_policy.policy_1.name
67+
depends_on = [sysdig_secure_drift_policy.policy_1]
68+
}
69+
`, name, name)
70+
}

0 commit comments

Comments
 (0)