diff --git a/CHANGELOG.md b/CHANGELOG.md index a9c805c40..217bf420f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Added - New resource `elasticstack_elasticsearch_logstash_pipeline` to manage Logstash pipelines ([Centralized Pipeline Management](https://www.elastic.co/guide/en/logstash/current/logstash-centralized-pipeline-management.html)) ([#151](https://github.com/elastic/terraform-provider-elasticstack/pull/151)) +- Add `elasticstack_elasticsearch_security_role` data source ([#177](https://github.com/elastic/terraform-provider-elasticstack/pull/177)) - Add `elasticstack_elasticsearch_security_role_mapping` data source ([#178](https://github.com/elastic/terraform-provider-elasticstack/pull/178)) ### Fixed diff --git a/docs/data-sources/elasticsearch_security_role.md b/docs/data-sources/elasticsearch_security_role.md new file mode 100644 index 000000000..8f747c94e --- /dev/null +++ b/docs/data-sources/elasticsearch_security_role.md @@ -0,0 +1,91 @@ +--- +subcategory: "Security" +layout: "" +page_title: "Elasticstack: elasticstack_elasticsearch_security_role Data Source" +description: |- + Retrieves roles in the native realm. +--- + +# Data Source: elasticstack_elasticsearch_security_role + +Use this data source to get information about an existing Elasticsearch role. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-role.html + +## Example Usage + +```terraform +provider "elasticstack" { + elasticsearch {} +} + +data "elasticstack_elasticsearch_security_role" "role" { + name = "testrole" +} + +output "role" { + value = data.elasticstack_elasticsearch_security_role.role.name +} +``` + + +## Schema + +### Required + +- `name` (String) The name of the role. + +### Optional + +- `elasticsearch_connection` (Block List, Max: 1) Used to establish connection to Elasticsearch server. Overrides environment variables if present. (see [below for nested schema](#nestedblock--elasticsearch_connection)) +- `run_as` (Set of String) A list of users that the owners of this role can impersonate. + +### Read-Only + +- `applications` (Set of Object) A list of application privilege entries. (see [below for nested schema](#nestedatt--applications)) +- `cluster` (Set of String) A list of cluster privileges. These privileges define the cluster level actions that users with this role are able to execute. +- `global` (String) An object defining global privileges. +- `id` (String) Internal identifier of the resource +- `indices` (Set of Object) A list of indices permissions entries. (see [below for nested schema](#nestedatt--indices)) +- `metadata` (String) Optional meta-data. + + +### Nested Schema for `elasticsearch_connection` + +Optional: + +- `api_key` (String, Sensitive) API Key to use for authentication to Elasticsearch +- `ca_data` (String) PEM-encoded custom Certificate Authority certificate +- `ca_file` (String) Path to a custom Certificate Authority certificate +- `endpoints` (List of String, Sensitive) A list of endpoints the Terraform provider will point to. They must include the http(s) schema and port number. +- `insecure` (Boolean) Disable TLS certificate validation +- `password` (String, Sensitive) A password to use for API authentication to Elasticsearch. +- `username` (String) A username to use for API authentication to Elasticsearch. + + + +### Nested Schema for `applications` + +Read-Only: + +- `application` (String) +- `privileges` (Set of String) +- `resources` (Set of String) + + + +### Nested Schema for `indices` + +Read-Only: + +- `allow_restricted_indices` (Boolean) +- `field_security` (List of Object) (see [below for nested schema](#nestedobjatt--indices--field_security)) +- `names` (Set of String) +- `privileges` (Set of String) +- `query` (String) + + +### Nested Schema for `indices.field_security` + +Read-Only: + +- `except` (Set of String) +- `grant` (Set of String) diff --git a/examples/data-sources/elasticstack_elasticsearch_security_role/data-source.tf b/examples/data-sources/elasticstack_elasticsearch_security_role/data-source.tf new file mode 100644 index 000000000..2758a0de0 --- /dev/null +++ b/examples/data-sources/elasticstack_elasticsearch_security_role/data-source.tf @@ -0,0 +1,11 @@ +provider "elasticstack" { + elasticsearch {} +} + +data "elasticstack_elasticsearch_security_role" "role" { + name = "testrole" +} + +output "role" { + value = data.elasticstack_elasticsearch_security_role.role.name +} diff --git a/internal/elasticsearch/security/role_data_source.go b/internal/elasticsearch/security/role_data_source.go new file mode 100644 index 000000000..ab2d178cd --- /dev/null +++ b/internal/elasticsearch/security/role_data_source.go @@ -0,0 +1,165 @@ +package security + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceRole() *schema.Resource { + roleSchema := map[string]*schema.Schema{ + "id": { + Description: "Internal identifier of the resource", + Type: schema.TypeString, + Computed: true, + }, + "name": { + Description: "The name of the role.", + Type: schema.TypeString, + Required: true, + }, + "applications": { + Description: "A list of application privilege entries.", + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "application": { + Description: "The name of the application to which this entry applies.", + Type: schema.TypeString, + Computed: true, + }, + "privileges": { + Description: "A list of strings, where each element is the name of an application privilege or action.", + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Computed: true, + }, + "resources": { + Description: "A list resources to which the privileges are applied.", + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Computed: true, + }, + }, + }, + }, + "global": { + Description: "An object defining global privileges.", + Type: schema.TypeString, + Computed: true, + }, + "cluster": { + Description: "A list of cluster privileges. These privileges define the cluster level actions that users with this role are able to execute.", + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Computed: true, + }, + "indices": { + Description: "A list of indices permissions entries.", + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "field_security": { + Description: "The document fields that the owners of the role have read access to.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "grant": { + Description: "List of the fields to grant the access to.", + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "except": { + Description: "List of the fields to which the grants will not be applied.", + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "names": { + Description: "A list of indices (or index name patterns) to which the permissions in this entry apply.", + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "privileges": { + Description: "The index level privileges that the owners of the role have on the specified indices.", + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "query": { + Description: "A search query that defines the documents the owners of the role have read access to.", + Type: schema.TypeString, + Computed: true, + }, + "allow_restricted_indices": { + Description: "Include matching restricted indices in names parameter. Usage is strongly discouraged as it can grant unrestricted operations on critical data, make the entire system unstable or leak sensitive information.", + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + "metadata": { + Description: "Optional meta-data.", + Type: schema.TypeString, + Computed: true, + }, + "run_as": { + Description: "A list of users that the owners of this role can impersonate.", + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + } + + utils.AddConnectionSchema(roleSchema) + + return &schema.Resource{ + Description: "Retrieves roles in the native realm. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-role.html", + ReadContext: dataSourceSecurityRoleRead, + Schema: roleSchema, + } +} + +func dataSourceSecurityRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := clients.NewApiClient(d, meta) + if err != nil { + return diag.FromErr(err) + } + + roleId := d.Get("name").(string) + id, diags := client.ID(ctx, roleId) + if diags.HasError() { + return diags + } + d.SetId(id.String()) + + return resourceSecurityRoleRead(ctx, d, meta) +} diff --git a/internal/elasticsearch/security/role_data_source_test.go b/internal/elasticsearch/security/role_data_source_test.go new file mode 100644 index 000000000..12be57a6b --- /dev/null +++ b/internal/elasticsearch/security/role_data_source_test.go @@ -0,0 +1,66 @@ +package security_test + +import ( + "testing" + + "github.com/elastic/terraform-provider-elasticstack/internal/acctest" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceSecurityRole(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceSecurityRole, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.elasticstack_elasticsearch_security_role.test", "name", "data_source_test"), + resource.TestCheckTypeSetElemAttr("data.elasticstack_elasticsearch_security_role.test", "cluster.*", "all"), + utils.TestCheckResourceListAttr("data.elasticstack_elasticsearch_security_role.test", "indices.0.names", []string{"index1", "index2"}), + resource.TestCheckTypeSetElemAttr("data.elasticstack_elasticsearch_security_role.test", "indices.0.privileges.*", "all"), + resource.TestCheckResourceAttr("data.elasticstack_elasticsearch_security_role.test", "indices.0.allow_restricted_indices", "true"), + resource.TestCheckResourceAttr("data.elasticstack_elasticsearch_security_role.test", "applications.0.application", "myapp"), + utils.TestCheckResourceListAttr("data.elasticstack_elasticsearch_security_role.test", "applications.0.privileges", []string{"admin", "read"}), + resource.TestCheckTypeSetElemAttr("data.elasticstack_elasticsearch_security_role.test", "applications.0.resources.*", "*"), + resource.TestCheckTypeSetElemAttr("data.elasticstack_elasticsearch_security_role.test", "run_as.*", "other_user"), + resource.TestCheckResourceAttr("data.elasticstack_elasticsearch_security_role.test", "metadata", `{"version":1}`), + ), + }, + }, + }) +} + +const testAccDataSourceSecurityRole = ` +provider "elasticstack" { + elasticsearch {} +} + +resource "elasticstack_elasticsearch_security_role" "test" { + name = "data_source_test" + cluster = ["all"] + + indices { + names = ["index1", "index2"] + privileges = ["all"] + allow_restricted_indices = true + } + + applications { + application = "myapp" + privileges = ["admin", "read"] + resources = ["*"] + } + + run_as = ["other_user"] + + metadata = jsonencode({ + version = 1 + }) +} + +data "elasticstack_elasticsearch_security_role" "test" { + name = elasticstack_elasticsearch_security_role.test.name +} +` diff --git a/internal/elasticsearch/security/role_mapping_data_source_test.go b/internal/elasticsearch/security/role_mapping_data_source_test.go index 63e52616b..1aaa65e09 100644 --- a/internal/elasticsearch/security/role_mapping_data_source_test.go +++ b/internal/elasticsearch/security/role_mapping_data_source_test.go @@ -14,7 +14,7 @@ func TestAccDataSourceSecurityRoleMapping(t *testing.T) { ProviderFactories: acctest.Providers, Steps: []resource.TestStep{ { - Config: testAccDataSourceSecurityRole, + Config: testAccDataSourceSecurityRoleMapping, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.elasticstack_elasticsearch_security_role_mapping.test", "name", "data_source_test"), resource.TestCheckResourceAttr("data.elasticstack_elasticsearch_security_role_mapping.test", "enabled", "true"), @@ -27,7 +27,7 @@ func TestAccDataSourceSecurityRoleMapping(t *testing.T) { }) } -const testAccDataSourceSecurityRole = ` +const testAccDataSourceSecurityRoleMapping = ` provider "elasticstack" { elasticsearch {} } diff --git a/provider/provider.go b/provider/provider.go index 3e13e5cc0..8baee6d4a 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -118,6 +118,7 @@ func New(version string) func() *schema.Provider { "elasticstack_elasticsearch_ingest_processor_urldecode": ingest.DataSourceProcessorUrldecode(), "elasticstack_elasticsearch_ingest_processor_uri_parts": ingest.DataSourceProcessorUriParts(), "elasticstack_elasticsearch_ingest_processor_user_agent": ingest.DataSourceProcessorUserAgent(), + "elasticstack_elasticsearch_security_role": security.DataSourceRole(), "elasticstack_elasticsearch_security_role_mapping": security.DataSourceRoleMapping(), "elasticstack_elasticsearch_security_user": security.DataSourceUser(), "elasticstack_elasticsearch_snapshot_repository": cluster.DataSourceSnapshotRespository(), diff --git a/templates/data-sources/elasticsearch_security_role.md.tmpl b/templates/data-sources/elasticsearch_security_role.md.tmpl new file mode 100644 index 000000000..73d4a6cee --- /dev/null +++ b/templates/data-sources/elasticsearch_security_role.md.tmpl @@ -0,0 +1,17 @@ +--- +subcategory: "Security" +layout: "" +page_title: "Elasticstack: elasticstack_elasticsearch_security_role Data Source" +description: |- + Retrieves roles in the native realm. +--- + +# Data Source: elasticstack_elasticsearch_security_role + +Use this data source to get information about an existing Elasticsearch role. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-role.html + +## Example Usage + +{{ tffile "examples/data-sources/elasticstack_elasticsearch_security_role/data-source.tf" }} + +{{ .SchemaMarkdown | trimspace }}