Skip to content

Commit 1f84b46

Browse files
feat(drift-policies): add process based exceptions to drift policies (#581)
* feat: add process based exceptions to drift policies Signed-off-by: Igor Eulalio <[email protected]> * address review comments --------- Signed-off-by: Igor Eulalio <[email protected]> Co-authored-by: kmvachhani <[email protected]> Co-authored-by: kmvachhani <[email protected]>
1 parent 78e701d commit 1f84b46

File tree

5 files changed

+176
-53
lines changed

5 files changed

+176
-53
lines changed

sysdig/internal/client/v2/model.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -426,11 +426,13 @@ type RuntimePolicyRuleList struct {
426426
}
427427

428428
type DriftRuleDetails struct {
429-
RuleType ElementType `json:"ruleType"`
430-
Exceptions *RuntimePolicyRuleList `json:"exceptionList"`
431-
ProhibitedBinaries *RuntimePolicyRuleList `json:"prohibitedBinaries"`
432-
Mode string `json:"mode"`
433-
Details `json:"-"`
429+
RuleType ElementType `json:"ruleType"`
430+
Exceptions *RuntimePolicyRuleList `json:"exceptionList"`
431+
ProcessBasedExceptions *RuntimePolicyRuleList `json:"allowlistProcess"`
432+
ProcessBasedDenylist *RuntimePolicyRuleList `json:"denylistProcess"`
433+
ProhibitedBinaries *RuntimePolicyRuleList `json:"prohibitedBinaries"`
434+
Mode string `json:"mode"`
435+
Details `json:"-"`
434436
}
435437

436438
func (p DriftRuleDetails) GetRuleType() ElementType {

sysdig/resource_sysdig_secure_drift_policy.go

+10-8
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,16 @@ func resourceSysdigSecureDriftPolicy() *schema.Resource {
5656
Required: true,
5757
Elem: &schema.Resource{
5858
Schema: map[string]*schema.Schema{
59-
"id": ReadOnlyIntSchema(),
60-
"name": ReadOnlyStringSchema(),
61-
"description": DescriptionSchema(),
62-
"tags": TagsSchema(),
63-
"version": VersionSchema(),
64-
"enabled": BoolSchema(), // Enable maps to mode rule attribute
65-
"exceptions": ExceptionsSchema(),
66-
"prohibited_binaries": ExceptionsSchema(),
59+
"id": ReadOnlyIntSchema(),
60+
"name": ReadOnlyStringSchema(),
61+
"description": DescriptionSchema(),
62+
"tags": TagsSchema(),
63+
"version": VersionSchema(),
64+
"enabled": BoolSchema(), // Enable maps to mode rule attribute
65+
"exceptions": ExceptionsSchema(),
66+
"prohibited_binaries": ExceptionsSchema(),
67+
"process_based_exceptions": ExceptionsSchema(),
68+
"process_based_prohibited_binaries": ExceptionsSchema(),
6769
},
6870
},
6971
},

sysdig/resource_sysdig_secure_drift_policy_test.go

+41
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ func TestAccDriftPolicy(t *testing.T) {
3636
{
3737
Config: driftPolicyWithoutNotificationChannel(rText()),
3838
},
39+
{
40+
Config: driftPolicyWithoutExceptions(rText()),
41+
},
3942
},
4043
})
4144
}
@@ -61,6 +64,9 @@ resource "sysdig_secure_drift_policy" "sample" {
6164
prohibited_binaries {
6265
items = ["/usr/bin/curl"]
6366
}
67+
process_based_exceptions {
68+
items = ["/usr/bin/curl"]
69+
}
6470
}
6571
6672
actions {
@@ -94,6 +100,9 @@ resource "sysdig_secure_drift_policy" "sample" {
94100
prohibited_binaries {
95101
items = ["/usr/bin/curl"]
96102
}
103+
process_based_exceptions {
104+
items = ["/usr/bin/curl"]
105+
}
97106
}
98107
99108
actions {
@@ -133,6 +142,9 @@ resource "sysdig_secure_drift_policy" "sample" {
133142
prohibited_binaries {
134143
items = ["/usr/bin/curl"]
135144
}
145+
process_based_exceptions {
146+
items = ["/usr/bin/curl"]
147+
}
136148
}
137149
138150
actions {}
@@ -162,6 +174,9 @@ resource "sysdig_secure_drift_policy" "sample" {
162174
prohibited_binaries {
163175
items = ["/usr/bin/curl"]
164176
}
177+
process_based_exceptions {
178+
items = ["/usr/bin/curl"]
179+
}
165180
}
166181
167182
actions {
@@ -171,3 +186,29 @@ resource "sysdig_secure_drift_policy" "sample" {
171186
172187
`, name)
173188
}
189+
190+
func driftPolicyWithoutExceptions(name string) string {
191+
return fmt.Sprintf(`
192+
%s
193+
194+
resource "sysdig_secure_drift_policy" "sample" {
195+
name = "Test Drift Policy %s"
196+
description = "Test Drift Policy Description"
197+
enabled = true
198+
severity = 4
199+
200+
rule {
201+
description = "Test Drift Rule Description"
202+
203+
enabled = true
204+
}
205+
206+
actions {
207+
prevent_drift = true
208+
}
209+
210+
notification_channels = [sysdig_secure_notification_channel_email.sample_email.id]
211+
}
212+
213+
`, secureNotificationChannelEmailWithName(name), name)
214+
}

sysdig/tfresource.go

+114-40
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const (
2222
defaultMalwareTag = "malware"
2323
defaultDriftTag = "drift"
2424
defaultMLTag = "machine_learning"
25+
26+
driftElementType = "DRIFT"
2527
)
2628

2729
type Target interface {
@@ -143,38 +145,97 @@ func setTFResourcePolicyRulesDrift(d *schema.ResourceData, policy v2.PolicyRules
143145
return errors.New("The policy must have at least one rule attached to it")
144146
}
145147

146-
rules := []map[string]interface{}{}
148+
var rules []map[string]interface{}
147149
for _, rule := range policy.Rules {
148-
// Only a single block of exceptions and prohibited binaries is allowed
149-
exceptions := []map[string]interface{}{{
150-
"items": rule.Details.(*v2.DriftRuleDetails).Exceptions.Items,
151-
"match_items": rule.Details.(*v2.DriftRuleDetails).Exceptions.MatchItems,
152-
}}
150+
driftDetails, ok := rule.Details.(*v2.DriftRuleDetails)
151+
if !ok {
152+
return errors.New("unexpected rule details type, expected DriftRuleDetails")
153+
}
154+
155+
// Directly use fields assuming backend returns zero values (not nil)
156+
exceptionsItems := driftDetails.Exceptions.Items
157+
exceptionsMatchItems := driftDetails.Exceptions.MatchItems
158+
159+
var exceptionsBlock []map[string]interface{}
160+
if len(exceptionsItems) > 0 || exceptionsMatchItems {
161+
exceptionsBlock = []map[string]interface{}{
162+
{
163+
"items": exceptionsItems,
164+
"match_items": exceptionsMatchItems,
165+
},
166+
}
167+
}
153168

154-
prohibitedBinaries := []map[string]interface{}{{
155-
"items": rule.Details.(*v2.DriftRuleDetails).ProhibitedBinaries.Items,
156-
"match_items": rule.Details.(*v2.DriftRuleDetails).ProhibitedBinaries.MatchItems,
157-
}}
169+
prohibitedItems := driftDetails.ProhibitedBinaries.Items
170+
prohibitedMatchItems := driftDetails.ProhibitedBinaries.MatchItems
158171

159-
mode := rule.Details.(*v2.DriftRuleDetails).Mode
160-
enabled := true
161-
if mode == "disabled" {
162-
enabled = false
172+
var prohibitedBinariesBlock []map[string]interface{}
173+
if len(prohibitedItems) > 0 || prohibitedMatchItems {
174+
prohibitedBinariesBlock = []map[string]interface{}{
175+
{
176+
"items": prohibitedItems,
177+
"match_items": prohibitedMatchItems,
178+
},
179+
}
163180
}
164181

165-
rules = append(rules, map[string]interface{}{
166-
"id": rule.Id,
167-
"name": rule.Name,
168-
"description": rule.Description,
169-
"version": rule.Version,
170-
"tags": rule.Tags,
171-
"enabled": enabled,
172-
"exceptions": exceptions,
173-
"prohibited_binaries": prohibitedBinaries,
174-
})
182+
processBasedExceptionsItems := driftDetails.ProcessBasedExceptions.Items
183+
processBasedExceptionMatchItems := driftDetails.ProcessBasedExceptions.MatchItems
184+
185+
var processBasedExceptionsBlock []map[string]interface{}
186+
if len(processBasedExceptionsItems) > 0 || processBasedExceptionMatchItems {
187+
processBasedExceptionsBlock = []map[string]interface{}{
188+
{
189+
"items": processBasedExceptionsItems,
190+
"match_items": processBasedExceptionMatchItems,
191+
},
192+
}
193+
}
194+
195+
processBasedProhibitedBinariesItems := driftDetails.ProcessBasedDenylist.Items
196+
processBasedProhibitedBinariesMatchItems := driftDetails.ProcessBasedDenylist.MatchItems
197+
198+
var processBasedProhibitedBinariesBlock []map[string]interface{}
199+
if len(processBasedProhibitedBinariesItems) > 0 || processBasedProhibitedBinariesMatchItems {
200+
processBasedProhibitedBinariesBlock = []map[string]interface{}{
201+
{
202+
"items": processBasedProhibitedBinariesItems,
203+
"match_items": processBasedProhibitedBinariesMatchItems,
204+
},
205+
}
206+
}
207+
208+
mode := driftDetails.Mode
209+
enabled := (mode != "disabled")
210+
211+
ruleMap := map[string]interface{}{
212+
"id": rule.Id,
213+
"name": rule.Name,
214+
"description": rule.Description,
215+
"version": rule.Version,
216+
"tags": rule.Tags,
217+
"enabled": enabled,
218+
}
219+
220+
if exceptionsBlock != nil {
221+
ruleMap["exceptions"] = exceptionsBlock
222+
}
223+
if prohibitedBinariesBlock != nil {
224+
ruleMap["prohibited_binaries"] = prohibitedBinariesBlock
225+
}
226+
if processBasedExceptionsBlock != nil {
227+
ruleMap["process_based_exceptions"] = processBasedExceptionsBlock
228+
}
229+
if processBasedProhibitedBinariesBlock != nil {
230+
ruleMap["process_based_prohibited_binaries"] = processBasedProhibitedBinariesBlock
231+
}
232+
233+
rules = append(rules, ruleMap)
175234
}
176235

177-
_ = d.Set("rule", rules)
236+
if err := d.Set("rule", rules); err != nil {
237+
return err
238+
}
178239

179240
return nil
180241
}
@@ -414,18 +475,13 @@ func setPolicyRulesDrift(policy *v2.PolicyRulesComposite, d *schema.ResourceData
414475
// TODO: Iterate over a list of rules instead of hard-coding the index values
415476
// TODO: Should we assume that only a single Malware rule can be attached to a policy?
416477

417-
exceptions := &v2.RuntimePolicyRuleList{}
418-
if _, ok := d.GetOk("rule.0.exceptions"); ok { // TODO: Do not hardcode the indexes
419-
exceptions.Items = schemaSetToList(d.Get("rule.0.exceptions.0.items"))
420-
exceptions.MatchItems = d.Get("rule.0.exceptions.0.match_items").(bool)
421-
}
478+
exceptions := extractIntoRuntimePolicyRuleList("rule.0.exceptions", d)
422479

423-
// TODO: Extract into a function
424-
prohibitedBinaries := &v2.RuntimePolicyRuleList{}
425-
if _, ok := d.GetOk("rule.0.prohibited_binaries"); ok { // TODO: Do not hardcode the indexes
426-
prohibitedBinaries.Items = schemaSetToList(d.Get("rule.0.prohibited_binaries.0.items"))
427-
prohibitedBinaries.MatchItems = d.Get("rule.0.prohibited_binaries.0.match_items").(bool)
428-
}
480+
prohibitedBinaries := extractIntoRuntimePolicyRuleList("rule.0.prohibited_binaries", d)
481+
482+
processBasedExceptions := extractIntoRuntimePolicyRuleList("rule.0.process_based_exceptions", d)
483+
484+
processBasedProhibitedBinaries := extractIntoRuntimePolicyRuleList("rule.0.process_based_prohibited_binaries", d)
429485

430486
tags := schemaSetToList(d.Get("rule.0.tags"))
431487
// Set default tags as field tags must not be null
@@ -445,10 +501,12 @@ func setPolicyRulesDrift(policy *v2.PolicyRulesComposite, d *schema.ResourceData
445501
Description: d.Get("rule.0.description").(string),
446502
Tags: tags,
447503
Details: v2.DriftRuleDetails{
448-
RuleType: v2.ElementType("DRIFT"), // TODO: Use const
449-
Mode: mode,
450-
Exceptions: exceptions,
451-
ProhibitedBinaries: prohibitedBinaries,
504+
RuleType: v2.ElementType(driftElementType), // TODO: Use const
505+
Mode: mode,
506+
Exceptions: &exceptions,
507+
ProhibitedBinaries: &prohibitedBinaries,
508+
ProcessBasedExceptions: &processBasedExceptions,
509+
ProcessBasedDenylist: &processBasedProhibitedBinaries,
452510
},
453511
}
454512

@@ -468,6 +526,22 @@ func setPolicyRulesDrift(policy *v2.PolicyRulesComposite, d *schema.ResourceData
468526
return nil
469527
}
470528

529+
func extractIntoRuntimePolicyRuleList(key string, d *schema.ResourceData) v2.RuntimePolicyRuleList {
530+
if _, ok := d.GetOk(key); ok {
531+
items := schemaSetToList(d.Get(key + ".0.items"))
532+
matchItems := d.Get(key + ".0.match_items").(bool)
533+
534+
return v2.RuntimePolicyRuleList{
535+
Items: items,
536+
MatchItems: matchItems,
537+
}
538+
}
539+
return v2.RuntimePolicyRuleList{
540+
Items: []string{},
541+
MatchItems: false,
542+
}
543+
}
544+
471545
func setPolicyRulesML(policy *v2.PolicyRulesComposite, d *schema.ResourceData) error {
472546
policy.Policy.Rules = []*v2.PolicyRule{}
473547
policy.Rules = []*v2.RuntimePolicyRule{}

website/docs/r/secure_drift_policy.md

+4
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ The rule block is required and supports:
118118
* `items` - (Required) Specify comma separated list of exceptions, e.g. `/usr/bin/rm, /usr/bin/curl`.
119119
* `prohibited_binaries` - (Optional) A prohibited binary can be a known harmful binary or one that facilitates discovery of your environment.
120120
* `items` - (Required) Specify comma separated list of prohibited binaries, e.g. `/usr/bin/rm, /usr/bin/curl`.
121+
* `process_based_exceptions` - (Optional) List of processes that will be able to execute a drifted file
122+
* `items` - (Required) Specify comma separated list of processes, e.g. `/usr/bin/rm, /usr/bin/curl`.
123+
* `process_based_prohibited_binaries` - (Optional) List of processes that will be prohibited to execute a drifted file
124+
* `items` - (Required) Specify comma separated list of processes, e.g. `/usr/bin/rm, /usr/bin/curl`.
121125

122126

123127

0 commit comments

Comments
 (0)