diff --git a/cyral/internal/policywizard/v1/constants.go b/cyral/internal/policywizard/v1/constants.go
new file mode 100644
index 00000000..fbcc038a
--- /dev/null
+++ b/cyral/internal/policywizard/v1/constants.go
@@ -0,0 +1,7 @@
+package policywizardv1
+
+const (
+ resourceName = "cyral_policy_wizard_v1"
+ dataSourceName = resourceName
+ apiPathPolicySet = "v1/policyWizards/policySets"
+)
diff --git a/cyral/internal/policywizard/v1/datasource.go b/cyral/internal/policywizard/v1/datasource.go
new file mode 100644
index 00000000..fb97b9dc
--- /dev/null
+++ b/cyral/internal/policywizard/v1/datasource.go
@@ -0,0 +1,111 @@
+package policywizardv1
+
+import (
+ "fmt"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+
+ "github.com/cyralinc/terraform-provider-cyral/cyral/client"
+ "github.com/cyralinc/terraform-provider-cyral/cyral/core"
+ "github.com/cyralinc/terraform-provider-cyral/cyral/core/types/resourcetype"
+)
+
+var dsContextHandler = core.DefaultContextHandler{
+ ResourceName: dataSourceName,
+ ResourceType: resourcetype.DataSource,
+ SchemaWriterFactoryGetMethod: func(_ *schema.ResourceData) core.SchemaWriter { return &PolicySet{} },
+ ReadUpdateDeleteURLFactory: func(d *schema.ResourceData, c *client.Client) string {
+ return fmt.Sprintf("https://%s/%s/%s", c.ControlPlane, apiPathPolicySet, d.Get("id").(string))
+ },
+}
+
+func dataSourceSchema() *schema.Resource {
+ return &schema.Resource{
+ Description: "This data source provides information about a policy set.",
+ ReadContext: dsContextHandler.ReadContext(),
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Description: "Identifier for the policy set.",
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "wizard_id": {
+ Description: "The ID of the policy wizard used to create this policy set.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "name": {
+ Description: "Name of the policy set.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "description": {
+ Description: "Description of the policy set.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "tags": {
+ Description: "Tags associated with the policy set.",
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ },
+ "scope": {
+ Description: "Scope of the policy set.",
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "repo_ids": {
+ Description: "List of repository IDs that are in scope. Empty list means all repositories are in scope.",
+ Type: schema.TypeList,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ Computed: true,
+ },
+ },
+ },
+ },
+ "wizard_parameters": {
+ Description: "Parameters passed to the wizard while creating the policy set.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "enabled": {
+ Description: "Indicates if the policy set is enabled.",
+ Type: schema.TypeBool,
+ Computed: true,
+ },
+ "policies": {
+ Description: "List of policies that comprise the policy set.",
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "type": {
+ Description: "Type of the policy.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "id": {
+ Description: "ID of the policy.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ },
+ },
+ "last_updated": {
+ Description: "Information about when and by whom the policy set was last updated.",
+ Type: schema.TypeMap,
+ Computed: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ },
+ "created": {
+ Description: "Information about when and by whom the policy set was created.",
+ Type: schema.TypeMap,
+ Computed: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ },
+ },
+ }
+}
diff --git a/cyral/internal/policywizard/v1/model.go b/cyral/internal/policywizard/v1/model.go
new file mode 100644
index 00000000..e10a5857
--- /dev/null
+++ b/cyral/internal/policywizard/v1/model.go
@@ -0,0 +1,147 @@
+package policywizardv1
+
+import (
+ "fmt"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+
+ "github.com/cyralinc/terraform-provider-cyral/cyral/utils"
+)
+
+// ChangeInfo represents information about changes to the policy set
+type ChangeInfo struct {
+ Actor string `json:"actor,omitempty"`
+ ActorType string `json:"actorType,omitempty"`
+ Timestamp string `json:"timestamp,omitempty"`
+}
+
+// ToMap converts ChangeInfo to a map
+func (c ChangeInfo) ToMap() map[string]interface{} {
+ return map[string]interface{}{
+ "actor": c.Actor,
+ "actor_type": c.ActorType,
+ "timestamp": c.Timestamp,
+ }
+}
+
+// PolicySetPolicy represents a policy in the policy set
+type PolicySetPolicy struct {
+ Type string `json:"type,omitempty"`
+ ID string `json:"id,omitempty"`
+}
+
+// ToMap converts PolicySetPolicy to a map
+func (p PolicySetPolicy) ToMap() map[string]interface{} {
+ return map[string]interface{}{
+ "type": p.Type,
+ "id": p.ID,
+ }
+}
+
+// Scope represents the scope of the policy set
+type Scope struct {
+ RepoIds []string `json:"repoIds,omitempty"`
+}
+
+// ToMap converts Scope to a list of maps
+func (s *Scope) ToMap() []map[string]interface{} {
+ return []map[string]interface{}{
+ {
+ "repo_ids": s.RepoIds,
+ },
+ }
+}
+
+// PolicySet represents the policy set details
+type PolicySet struct {
+ ID string `json:"id,omitempty"`
+ WizardID string `json:"wizardId,omitempty"`
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ Tags []string `json:"tags,omitempty"`
+ Scope *Scope `json:"scope,omitempty"`
+ WizardParameters string `json:"wizardParameters,omitempty"`
+ Enabled bool `json:"enabled,omitempty"`
+ Policies []PolicySetPolicy `json:"policies,omitempty"`
+ LastUpdated ChangeInfo `json:"lastUpdated,omitempty"`
+ Created ChangeInfo `json:"created,omitempty"`
+}
+
+// WriteToSchema writes the policy set data to the schema
+func (r *PolicySet) WriteToSchema(d *schema.ResourceData) error {
+ if err := d.Set("id", r.ID); err != nil {
+ return fmt.Errorf("error setting 'id' field: %w", err)
+ }
+ if err := d.Set("wizard_id", r.WizardID); err != nil {
+ return fmt.Errorf("error setting 'wizard_id' field: %w", err)
+ }
+ if err := d.Set("name", r.Name); err != nil {
+ return fmt.Errorf("error setting 'name' field: %w", err)
+ }
+ if err := d.Set("description", r.Description); err != nil {
+ return fmt.Errorf("error setting 'description' field: %w", err)
+ }
+ if err := d.Set("tags", r.Tags); err != nil {
+ return fmt.Errorf("error setting 'tags' field: %w", err)
+ }
+ if err := d.Set("wizard_parameters", r.WizardParameters); err != nil {
+ return fmt.Errorf("error setting 'wizard_parameters' field: %w", err)
+ }
+ if err := d.Set("enabled", r.Enabled); err != nil {
+ return fmt.Errorf("error setting 'enabled' field: %w", err)
+ }
+ if err := d.Set("policies", policiesToMaps(r.Policies)); err != nil {
+ return fmt.Errorf("error setting 'policies' field: %w", err)
+ }
+ if err := d.Set("last_updated", r.LastUpdated.ToMap()); err != nil {
+ return fmt.Errorf("error setting 'last_updated' field: %w", err)
+ }
+ if err := d.Set("created", r.Created.ToMap()); err != nil {
+ return fmt.Errorf("error setting 'created' field: %w", err)
+ }
+ if r.Scope != nil {
+ if err := d.Set("scope", r.Scope.ToMap()); err != nil {
+ return fmt.Errorf("error setting 'scope' field: %w", err)
+ }
+ }
+ d.SetId(r.ID)
+ return nil
+}
+
+func policiesToMaps(policies []PolicySetPolicy) []map[string]interface{} {
+ var result []map[string]interface{}
+ for _, policy := range policies {
+ result = append(result, policy.ToMap())
+ }
+ return result
+}
+
+// ReadFromSchema reads the policy set data from the schema
+func (r *PolicySet) ReadFromSchema(d *schema.ResourceData) error {
+ r.ID = d.Get("id").(string)
+ r.WizardID = d.Get("wizard_id").(string)
+ r.Name = d.Get("name").(string)
+ r.Description = d.Get("description").(string)
+ r.Tags = utils.ConvertFromInterfaceList[string](d.Get("tags").([]interface{}))
+ r.WizardParameters = d.Get("wizard_parameters").(string)
+ r.Enabled = d.Get("enabled").(bool)
+ if v, ok := d.GetOk("scope"); ok {
+ r.Scope = scopeFromInterface(v.([]interface{}))
+ }
+ return nil
+}
+
+// scopeFromInterface converts the map to a Scope struct
+func scopeFromInterface(s []interface{}) *Scope {
+ if len(s) == 0 || s[0] == nil {
+ // return an empty scope (ie a scope with a repo ids array of length 0)
+ return &Scope{
+ RepoIds: []string{},
+ }
+ }
+ m := s[0].(map[string]interface{})
+ scope := Scope{
+ RepoIds: utils.ConvertFromInterfaceList[string](m["repo_ids"].([]interface{})),
+ }
+ return &scope
+}
diff --git a/cyral/internal/policywizard/v1/resource.go b/cyral/internal/policywizard/v1/resource.go
new file mode 100644
index 00000000..b54c83d3
--- /dev/null
+++ b/cyral/internal/policywizard/v1/resource.go
@@ -0,0 +1,130 @@
+package policywizardv1
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+
+ "github.com/cyralinc/terraform-provider-cyral/cyral/client"
+ "github.com/cyralinc/terraform-provider-cyral/cyral/core"
+ "github.com/cyralinc/terraform-provider-cyral/cyral/core/types/resourcetype"
+)
+
+var resourceContextHandler = core.DefaultContextHandler{
+ ResourceName: resourceName,
+ ResourceType: resourcetype.Resource,
+ SchemaReaderFactory: func() core.SchemaReader { return &PolicySet{} },
+ SchemaWriterFactoryGetMethod: func(_ *schema.ResourceData) core.SchemaWriter { return &PolicySet{} },
+ BaseURLFactory: func(d *schema.ResourceData, c *client.Client) string {
+ return fmt.Sprintf("https://%s/%s", c.ControlPlane, apiPathPolicySet)
+ },
+ ReadUpdateDeleteURLFactory: func(d *schema.ResourceData, c *client.Client) string {
+ return fmt.Sprintf("https://%s/%s/%s",
+ c.ControlPlane,
+ apiPathPolicySet,
+ d.Id(),
+ )
+ },
+}
+
+func resourceSchema() *schema.Resource {
+ return &schema.Resource{
+ Description: "This resource allows management of policy sets in the Cyral platform.",
+ CreateContext: resourceContextHandler.CreateContext(),
+ ReadContext: resourceContextHandler.ReadContext(),
+ UpdateContext: resourceContextHandler.UpdateContext(),
+ DeleteContext: resourceContextHandler.DeleteContext(),
+ Importer: &schema.ResourceImporter{
+ StateContext: importPolicySetStateContext,
+ },
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Description: "Identifier for the policy set.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "wizard_id": {
+ Description: "The ID of the policy wizard used to create this policy set.",
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "name": {
+ Description: "Name of the policy set.",
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "description": {
+ Description: "Description of the policy set.",
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "tags": {
+ Description: "Tags associated with the policy set.",
+ Type: schema.TypeList,
+ Optional: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ },
+ "scope": {
+ Description: "Scope of the policy set.",
+ Type: schema.TypeList,
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "repo_ids": {
+ Description: "List of repository IDs that are in scope. Empty list means all repositories are in scope.",
+ Type: schema.TypeList,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ Optional: true,
+ },
+ },
+ },
+ },
+ "wizard_parameters": {
+ Description: "Parameters passed to the wizard while creating the policy set.",
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "enabled": {
+ Description: "Indicates if the policy set is enabled.",
+ Type: schema.TypeBool,
+ Optional: true,
+ },
+ "policies": {
+ Description: "List of policies that comprise the policy set.",
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "type": {
+ Description: "Type of the policy.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "id": {
+ Description: "ID of the policy.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ },
+ },
+ "last_updated": {
+ Description: "Information about when and by whom the policy set was last updated.",
+ Type: schema.TypeMap,
+ Computed: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ },
+ "created": {
+ Description: "Information about when and by whom the policy set was created.",
+ Type: schema.TypeMap,
+ Computed: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ },
+ },
+ }
+}
+
+func importPolicySetStateContext(_ context.Context, d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
+ return []*schema.ResourceData{d}, nil
+}
diff --git a/cyral/internal/policywizard/v1/resource_test.go b/cyral/internal/policywizard/v1/resource_test.go
new file mode 100644
index 00000000..e0d89eba
--- /dev/null
+++ b/cyral/internal/policywizard/v1/resource_test.go
@@ -0,0 +1,162 @@
+package policywizardv1_test
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
+
+ "github.com/cyralinc/terraform-provider-cyral/cyral/provider"
+)
+
+func initialPolicySetConfig() map[string]interface{} {
+ wizardParameters := `{"failClosed":true,"denyByDefault":true}`
+
+ return map[string]interface{}{
+ "wizard_id": "repo-lockdown",
+ "name": "Lockdown all repos",
+ "description": "Policy set created via wizard",
+ "tags": []string{"default", "block", "fail closed"},
+ "scope": map[string][]string{"repo_ids": {}}, // Empty scope means to target all repos
+ "wizard_parameters": wizardParameters,
+ "enabled": true,
+ }
+}
+
+func updatedPolicySetConfig() map[string]interface{} {
+ wizardParameters := `{"failClosed":false,"denyByDefault":true}`
+
+ return map[string]interface{}{
+ "wizard_id": "repo-lockdown",
+ "name": "Lockdown all repos",
+ "description": "Updated policy set created via wizard",
+ "tags": []string{"default", "block", "fail open"},
+ "scope": map[string][]string{"repo_ids": {}},
+ "wizard_parameters": wizardParameters,
+ "enabled": true,
+ }
+}
+
+func TestAccPolicyWizardV1Resource(t *testing.T) {
+ testInitialConfig, testInitialFunc := setupPolicySetTest("main_test", initialPolicySetConfig())
+ testUpdatedConfig, testUpdatedFunc := setupPolicySetTest("main_test", updatedPolicySetConfig())
+ resource.Test(t, resource.TestCase{
+ ProviderFactories: provider.ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testInitialConfig,
+ Check: testInitialFunc,
+ },
+ {
+ Config: testUpdatedConfig,
+ Check: testUpdatedFunc,
+ },
+ {
+ // Test importing the resource
+ ResourceName: "cyral_policy_wizard_v1.main_test",
+ ImportState: true,
+ ImportStateIdFunc: testImportStateIdFunc("cyral_policy_wizard_v1.main_test"),
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func setupPolicySetTest(resName string, policySet map[string]interface{}) (string, resource.TestCheckFunc) {
+ config := formatPolicySetIntoConfig(resName, policySet)
+ resourceFullName := fmt.Sprintf("cyral_policy_wizard_v1.%s", resName)
+
+ testFunction := resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceFullName, "wizard_id", policySet["wizard_id"].(string)),
+ resource.TestCheckResourceAttr(resourceFullName, "name", policySet["name"].(string)),
+ resource.TestCheckResourceAttr(resourceFullName, "description", policySet["description"].(string)),
+ resource.TestCheckResourceAttr(resourceFullName, "wizard_parameters", policySet["wizard_parameters"].(string)),
+ resource.TestCheckResourceAttr(resourceFullName, "enabled", fmt.Sprintf("%v", policySet["enabled"])),
+ )
+
+ // Check tags
+ if tags, ok := policySet["tags"].([]string); ok && len(tags) > 0 {
+ for i, tag := range tags {
+ key := fmt.Sprintf("tags.%d", i)
+ testFunction = resource.ComposeTestCheckFunc(
+ testFunction,
+ resource.TestCheckResourceAttr(resourceFullName, key, tag),
+ )
+ }
+ }
+
+ // Check scope
+ if scope, ok := policySet["scope"].(map[string][]string); ok {
+ if repoIds, ok := scope["repo_ids"]; ok && len(repoIds) > 0 {
+ for i, repoId := range repoIds {
+ key := fmt.Sprintf("scope.0.repo_ids.%d", i)
+ testFunction = resource.ComposeTestCheckFunc(
+ testFunction,
+ resource.TestCheckResourceAttr(resourceFullName, key, repoId),
+ )
+ }
+ }
+ }
+
+ return config, testFunction
+}
+
+func formatPolicySetIntoConfig(resName string, policySet map[string]interface{}) string {
+ config := fmt.Sprintf(`
+resource "cyral_policy_wizard_v1" "%s" {
+ wizard_id = "%s"
+ name = "%s"
+`, resName, policySet["wizard_id"].(string), policySet["name"].(string))
+
+ if description, ok := policySet["description"].(string); ok && description != "" {
+ config += fmt.Sprintf(` description = "%s"
+`, description)
+ }
+
+ // Handle tags
+ if tags, ok := policySet["tags"].([]string); ok && len(tags) > 0 {
+ config += " tags = [\n"
+ for _, tag := range tags {
+ config += fmt.Sprintf(` "%s",
+`, tag)
+ }
+ config += " ]\n"
+ }
+
+ // Handle scope
+ if scope, ok := policySet["scope"].(map[string][]string); ok {
+ if repoIds, ok := scope["repo_ids"]; ok && len(repoIds) > 0 {
+ config += " scope {\n"
+ config += " repo_ids = [\n"
+ for _, repoId := range repoIds {
+ config += fmt.Sprintf(` "%s",
+`, repoId)
+ }
+ config += " ]\n"
+ config += " }\n"
+ }
+ }
+
+ // Properly escape wizard_parameters
+ config += fmt.Sprintf(" wizard_parameters = %q\n", policySet["wizard_parameters"].(string))
+
+ if enabled, ok := policySet["enabled"].(bool); ok {
+ config += fmt.Sprintf(" enabled = %v\n", enabled)
+ }
+
+ config += "}\n"
+
+ return config
+}
+
+func testImportStateIdFunc(resourceName string) func(*terraform.State) (string, error) {
+ return func(s *terraform.State) (string, error) {
+ rs, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return "", fmt.Errorf("resource %s not found in state", resourceName)
+ }
+ // The ID is the policy set ID
+ return rs.Primary.ID, nil
+ }
+}
diff --git a/cyral/internal/policywizard/v1/schema_loader.go b/cyral/internal/policywizard/v1/schema_loader.go
new file mode 100644
index 00000000..34139d21
--- /dev/null
+++ b/cyral/internal/policywizard/v1/schema_loader.go
@@ -0,0 +1,31 @@
+package policywizardv1
+
+import "github.com/cyralinc/terraform-provider-cyral/cyral/core"
+
+type packageSchema struct {
+}
+
+func (p *packageSchema) Name() string {
+ return "policywizardv1"
+}
+
+func (p *packageSchema) Schemas() []*core.SchemaDescriptor {
+ return []*core.SchemaDescriptor{
+
+ {
+ Name: dataSourceName,
+ Type: core.DataSourceSchemaType,
+ Schema: dataSourceSchema,
+ },
+
+ {
+ Name: resourceName,
+ Type: core.ResourceSchemaType,
+ Schema: resourceSchema,
+ },
+ }
+}
+
+func PackageSchema() core.PackageSchema {
+ return &packageSchema{}
+}
diff --git a/cyral/provider/schema_loader.go b/cyral/provider/schema_loader.go
index 0cc34034..2c0de7d7 100644
--- a/cyral/provider/schema_loader.go
+++ b/cyral/provider/schema_loader.go
@@ -16,6 +16,7 @@ import (
integration_teams "github.com/cyralinc/terraform-provider-cyral/cyral/internal/integration/teams"
"github.com/cyralinc/terraform-provider-cyral/cyral/internal/permission"
policyv2 "github.com/cyralinc/terraform-provider-cyral/cyral/internal/policy/v2"
+ policywizardv1 "github.com/cyralinc/terraform-provider-cyral/cyral/internal/policywizard/v1"
"github.com/cyralinc/terraform-provider-cyral/cyral/internal/regopolicy"
"github.com/cyralinc/terraform-provider-cyral/cyral/internal/repository"
repository_accessgateway "github.com/cyralinc/terraform-provider-cyral/cyral/internal/repository/accessgateway"
@@ -56,6 +57,7 @@ func packagesSchemas() []core.PackageSchema {
integration_teams.PackageSchema(),
permission.PackageSchema(),
policyv2.PackageSchema(),
+ policywizardv1.PackageSchema(),
regopolicy.PackageSchema(),
repository.PackageSchema(),
repository_accessgateway.PackageSchema(),
diff --git a/docs/data-sources/policy_wizard_v1.md b/docs/data-sources/policy_wizard_v1.md
new file mode 100644
index 00000000..899ba57b
--- /dev/null
+++ b/docs/data-sources/policy_wizard_v1.md
@@ -0,0 +1,49 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "cyral_policy_wizard_v1 Data Source - terraform-provider-cyral"
+subcategory: ""
+description: |-
+ This data source provides information about a policy set.
+---
+
+# cyral_policy_wizard_v1 (Data Source)
+
+This data source provides information about a policy set.
+
+
+
+## Schema
+
+### Required
+
+- `id` (String) Identifier for the policy set.
+
+### Read-Only
+
+- `created` (Map of String) Information about when and by whom the policy set was created.
+- `description` (String) Description of the policy set.
+- `enabled` (Boolean) Indicates if the policy set is enabled.
+- `last_updated` (Map of String) Information about when and by whom the policy set was last updated.
+- `name` (String) Name of the policy set.
+- `policies` (List of Object) List of policies that comprise the policy set. (see [below for nested schema](#nestedatt--policies))
+- `scope` (List of Object) Scope of the policy set. (see [below for nested schema](#nestedatt--scope))
+- `tags` (List of String) Tags associated with the policy set.
+- `wizard_id` (String) The ID of the policy wizard used to create this policy set.
+- `wizard_parameters` (String) Parameters passed to the wizard while creating the policy set.
+
+
+
+### Nested Schema for `policies`
+
+Read-Only:
+
+- `id` (String)
+- `type` (String)
+
+
+
+### Nested Schema for `scope`
+
+Read-Only:
+
+- `repo_ids` (List of String)
diff --git a/docs/guides/iam_auth_rds_pg.md b/docs/guides/iam_auth_rds_pg.md
index 1b49d7c2..48456df2 100644
--- a/docs/guides/iam_auth_rds_pg.md
+++ b/docs/guides/iam_auth_rds_pg.md
@@ -246,7 +246,7 @@ module "cyral_sidecar" {
source = "cyralinc/sidecar-ec2/aws"
# Use the module version that is compatible with your sidecar.
- version = "~> 5.0"
+ version = "~> 4.3"
sidecar_id = cyral_sidecar.sidecar.id
control_plane = local.control_plane_host
@@ -265,11 +265,11 @@ module "cyral_sidecar" {
load_balancer_scheme = local.sidecar.public_sidecar ? "internet-facing" : "internal"
associate_public_ip_address = local.sidecar.public_sidecar
- dns_hosted_zone_id = local.sidecar.dns_hosted_zone_id
- dns_name = local.sidecar.dns_name
+ sidecar_dns_hosted_zone_id = local.sidecar.dns_hosted_zone_id
+ sidecar_dns_name = local.sidecar.dns_name
}
output "sidecar_load_balancer_dns" {
- value = module.cyral_sidecar.load_balancer_dns
+ value = module.cyral_sidecar.sidecar_load_balancer_dns
}
```
diff --git a/docs/guides/mongodb_cluster_okta_idp.md b/docs/guides/mongodb_cluster_okta_idp.md
index aa7e4d07..9b8b9751 100644
--- a/docs/guides/mongodb_cluster_okta_idp.md
+++ b/docs/guides/mongodb_cluster_okta_idp.md
@@ -98,6 +98,17 @@ locals {
# Name of the CloudWatch log group used to push logs
cloudwatch_log_group_name = "cyral-example-loggroup"
+ # Set the parameters to access the private Cyral container
+ # registry. These parameters can be found in the sidecar
+ # Terraform template downloaded from the UI. Use the
+ # commented values to locate the variables and copy the
+ # values from the downloaded template.
+ container_registry = {
+ name = "" # container_registry
+ username = "" # container_registry_username
+ registry_key = "" # container_registry_key
+ }
+
# Specify the maximum number of nodes you expect this cluster to
# have, taking into consideration future growth. This number must be
# at least equal to the number of nodes currently in your
@@ -243,7 +254,7 @@ module "cyral_sidecar" {
source = "cyralinc/sidecar-ec2/aws"
# Use the module version that is compatible with your sidecar.
- version = "~> 5.0"
+ version = "~> 4.0"
sidecar_version = local.sidecar.sidecar_version
@@ -269,16 +280,22 @@ module "cyral_sidecar" {
load_balancer_scheme = local.sidecar.public_sidecar ? "internet-facing" : "internal"
associate_public_ip_address = local.sidecar.public_sidecar
+ deploy_secrets = true
+ secrets_location = "/cyral/sidecars/${cyral_sidecar.sidecar.id}/secrets"
+
+ container_registry = local.sidecar.container_registry.name
+ container_registry_username = local.sidecar.container_registry.username
+ container_registry_key = local.sidecar.container_registry.registry_key
client_id = cyral_sidecar_credentials.sidecar_credentials.client_id
client_secret = cyral_sidecar_credentials.sidecar_credentials.client_secret
}
output "sidecar_dns" {
- value = module.cyral_sidecar.dns
+ value = module.cyral_sidecar.sidecar_dns
}
output "sidecar_load_balancer_dns" {
- value = module.cyral_sidecar.load_balancer_dns
+ value = module.cyral_sidecar.sidecar_load_balancer_dns
}
```
diff --git a/docs/guides/s3_browser_and_aws_cli.md b/docs/guides/s3_browser_and_aws_cli.md
index 358b19d4..4ab430ce 100644
--- a/docs/guides/s3_browser_and_aws_cli.md
+++ b/docs/guides/s3_browser_and_aws_cli.md
@@ -252,7 +252,7 @@ module "cyral_sidecar" {
source = "cyralinc/sidecar-ec2/aws"
# Use the module version that is compatible with your sidecar.
- version = "~> 5.0"
+ version = "~> 4.3"
sidecar_id = cyral_sidecar.sidecar.id
control_plane = local.control_plane_host
@@ -271,16 +271,17 @@ module "cyral_sidecar" {
load_balancer_scheme = local.sidecar.public_sidecar ? "internet-facing" : "internal"
associate_public_ip_address = local.sidecar.public_sidecar
+
load_balancer_certificate_arn = local.sidecar.load_balancer_certificate_arn
load_balancer_tls_ports = [
local.repos.s3.browser_port
]
- dns_hosted_zone_id = local.sidecar.dns_hosted_zone_id
- dns_name = local.sidecar.dns_name
+ sidecar_dns_hosted_zone_id = local.sidecar.dns_hosted_zone_id
+ sidecar_dns_name = local.sidecar.dns_name
}
output "sidecar_load_balancer_dns" {
- value = module.cyral_sidecar.load_balancer_dns
+ value = module.cyral_sidecar.sidecar_load_balancer_dns
}
```
diff --git a/docs/guides/setup_cp_and_deploy_sidecar.md b/docs/guides/setup_cp_and_deploy_sidecar.md
index 22979867..3b22613c 100644
--- a/docs/guides/setup_cp_and_deploy_sidecar.md
+++ b/docs/guides/setup_cp_and_deploy_sidecar.md
@@ -70,6 +70,17 @@ locals {
# Set the allowed CIDR block for monitoring requests to the
# sidecar
monitoring_inbound_cidr = ["0.0.0.0/0"]
+
+ # Set the parameters to access the private Cyral container
+ # registry. These parameters can be found in the sidecar
+ # Terraform template downloaded from the UI. Use the
+ # commented values to locate the variables and copy the
+ # values from the downloaded template.
+ container_registry = {
+ name = "" # container_registry
+ username = "" # container_registry_username
+ registry_key = "" # container_registry_key
+ }
}
}
@@ -148,7 +159,7 @@ module "cyral_sidecar" {
source = "cyralinc/sidecar-ec2/aws"
# Use the module version that is compatible with your sidecar.
- version = "~> 5.0"
+ version = "~> 4.0"
sidecar_version = local.sidecar.sidecar_version
@@ -170,16 +181,23 @@ module "cyral_sidecar" {
load_balancer_scheme = local.sidecar.public_sidecar ? "internet-facing" : "internal"
associate_public_ip_address = local.sidecar.public_sidecar
+ deploy_secrets = true
+ secrets_location = "/cyral/sidecars/${cyral_sidecar.sidecar.id}/secrets"
+
+ container_registry = local.sidecar.container_registry.name
+ container_registry_username = local.sidecar.container_registry.username
+ container_registry_key = local.sidecar.container_registry.registry_key
+
client_id = cyral_sidecar_credentials.sidecar_credentials.client_id
client_secret = cyral_sidecar_credentials.sidecar_credentials.client_secret
}
output "sidecar_dns" {
- value = module.cyral_sidecar.dns
+ value = module.cyral_sidecar.sidecar_dns
}
output "sidecar_load_balancer_dns" {
- value = module.cyral_sidecar.load_balancer_dns
+ value = module.cyral_sidecar.sidecar_load_balancer_dns
}
```
diff --git a/docs/guides/smart_ports.md b/docs/guides/smart_ports.md
index 213995ac..31f1120a 100644
--- a/docs/guides/smart_ports.md
+++ b/docs/guides/smart_ports.md
@@ -93,6 +93,17 @@ locals {
# Set the allowed CIDR block for monitoring requests to the
# sidecar
monitoring_inbound_cidr = ["0.0.0.0/0"]
+
+ # Set the parameters to access the private Cyral container
+ # registry. These parameters can be found in the sidecar
+ # Terraform template downloaded from the UI. Use the
+ # commented values to locate the variables and copy the
+ # values from the downloaded template.
+ container_registry = {
+ name = "" # container_registry
+ username = "" # container_registry_username
+ registry_key = "" # container_registry_key
+ }
}
}
@@ -305,7 +316,7 @@ module "cyral_sidecar" {
source = "cyralinc/sidecar-ec2/aws"
# Use the module version that is compatible with your sidecar.
- version = "~> 5.0"
+ version = "~> 4.0"
sidecar_version = local.sidecar.sidecar_version
@@ -325,12 +336,19 @@ module "cyral_sidecar" {
load_balancer_scheme = local.sidecar.public_sidecar ? "internet-facing" : "internal"
associate_public_ip_address = local.sidecar.public_sidecar
+ deploy_secrets = true
+ secrets_location = "/cyral/sidecars/${cyral_sidecar.sidecar.id}/secrets"
+
+ container_registry = local.sidecar.container_registry.name
+ container_registry_username = local.sidecar.container_registry.username
+ container_registry_key = local.sidecar.container_registry.registry_key
+
client_id = cyral_sidecar_credentials.sidecar_credentials.client_id
client_secret = cyral_sidecar_credentials.sidecar_credentials.client_secret
}
output "sidecar_load_balancer_dns" {
- value = module.cyral_sidecar.load_balancer_dns
+ value = module.cyral_sidecar.sidecar_load_balancer_dns
}
```
@@ -411,6 +429,17 @@ locals {
# Set the allowed CIDR block for monitoring requests to the
# sidecar
monitoring_inbound_cidr = ["0.0.0.0/0"]
+
+ # Set the parameters to access the private Cyral container
+ # registry. These parameters can be found in the sidecar
+ # Terraform template downloaded from the UI. Use the
+ # commented values to locate the variables and copy the
+ # values from the downloaded template.
+ container_registry = {
+ name = "" # container_registry
+ username = "" # container_registry_username
+ registry_key = "" # container_registry_key
+ }
}
}
@@ -559,7 +588,7 @@ module "cyral_sidecar" {
source = "cyralinc/sidecar-ec2/aws"
# Use the module version that is compatible with your sidecar.
- version = "~> 5.0"
+ version = "~> 4.0"
sidecar_version = local.sidecar.sidecar_version
@@ -579,11 +608,18 @@ module "cyral_sidecar" {
load_balancer_scheme = local.sidecar.public_sidecar ? "internet-facing" : "internal"
associate_public_ip_address = local.sidecar.public_sidecar
+ deploy_secrets = true
+ secrets_location = "/cyral/sidecars/${cyral_sidecar.sidecar.id}/secrets"
+
+ container_registry = local.sidecar.container_registry.name
+ container_registry_username = local.sidecar.container_registry.username
+ container_registry_key = local.sidecar.container_registry.registry_key
+
client_id = cyral_sidecar_credentials.sidecar_credentials.client_id
client_secret = cyral_sidecar_credentials.sidecar_credentials.client_secret
}
output "sidecar_load_balancer_dns" {
- value = module.cyral_sidecar.load_balancer_dns
+ value = module.cyral_sidecar.sidecar_load_balancer_dns
}
```
diff --git a/docs/index.md b/docs/index.md
index 10d38fd6..fd27a27d 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -37,7 +37,7 @@ terraform {
required_providers {
cyral = {
source = "cyralinc/cyral"
- version = "~> 4.0"
+ version = "~> 4.1"
}
}
}
diff --git a/docs/resources/integration_logging.md b/docs/resources/integration_logging.md
index 0546207c..9305690c 100644
--- a/docs/resources/integration_logging.md
+++ b/docs/resources/integration_logging.md
@@ -37,7 +37,7 @@ resource "cyral_sidecar_credentials" "creds" {
module "cyral_sidecar" {
source = "cyralinc/sidecar-ec2/aws"
- version = "~> 5.0"
+ version = "~> 4.0"
sidecar_id = cyral_sidecar.sidecar.id
diff --git a/docs/resources/policy_wizard_v1.md b/docs/resources/policy_wizard_v1.md
new file mode 100644
index 00000000..26163026
--- /dev/null
+++ b/docs/resources/policy_wizard_v1.md
@@ -0,0 +1,80 @@
+# cyral_policy_wizard_v1 (Resource)
+
+This resource allows management of policy sets in the Cyral platform.
+
+-> Import ID syntax is `{policy_set_id}`.
+
+## Example Usage
+
+```terraform
+resource "cyral_repository" "myrepo" {
+ type = "mongodb"
+ name = "myrepo"
+
+ repo_node {
+ name = "node-1"
+ host = "mongodb.cyral.com"
+ port = 27017
+ }
+
+ mongodb_settings {
+ server_type = "standalone"
+ }
+}
+
+resource "cyral_policy_wizard_v1" "repo_lockdown_example" {
+ wizardId = "repo_lockdown"
+ name = "block by default"
+ description = "Block all access to this repository by default, but allow queries not parsed by Cyral"
+ enabled = true
+ tags = ["default block", "fail open"]
+ scope {
+ repo_ids = [cyral_repository.myrepo.id]
+ }
+ wizardParameters = jsonencode({
+ denyByDefault = true
+ })
+ enabled = true
+}
+```
+
+
+
+## Schema
+
+### Required
+
+- `name` (String) Name of the policy set.
+- `wizard_id` (String) The ID of the policy wizard used to create this policy set.
+- `wizard_parameters` (String) Parameters passed to the wizard while creating the policy set.
+
+### Optional
+
+- `description` (String) Description of the policy set.
+- `enabled` (Boolean) Indicates if the policy set is enabled.
+- `scope` (Block List) Scope of the policy set. (see [below for nested schema](#nestedblock--scope))
+- `tags` (List of String) Tags associated with the policy set.
+
+### Read-Only
+
+- `created` (Map of String) Information about when and by whom the policy set was created.
+- `id` (String) Identifier for the policy set.
+- `last_updated` (Map of String) Information about when and by whom the policy set was last updated.
+- `policies` (List of Object) List of policies that comprise the policy set. (see [below for nested schema](#nestedatt--policies))
+
+
+
+### Nested Schema for `scope`
+
+Optional:
+
+- `repo_ids` (List of String) List of repository IDs that are in scope. Empty list means all repositories are in scope.
+
+
+
+### Nested Schema for `policies`
+
+Read-Only:
+
+- `id` (String)
+- `type` (String)
diff --git a/examples/resources/cyral_policy_wizard_v1/resource.tf b/examples/resources/cyral_policy_wizard_v1/resource.tf
new file mode 100644
index 00000000..71564da5
--- /dev/null
+++ b/examples/resources/cyral_policy_wizard_v1/resource.tf
@@ -0,0 +1,29 @@
+resource "cyral_repository" "myrepo" {
+ type = "mongodb"
+ name = "myrepo"
+
+ repo_node {
+ name = "node-1"
+ host = "mongodb.cyral.com"
+ port = 27017
+ }
+
+ mongodb_settings {
+ server_type = "standalone"
+ }
+}
+
+resource "cyral_policy_wizard_v1" "repo_lockdown_example" {
+ wizardId = "repo_lockdown"
+ name = "block by default"
+ description = "Block all access to this repository by default, but allow queries not parsed by Cyral"
+ enabled = true
+ tags = ["default block", "fail open"]
+ scope {
+ repo_ids = [cyral_repository.myrepo.id]
+ }
+ wizardParameters = jsonencode({
+ denyByDefault = true
+ })
+ enabled = true
+}
diff --git a/templates/resources/policy_wizard_v1.md.tmpl b/templates/resources/policy_wizard_v1.md.tmpl
new file mode 100644
index 00000000..65492331
--- /dev/null
+++ b/templates/resources/policy_wizard_v1.md.tmpl
@@ -0,0 +1,11 @@
+# {{ .Name | trimspace }} ({{ .Type | trimspace }})
+
+{{ .Description | trimspace }}
+
+-> Import ID syntax is `{policy_set_id}`.
+
+## Example Usage
+
+{{ tffile "examples/resources/cyral_policy_wizard_v1/resource.tf" }}
+
+{{ .SchemaMarkdown | trimspace }}