-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New Data Source: wiz_host_config_rules (#30)
Added a new data source to retrieve Wiz host configuration rules. closes #24
- Loading branch information
Showing
7 changed files
with
446 additions
and
1 deletion.
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
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,56 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "wiz_host_config_rules Data Source - terraform-provider-wiz" | ||
subcategory: "" | ||
description: |- | ||
Query cloud configuration rules. | ||
--- | ||
|
||
# wiz_host_config_rules (Data Source) | ||
|
||
Query cloud configuration rules. | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
# get the first five host configuration rules for access keys | ||
data "wiz_host_config_rules" "access" { | ||
first = 5 | ||
search = "access" | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Optional | ||
|
||
- `enabled` (Boolean) Host Configuration Rule enabled status. | ||
- `first` (Number) How many results to return | ||
- Defaults to `500`. | ||
- `framework_category` (List of String) Search rules by any of securityFramework | securitySubCategory | securityCategory. | ||
- `search` (String) Free text search on id, name, externalId. | ||
- `target_platform` (List of String) Search by target platforms. | ||
|
||
### Read-Only | ||
|
||
- `host_configuration_rules` (Set of Object) The returned cloud configuration rules. (see [below for nested schema](#nestedatt--host_configuration_rules)) | ||
- `id` (String) Internal identifier for the data. | ||
|
||
<a id="nestedatt--host_configuration_rules"></a> | ||
### Nested Schema for `host_configuration_rules` | ||
|
||
Read-Only: | ||
|
||
- `builtin` (Boolean) | ||
- `description` (String) | ||
- `direct_oval` (String) | ||
- `enabled` (Boolean) | ||
- `external_id` (String) | ||
- `id` (String) | ||
- `name` (String) | ||
- `security_sub_category_ids` (List of String) | ||
- `short_name` (String) | ||
- `target_platform_ids` (List of String) | ||
|
||
|
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,5 @@ | ||
# get the first five host configuration rules for access keys | ||
data "wiz_host_config_rules" "access" { | ||
first = 5 | ||
search = "access" | ||
} |
316 changes: 316 additions & 0 deletions
316
internal/provider/data_source_host_configuration_rules.go
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,316 @@ | ||
package provider | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"crypto/sha1" | ||
"encoding/hex" | ||
"fmt" | ||
"sort" | ||
|
||
"github.com/hashicorp/terraform-plugin-log/tflog" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"wiz.io/hashicorp/terraform-provider-wiz/internal" | ||
"wiz.io/hashicorp/terraform-provider-wiz/internal/client" | ||
"wiz.io/hashicorp/terraform-provider-wiz/internal/utils" | ||
"wiz.io/hashicorp/terraform-provider-wiz/internal/vendor" | ||
) | ||
|
||
func dataSourceWizHostConfigurationRules() *schema.Resource { | ||
return &schema.Resource{ | ||
Description: "Query cloud configuration rules.", | ||
Schema: map[string]*schema.Schema{ | ||
"id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "Internal identifier for the data.", | ||
}, | ||
"first": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 500, | ||
Description: "How many results to return", | ||
}, | ||
"search": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Description: "Free text search on id, name, externalId.", | ||
}, | ||
"enabled": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Description: "Host Configuration Rule enabled status.", | ||
}, | ||
"framework_category": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
Description: "Search rules by any of securityFramework | securitySubCategory | securityCategory.", | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
}, | ||
}, | ||
"target_platform": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
Description: "Search by target platforms.", | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
}, | ||
}, | ||
"host_configuration_rules": { | ||
Type: schema.TypeSet, | ||
Computed: true, | ||
Description: "The returned cloud configuration rules.", | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "Wiz UUID.", | ||
}, | ||
"external_id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "An external id for the rule.", | ||
}, | ||
"name": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "The name of the rule.", | ||
}, | ||
"short_name": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "A short name that identifies the rule.", | ||
}, | ||
"description": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"enabled": { | ||
Type: schema.TypeBool, | ||
Computed: true, | ||
Description: "Rule enabled status.", | ||
}, | ||
"security_sub_category_ids": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
}, | ||
}, | ||
"builtin": { | ||
Type: schema.TypeBool, | ||
Computed: true, | ||
Description: "Indication whether the rule is built-in or custom.", | ||
}, | ||
"direct_oval": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "Direct OVAL definition assessed on hosts during disk scanning.", | ||
}, | ||
"target_platform_ids": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
Description: "The platforms the rule is targeting. e.g Ubuntu, RedHat, NGINX.", | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
ReadContext: dataSourceWizHostConfigurationRuleRead, | ||
} | ||
} | ||
|
||
// ReadHostConfigurationRules struct | ||
type ReadHostConfigurationRules struct { | ||
HostConfigurationRules vendor.HostConfigurationRuleConnection `json:"hostConfigurationRules"` | ||
} | ||
|
||
func dataSourceWizHostConfigurationRuleRead(ctx context.Context, d *schema.ResourceData, m interface{}) (diags diag.Diagnostics) { | ||
tflog.Info(ctx, "dataSourceWizHostConfigurationRuleRead called...") | ||
|
||
// generate the id for this resource | ||
// id must be deterministic, so the id is based on a hash of the search parameters | ||
var identifier bytes.Buffer | ||
|
||
a, b := d.GetOk("first") | ||
if b { | ||
identifier.WriteString(utils.PrettyPrint(a)) | ||
} | ||
a, b = d.GetOk("search") | ||
if b { | ||
identifier.WriteString(utils.PrettyPrint(a)) | ||
} | ||
a, b = d.GetOk("enabled") | ||
if b { | ||
identifier.WriteString(utils.PrettyPrint(a)) | ||
} | ||
a, b = d.GetOk("framework_category") | ||
if b { | ||
identifier.WriteString(utils.PrettyPrint(a)) | ||
} | ||
a, b = d.GetOk("target_platform") | ||
if b { | ||
identifier.WriteString(utils.PrettyPrint(a)) | ||
} | ||
|
||
h := sha1.New() | ||
h.Write([]byte(identifier.String())) | ||
hashID := hex.EncodeToString(h.Sum(nil)) | ||
|
||
// Set the id | ||
d.SetId(hashID) | ||
|
||
// define the graphql query | ||
query := `query hostConfigurationRules( | ||
$filterBy: HostConfigurationRuleFilters | ||
$first: Int | ||
$after: String | ||
$orderBy: HostConfigurationRuleOrder | ||
) { | ||
hostConfigurationRules( | ||
filterBy: $filterBy | ||
first: $first | ||
after: $after | ||
orderBy: $orderBy | ||
) { | ||
nodes { | ||
id | ||
externalId | ||
name | ||
shortName | ||
description | ||
enabled | ||
securitySubCategories { | ||
id | ||
} | ||
builtin | ||
directOVAL | ||
targetPlatforms { | ||
id | ||
} | ||
} | ||
pageInfo { | ||
hasNextPage | ||
endCursor | ||
} | ||
totalCount | ||
} | ||
}` | ||
|
||
// set the resource parameters | ||
err := d.Set("first", d.Get("first").(int)) | ||
if err != nil { | ||
return append(diags, diag.FromErr(err)...) | ||
} | ||
err = d.Set("search", d.Get("search").(string)) | ||
if err != nil { | ||
return append(diags, diag.FromErr(err)...) | ||
} | ||
a, b = d.GetOk("enabled") | ||
if b { | ||
err = d.Set("enabled", a.(bool)) | ||
if err != nil { | ||
return append(diags, diag.FromErr(err)...) | ||
} | ||
} | ||
err = d.Set("framework_category", d.Get("framework_category").([]interface{})) | ||
if err != nil { | ||
return append(diags, diag.FromErr(err)...) | ||
} | ||
err = d.Set("target_platform", d.Get("target_platform").([]interface{})) | ||
if err != nil { | ||
return append(diags, diag.FromErr(err)...) | ||
} | ||
|
||
// populate the graphql variables | ||
vars := &internal.QueryVariables{} | ||
vars.First = d.Get("first").(int) | ||
filterBy := &vendor.HostConfigurationRuleFilters{} | ||
a, b = d.GetOk("search") | ||
if b { | ||
filterBy.Search = a.(string) | ||
} | ||
a, b = d.GetOk("enabled") | ||
if b { | ||
filterBy.Enabled = utils.ConvertBoolToPointer(a.(bool)) | ||
} | ||
a, b = d.GetOk("framework_category") | ||
if b { | ||
filterBy.FrameworkCategory = utils.ConvertListToString(a.([]interface{})) | ||
} | ||
a, b = d.GetOk("target_platform") | ||
if b { | ||
filterBy.TargetPlatforms = utils.ConvertListToString(a.([]interface{})) | ||
} | ||
|
||
vars.FilterBy = filterBy | ||
|
||
// process the request | ||
data := &ReadHostConfigurationRules{} | ||
requestDiags := client.ProcessRequest(ctx, m, vars, data, query, "host_config_rules", "read") | ||
diags = append(diags, requestDiags...) | ||
if len(diags) > 0 { | ||
return diags | ||
} | ||
|
||
hostConfigurationRules := flattenHostConfigurationRules(ctx, &data.HostConfigurationRules.Nodes) | ||
if err := d.Set("host_configuration_rules", hostConfigurationRules); err != nil { | ||
return append(diags, diag.FromErr(err)...) | ||
} | ||
|
||
return diags | ||
} | ||
|
||
func flattenHostConfigurationRules(ctx context.Context, nodes *[]*vendor.HostConfigurationRule) []interface{} { | ||
tflog.Info(ctx, "flattenHostConfigurationRules called...") | ||
tflog.Debug(ctx, fmt.Sprintf("HostConfigurationRules: %s", utils.PrettyPrint(nodes))) | ||
|
||
// walk the slice and construct the list | ||
var output = make([]interface{}, 0, 0) | ||
for _, b := range *nodes { | ||
tflog.Debug(ctx, fmt.Sprintf("b: %T %s", b, utils.PrettyPrint(b))) | ||
ruleMap := make(map[string]interface{}) | ||
ruleMap["id"] = b.ID | ||
ruleMap["name"] = b.Name | ||
ruleMap["short_name"] = b.ShortName | ||
ruleMap["builtin"] = b.Builtin | ||
ruleMap["description"] = b.Description | ||
ruleMap["direct_oval"] = b.DirectOVAL | ||
ruleMap["external_id"] = b.ExternalID | ||
ruleMap["security_sub_category_ids"] = flattenSecuritySubCategoryIDs(ctx, &b.SecuritySubCategories) | ||
ruleMap["target_platform_ids"] = flattenTargetPlatformIDs(ctx, b.TargetPlatforms) | ||
|
||
output = append(output, ruleMap) | ||
} | ||
|
||
tflog.Debug(ctx, fmt.Sprintf("flattenCloudConfigurationRules output: %s", utils.PrettyPrint(output))) | ||
|
||
return output | ||
} | ||
|
||
func flattenTargetPlatformIDs(ctx context.Context, plats []vendor.Technology) []interface{} { | ||
tflog.Info(ctx, "flattenTargetPlatformIDs called...") | ||
tflog.Debug(ctx, fmt.Sprintf("TargetPlatforms: %s", utils.PrettyPrint(plats))) | ||
|
||
// walk the slice and construct the list | ||
var output = make([]interface{}, 0, 0) | ||
for _, b := range plats { | ||
tflog.Debug(ctx, fmt.Sprintf("b: %T %s", b, utils.PrettyPrint(b))) | ||
output = append(output, b.ID) | ||
} | ||
|
||
// sort the return slice to avoid unwanted diffs | ||
sort.Slice(output, func(i, j int) bool { | ||
return output[i].(string) < output[j].(string) | ||
}) | ||
|
||
tflog.Debug(ctx, fmt.Sprintf("flattenTargetPlatformIDs output: %s", utils.PrettyPrint(output))) | ||
|
||
return output | ||
} |
Oops, something went wrong.