Skip to content

Commit

Permalink
feat: add new lacework_managed_policies resource (#516)
Browse files Browse the repository at this point in the history
* 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
3 people authored Jul 25, 2023
1 parent e4fd1ee commit 5d4f495
Show file tree
Hide file tree
Showing 6 changed files with 365 additions and 0 deletions.
50 changes: 50 additions & 0 deletions examples/resource_lacework_managed_policies/main.tf
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
}
8 changes: 8 additions & 0 deletions integration/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,14 @@ func GetPolicyProps(result string) api.PolicyResponse {
return resp
}

func GetPolicyPropsById(id string) api.PolicyResponse {
resp, err := LwClient.V2.Policy.Get(id)
if err != nil {
log.Fatalf("Unable to retrieve policy with id: %s", id)
}
return resp
}

func GetPolicyExceptionProps(result string, policyID string) (resp api.PolicyExceptionResponse) {
id := GetSpecificIDFromTerraResults(1, result)
err := LwClient.V2.Policy.Exceptions.Get(policyID, id, &resp)
Expand Down
113 changes: 113 additions & 0 deletions integration/resource_lacework_managed_policies_test.go
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")
}
1 change: 1 addition & 0 deletions lacework/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func Provider() *schema.Provider {
"lacework_integration_oci_cfg": resourceLaceworkIntegrationOciCfg(),
"lacework_integration_proxy_scanner": resourceLaceworkIntegrationProxyScanner(),
"lacework_query": resourceLaceworkQuery(),
"lacework_managed_policies": resourceLaceworkManagedPolicies(),
"lacework_policy": resourceLaceworkPolicy(),
"lacework_policy_compliance": resourceLaceworkPolicyCompliance(),
"lacework_policy_exception": resourceLaceworkPolicyException(),
Expand Down
149 changes: 149 additions & 0 deletions lacework/resource_lacework_managed_policies.go
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
}
44 changes: 44 additions & 0 deletions website/docs/r/managed_policies.html.markdown
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`.

0 comments on commit 5d4f495

Please sign in to comment.