ELK Stack — RBAC and Roles
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_systemandbeats_systemusers 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.