ELK Stack — RBAC and Roles

4 minute read

RBAC and Roles

Role-Based Access Control (RBAC) is the cornerstone of Elasticsearch authorization. Every authenticated user is assigned one or more roles, and each role defines a set of privileges at the cluster and index level.

RBAC answers the question: “This user is who they say they are — but what are they allowed to do?”


Built-in Users

Elasticsearch ships with several reserved users:

User Purpose
elastic Superuser — full access to the cluster
kibana_system Used internally by Kibana to communicate with Elasticsearch
logstash_system Used by Logstash for monitoring (not data ingestion)
beats_system Used by Beats for monitoring
apm_system Used by APM Server for monitoring
remote_monitoring_user Used for cross-cluster monitoring

Important: The logstash_system and beats_system users are for monitoring only. Create dedicated users with appropriate roles for data ingestion.


Built-in Roles

Role Privileges
superuser Full access to the entire cluster
kibana_admin Full access to all Kibana features
editor Read/write access to all Kibana apps and data
viewer Read-only access to all Kibana apps and data
ingest_admin Manage ingest pipelines and index templates
monitoring_user Read-only access to monitoring data
transform_admin Manage transforms
machine_learning_admin Manage machine learning jobs
watcher_admin Manage watches (alerting)
rollup_admin Manage rollup jobs

List all roles:

curl -k -u elastic:password https://localhost:9200/_security/role | jq 'keys'

Creating Custom Roles

Custom roles let you tailor permissions for your teams.

Example: Log Viewer Role

A role that can only read logs indices:

curl -k -u elastic:password -X POST "https://localhost:9200/_security/role/log_viewer" \
  -H "Content-Type: application/json" -d'
{
  "cluster": [],
  "indices": [
    {
      "names": ["logs-*", "filebeat-*", "logstash-*"],
      "privileges": ["read", "view_index_metadata"]
    }
  ],
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": ["feature_discover.read", "feature_dashboard.read"],
      "resources": ["*"]
    }
  ]
}'

Example: Application Team Role

A role for a team that owns specific application indices:

curl -k -u elastic:password -X POST "https://localhost:9200/_security/role/app_team_payments" \
  -H "Content-Type: application/json" -d'
{
  "cluster": ["monitor"],
  "indices": [
    {
      "names": ["logs-payments-*", "metrics-payments-*"],
      "privileges": ["read", "write", "create_index", "view_index_metadata"]
    }
  ],
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": ["feature_discover.all", "feature_dashboard.all", "feature_visualize.all"],
      "resources": ["space:payments"]
    }
  ]
}'

Cluster Privileges

Cluster privileges control operations that affect the entire cluster:

Privilege Description
all Full cluster access
monitor Read-only cluster state, stats, health
manage Manage cluster settings, snapshots, templates
manage_security Manage users, roles, API keys
manage_index_templates Create and delete index templates
manage_ingest_pipelines Create and delete ingest pipelines
manage_ilm Manage index lifecycle policies
manage_ml Manage machine learning jobs
manage_pipeline Manage ingest pipelines
transport_client Connect as a transport client

Index Privileges

Index privileges control what a user can do with specific indices:

Privilege Description
all Full access to the index
read Read documents and search
write Index, update, and delete documents
create_index Create new indices matching the pattern
delete_index Delete indices
manage Manage index settings, mappings, aliases
view_index_metadata View index metadata (required for Kibana)
create Index new documents (no update/delete)
index Index and update documents
delete Delete documents
auto_configure Auto-configure data streams and indices

Field-Level Security (FLS)

FLS restricts which fields a user can see within a document. This is critical for protecting sensitive data like PII.

Example: Hide Sensitive Fields

curl -k -u elastic:password -X POST "https://localhost:9200/_security/role/analyst_no_pii" \
  -H "Content-Type: application/json" -d'
{
  "indices": [
    {
      "names": ["customer-data-*"],
      "privileges": ["read"],
      "field_security": {
        "grant": ["*"],
        "except": ["ssn", "credit_card", "date_of_birth", "email"]
      }
    }
  ]
}'

A user with this role can search customer-data-* but will never see the ssn, credit_card, date_of_birth, or email fields.

Example: Grant Only Specific Fields

curl -k -u elastic:password -X POST "https://localhost:9200/_security/role/metrics_viewer" \
  -H "Content-Type: application/json" -d'
{
  "indices": [
    {
      "names": ["metrics-*"],
      "privileges": ["read"],
      "field_security": {
        "grant": ["@timestamp", "host.name", "system.cpu.*", "system.memory.*"]
      }
    }
  ]
}'

Document-Level Security (DLS)

DLS restricts which documents a user can see. Only documents matching the query are returned.

Example: Team-Scoped Access

curl -k -u elastic:password -X POST "https://localhost:9200/_security/role/team_eu_logs" \
  -H "Content-Type: application/json" -d'
{
  "indices": [
    {
      "names": ["logs-*"],
      "privileges": ["read"],
      "query": {
        "match": {
          "geo.region": "eu"
        }
      }
    }
  ]
}'

Users with this role only see log documents where geo.region is eu.

Example: Combining FLS and DLS

curl -k -u elastic:password -X POST "https://localhost:9200/_security/role/eu_analyst" \
  -H "Content-Type: application/json" -d'
{
  "indices": [
    {
      "names": ["customer-data-*"],
      "privileges": ["read"],
      "field_security": {
        "grant": ["*"],
        "except": ["ssn", "credit_card"]
      },
      "query": {
        "match": {
          "country": "Germany"
        }
      }
    }
  ]
}'

This role sees only German customer records and cannot access the ssn or credit_card fields.


Role Mappings

Role mappings connect external identities (from LDAP, SAML, OIDC) to Elasticsearch roles:

curl -k -u elastic:password -X POST "https://localhost:9200/_security/role_mapping/ldap_admins" \
  -H "Content-Type: application/json" -d'
{
  "enabled": true,
  "roles": ["superuser"],
  "rules": {
    "field": {
      "groups": "cn=es-admins,ou=groups,dc=example,dc=com"
    }
  },
  "metadata": {
    "version": 1
  }
}'

Map multiple groups:

curl -k -u elastic:password -X POST "https://localhost:9200/_security/role_mapping/ldap_viewers" \
  -H "Content-Type: application/json" -d'
{
  "enabled": true,
  "roles": ["viewer"],
  "rules": {
    "any": [
      { "field": { "groups": "cn=developers,ou=groups,dc=example,dc=com" } },
      { "field": { "groups": "cn=analysts,ou=groups,dc=example,dc=com" } }
    ]
  }
}'

User Management API

Create a User

curl -k -u elastic:password -X POST "https://localhost:9200/_security/user/jane_smith" \
  -H "Content-Type: application/json" -d'
{
  "password": "SecurePassword123!",
  "roles": ["log_viewer", "monitoring_user"],
  "full_name": "Jane Smith",
  "email": "jane.smith@example.com",
  "metadata": {
    "department": "Engineering",
    "team": "Platform"
  }
}'

List All Users

curl -k -u elastic:password https://localhost:9200/_security/user | jq 'keys'

Update a User’s Roles

curl -k -u elastic:password -X PUT "https://localhost:9200/_security/user/jane_smith" \
  -H "Content-Type: application/json" -d'
{
  "roles": ["log_viewer", "monitoring_user", "app_team_payments"],
  "full_name": "Jane Smith",
  "email": "jane.smith@example.com"
}'

Disable a User

curl -k -u elastic:password -X PUT "https://localhost:9200/_security/user/jane_smith/_disable"

Delete a User

curl -k -u elastic:password -X DELETE "https://localhost:9200/_security/user/jane_smith"

Quick Reference

Task API / Command
List roles GET /_security/role
Create role POST /_security/role/<name>
Delete role DELETE /_security/role/<name>
Create user POST /_security/user/<name>
Disable user PUT /_security/user/<name>/_disable
Enable user PUT /_security/user/<name>/_enable
Delete user DELETE /_security/user/<name>
Create role mapping POST /_security/role_mapping/<name>
Field-level security "field_security": { "grant": [...], "except": [...] }
Document-level security "query": { "match": { ... } }

Next: API Keys — programmatic authentication without passwords.