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 }}