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