-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add new lacework_managed_policies resource (#516)
* feat(GROW-1211): add the lacework_managed_policies resource --------- Co-authored-by: Salim Afiune <[email protected]> Co-authored-by: lacework-aaronscheiber <[email protected]>
- Loading branch information
1 parent
e4fd1ee
commit 5d4f495
Showing
6 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
terraform { | ||
required_providers { | ||
lacework = { | ||
source = "lacework/lacework" | ||
} | ||
} | ||
} | ||
|
||
resource "lacework_managed_policies" "example" { | ||
policy { | ||
id = var.id_1 | ||
enabled = var.enabled_1 | ||
severity = var.severity_1 | ||
} | ||
policy { | ||
id = var.id_2 | ||
enabled = var.enabled_2 | ||
severity = var.severity_2 | ||
} | ||
} | ||
|
||
variable "id_1" { | ||
type = string | ||
default = "lacework-global-1" | ||
} | ||
|
||
variable "enabled_1" { | ||
type = bool | ||
} | ||
|
||
variable "severity_1" { | ||
type = string | ||
} | ||
|
||
variable "id_2" { | ||
type = string | ||
default = "lacework-global-2" | ||
} | ||
|
||
variable "enabled_2" { | ||
type = bool | ||
} | ||
|
||
variable "severity_2" { | ||
type = string | ||
} | ||
|
||
output "policy" { | ||
value = lacework_managed_policies.example.policy | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package integration | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/gruntwork-io/terratest/modules/terraform" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// TestManagedPolicies applies integration terraform: | ||
// => '../examples/resource_lacework_managed_policies' | ||
// | ||
// It uses the go-sdk to verify that the lacework managed policies can be updated correctly. | ||
// nolint | ||
func TestManagedPolicies(t *testing.T) { | ||
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ | ||
TerraformDir: "../examples/resource_lacework_managed_policies", | ||
EnvVars: tokenEnvVar, | ||
Vars: map[string]interface{}{ | ||
"id_1": "lacework-global-1", | ||
"enabled_1": false, | ||
"severity_1": "High", | ||
"id_2": "lacework-global-2", | ||
"enabled_2": false, | ||
"severity_2": "Critical", | ||
}, | ||
}) | ||
defer terraform.Destroy(t, terraformOptions) | ||
|
||
terraform.InitAndApplyAndIdempotent(t, terraformOptions) | ||
|
||
policies := terraform.Output(t, terraformOptions, "policy") | ||
assert.Equal(t, "[map[enabled:false id:lacework-global-1 severity:high] map[enabled:false id:lacework-global-2 severity:critical]]", policies) | ||
|
||
policy1Props := GetPolicyPropsById("lacework-global-1") | ||
assert.False(t, policy1Props.Data.Enabled) | ||
assert.Equal(t, "high", policy1Props.Data.Severity) | ||
|
||
policy2Props := GetPolicyPropsById("lacework-global-2") | ||
assert.False(t, policy2Props.Data.Enabled) | ||
assert.Equal(t, "critical", policy2Props.Data.Severity) | ||
|
||
// Update managed policies | ||
terraformOptions.Vars = map[string]interface{}{ | ||
"id_1": "lacework-global-1", | ||
"enabled_1": true, | ||
"severity_1": "Low", | ||
"id_2": "lacework-global-2", | ||
"enabled_2": true, | ||
"severity_2": "Medium", | ||
} | ||
|
||
terraform.ApplyAndIdempotent(t, terraformOptions) | ||
updatePolicy1Props := GetPolicyPropsById("lacework-global-1") | ||
assert.True(t, updatePolicy1Props.Data.Enabled) | ||
assert.Equal(t, "low", updatePolicy1Props.Data.Severity) | ||
|
||
updatePolicy2Props := GetPolicyPropsById("lacework-global-2") | ||
assert.True(t, updatePolicy2Props.Data.Enabled) | ||
assert.Equal(t, "medium", updatePolicy2Props.Data.Severity) | ||
} | ||
|
||
// TestManagedPoliciesWithDuplicateIDs applies integration terraform: | ||
// => '../examples/resource_lacework_managed_policies' | ||
// | ||
// It uses the go-sdk to verify that the lacework managed policies can not have duplicate policy IDs. | ||
// nolint | ||
func TestManagedPoliciesWithDuplicateIDs(t *testing.T) { | ||
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ | ||
TerraformDir: "../examples/resource_lacework_managed_policies", | ||
EnvVars: tokenEnvVar, | ||
Vars: map[string]interface{}{ | ||
"id_1": "lacework-global-1", | ||
"enabled_1": false, | ||
"severity_1": "High", | ||
"id_2": "lacework-global-1", | ||
"enabled_2": false, | ||
"severity_2": "Critical", | ||
}, | ||
}) | ||
defer terraform.Destroy(t, terraformOptions) | ||
|
||
_, err := terraform.InitAndApplyE(t, terraformOptions) | ||
|
||
assert.Error(t, err) | ||
assert.ErrorContains(t, err, "Unable to update duplicate policy ID") | ||
} | ||
|
||
// TestManagedPoliciesWithCustomIDs applies integration terraform: | ||
// => '../examples/resource_lacework_managed_policies' | ||
// | ||
// It uses the go-sdk to verify if the lacework managed policies can not have custom policy IDs. | ||
// nolint | ||
func TestManagedPoliciesWithCustomIDs(t *testing.T) { | ||
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ | ||
TerraformDir: "../examples/resource_lacework_managed_policies", | ||
EnvVars: tokenEnvVar, | ||
Vars: map[string]interface{}{ | ||
"id_1": "lacework-custom-1", | ||
"enabled_1": false, | ||
"severity_1": "High", | ||
"id_2": "lacework-custom-2", | ||
"enabled_2": false, | ||
"severity_2": "Critical", | ||
}, | ||
}) | ||
defer terraform.Destroy(t, terraformOptions) | ||
|
||
_, err := terraform.InitAndApplyE(t, terraformOptions) | ||
|
||
assert.Error(t, err) | ||
assert.ErrorContains(t, err, "Unable to update custom policy ID") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package lacework | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/lacework/go-sdk/api" | ||
) | ||
|
||
func resourceLaceworkManagedPolicies() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceLaceworkManagedPoliciesCreate, | ||
Update: resourceLaceworkManagedPoliciesUpdate, | ||
Delete: resourceLaceworkManagedPoliciesDelete, | ||
Read: resourceLaceworkManagedPoliciesRead, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"policy": { | ||
Type: schema.TypeSet, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"id": { | ||
Type: schema.TypeString, | ||
Description: "The id of the policy", | ||
Required: true, | ||
}, | ||
"enabled": { | ||
Type: schema.TypeBool, | ||
Description: "The state of the policy", | ||
Required: true, | ||
}, | ||
"severity": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "The severity for the policy. Valid severities are: " + | ||
"Critical, High, Medium, Low, Info", | ||
StateFunc: func(val interface{}) string { | ||
return strings.TrimSpace(strings.ToLower(val.(string))) | ||
}, | ||
ValidateDiagFunc: ValidSeverity(), | ||
}, | ||
}, | ||
}, | ||
Required: true, | ||
Description: "A list of Lacework managed policies", | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceLaceworkManagedPoliciesCreate(d *schema.ResourceData, meta interface{}) error { | ||
d.SetId(time.Now().UTC().String()) | ||
return resourceLaceworkManagedPoliciesUpdate(d, meta) | ||
} | ||
|
||
func resourceLaceworkManagedPoliciesUpdate(d *schema.ResourceData, meta interface{}) error { | ||
lacework := meta.(*api.Client) | ||
policies, err := getBulkUpdatePolicies(d) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
log.Printf("[INFO] Updating Policies with data:\n%+v\n", policies) | ||
_, updateErr := lacework.V2.Policy.UpdateMany(policies) | ||
if updateErr != nil { | ||
return updateErr | ||
} | ||
log.Printf("[INFO] Updated Policies with data:\n%+v\n", policies) | ||
return nil | ||
} | ||
|
||
func resourceLaceworkManagedPoliciesRead(d *schema.ResourceData, meta interface{}) error { | ||
lacework := meta.(*api.Client) | ||
|
||
policiesListResponse, err := lacework.V2.Policy.List() | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
bulkUpdatePolicies, err := getBulkUpdatePolicies(d) | ||
|
||
if err != nil { | ||
// Return nil so that `destroy` can succeed | ||
return nil | ||
} | ||
|
||
policyMap := make(map[string]api.Policy, len(policiesListResponse.Data)) | ||
|
||
for _, policy := range policiesListResponse.Data { | ||
policyMap[policy.PolicyID] = policy | ||
} | ||
|
||
policySet := make([]map[string]any, len(bulkUpdatePolicies)) | ||
|
||
for i, bulkUpdatePolicy := range bulkUpdatePolicies { | ||
policySet[i] = map[string]any{} | ||
policySet[i]["id"] = bulkUpdatePolicy.PolicyID | ||
policySet[i]["enabled"] = policyMap[bulkUpdatePolicy.PolicyID].Enabled | ||
policySet[i]["severity"] = policyMap[bulkUpdatePolicy.PolicyID].Severity | ||
} | ||
|
||
d.Set("policy", policySet) | ||
|
||
return nil | ||
} | ||
|
||
func resourceLaceworkManagedPoliciesDelete(d *schema.ResourceData, meta interface{}) error { | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
func getBulkUpdatePolicies(d *schema.ResourceData) (api.BulkUpdatePolicies, error) { | ||
var policies api.BulkUpdatePolicies | ||
list := d.Get("policy").(*schema.Set).List() | ||
seen := make(map[string]bool, 0) | ||
|
||
for _, v := range list { | ||
val := v.(map[string]interface{}) | ||
|
||
if val["id"] == nil || val["id"] == "" { | ||
continue | ||
} | ||
|
||
policyID := val["id"].(string) | ||
enabled := val["enabled"].(bool) | ||
|
||
if !strings.HasPrefix(policyID, "lacework-global") { | ||
return nil, fmt.Errorf("Unable to update custom policy ID: %s", policyID) | ||
} | ||
if seen[policyID] == true { | ||
return nil, fmt.Errorf("Unable to update duplicate policy ID: %s", policyID) | ||
} | ||
|
||
policy := api.BulkUpdatePolicy{ | ||
PolicyID: policyID, | ||
Enabled: &enabled, | ||
Severity: val["severity"].(string), | ||
} | ||
|
||
seen[policyID] = true | ||
policies = append(policies, policy) | ||
} | ||
return policies, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
--- | ||
subcategory: "Policies" | ||
layout: "lacework" | ||
page_title: "Lacework: lacework_managed_policies" | ||
description: |- | ||
Manage Lacework Defined Policies | ||
--- | ||
|
||
# lacework\_managed\_policies | ||
|
||
Use this resource to update the `state` (enabled/disabled) and the `severity` properties for Lacework-defined policies. | ||
|
||
## Example Usage | ||
|
||
The following example shows how to manage three Lacework-defined policies. | ||
|
||
```hcl | ||
resource "lacework_managed_policies" "example" { | ||
policy { | ||
id = "lacework-global-1" | ||
enabled = true | ||
severity = "High" | ||
} | ||
policy { | ||
id = "lacework-global-2" | ||
enabled = false | ||
severity = "Critical" | ||
} | ||
policy { | ||
id = "lacework-global-10" | ||
enabled = true | ||
severity = "Low" | ||
} | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
For each `policy` block, the following arguments are supported: | ||
|
||
* `id` - (Required) The Lacework-defined policy id. | ||
* `enabled` - (Required) Whether the policy is enabled or disabled. | ||
* `severity` - (Required) The list of the severities. Valid severities include: | ||
`Critical`, `High`, `Medium`, `Low` and `Info`. |