ELK Stack — RBAC

6 minute read

Introduction

Role-Based Access Control (RBAC) is the mechanism that determines who can do what in Elasticsearch and Kibana. In a multi-team environment, you need to ensure that developers can only see their application’s logs, security analysts have access to SIEM features, and executives can view dashboards without accidentally modifying alerting rules.

Kibana RBAC works hand-in-hand with Elasticsearch security, combining Kibana privileges (which features and Spaces a user can access) with Elasticsearch privileges (which indices and cluster operations they can perform).


RBAC Architecture

The privilege hierarchy works in layers:

User
  └── Role(s)
        ├── Kibana Privileges
        │     ├── Space: Default → Feature access (read/all)
        │     ├── Space: Platform → Feature access (read/all)
        │     └── Global → Feature access across all spaces
        └── Elasticsearch Privileges
              ├── Cluster privileges (monitor, manage, etc.)
              └── Index privileges (read, write, manage, etc.)
                    ├── Field-level security
                    └── Document-level security

A user can have multiple roles, and the effective privilege is the union of all assigned roles.


Built-in Roles

Elasticsearch and Kibana ship with several built-in roles:

Role Scope Permissions
superuser Full Complete access to all Elasticsearch and Kibana features
kibana_admin Kibana Full access to all Kibana features in all Spaces
kibana_system Internal Used by the Kibana server process — do not assign to users
viewer Read-only Read access to all Kibana features in all Spaces
editor Read-write Read-write access to Kibana features (cannot manage security)
monitoring_user Monitoring Read access to cluster monitoring data
ingest_admin Ingest Manage ingest pipelines and index templates
machine_learning_admin ML Full access to Machine Learning features
machine_learning_user ML Read-only access to ML results

Best practice: Never assign superuser to human users. Create custom roles with the minimum required privileges.


Creating Custom Roles

Via the UI

  1. Open Stack Management → Roles
  2. Click Create role
  3. Enter the role name — e.g., platform-readonly
  4. Configure Elasticsearch privileges (see sections below)
  5. Configure Kibana privileges (see sections below)
  6. Click Create role

Via the API

curl -X PUT "https://localhost:9200/_security/role/platform-readonly" \
  -H "Content-Type: application/json" \
  -u elastic:changeme \
  -d '{
    "cluster": ["monitor"],
    "indices": [
      {
        "names": ["logs-platform-*", "metrics-platform-*"],
        "privileges": ["read", "view_index_metadata"],
        "field_security": {
          "grant": ["*"],
          "except": ["user.email", "user.ip"]
        },
        "query": "{\"match\": {\"environment\": \"production\"}}"
      }
    ],
    "applications": [
      {
        "application": "kibana-.kibana",
        "privileges": ["feature_discover.read", "feature_dashboard.read"],
        "resources": ["space:platform"]
      }
    ]
  }'

Elasticsearch Cluster Privileges

Cluster privileges control cluster-wide operations:

Privilege Description
monitor Read-only access to cluster state, health, and stats
manage Full cluster management (indices, pipelines, snapshots)
manage_security Manage users, roles, and API keys
manage_index_templates Create and delete index templates
manage_ingest_pipelines Create and delete ingest pipelines
manage_ml Full Machine Learning management
manage_pipeline Manage ingest pipelines
transport_client Required for transport client connections
all Unrestricted cluster access

Recommendation: Grant monitor to most read-only roles. Reserve manage for admin roles.


Elasticsearch Index Privileges

Index privileges control access to specific indices:

Privilege Description
read Read documents and search
write Index, update, and delete documents
create_index Create new indices
delete_index Delete indices
manage Full index management (settings, mappings, aliases)
view_index_metadata View index metadata (required for Discover)
monitor Read index stats and status
all Unrestricted index access

Pattern matching: Index names support wildcards — e.g., logs-platform-* grants access to all platform log indices.


Field-Level Security

Field-level security restricts which fields a user can see within documents. This is critical for privacy and compliance.

Grant Specific Fields

{
  "indices": [
    {
      "names": ["logs-*"],
      "privileges": ["read"],
      "field_security": {
        "grant": ["@timestamp", "message", "log.level", "host.name", "service.name"]
      }
    }
  ]
}

The user can only see the five granted fields — all other fields are invisible.

Exclude Specific Fields

{
  "indices": [
    {
      "names": ["logs-*"],
      "privileges": ["read"],
      "field_security": {
        "grant": ["*"],
        "except": ["user.email", "user.ssn", "client.ip"]
      }
    }
  ]
}

The user sees all fields except the excluded PII fields.


Document-Level Security

Document-level security restricts which documents a user can see based on a query filter. The filter is applied transparently — the user never sees documents that don’t match.

Example — Only Production Documents

{
  "indices": [
    {
      "names": ["logs-*"],
      "privileges": ["read"],
      "query": "{\"match\": {\"environment\": \"production\"}}"
    }
  ]
}

Example — Only Documents from User’s Team

{
  "indices": [
    {
      "names": ["logs-*"],
      "privileges": ["read"],
      "query": "{\"match\": {\"team\": \"platform\"}}"
    }
  ]
}

Combining Field-Level and Document-Level Security

You can apply both simultaneously:

{
  "indices": [
    {
      "names": ["logs-*"],
      "privileges": ["read", "view_index_metadata"],
      "field_security": {
        "grant": ["*"],
        "except": ["user.email"]
      },
      "query": "{\"match\": {\"environment\": \"production\"}}"
    }
  ]
}

This role can see production documents only, with the user.email field redacted.


Kibana Privileges

Kibana privileges control access to Kibana features within a Space.

Feature Privileges

Level Description
all Full read-write access to the feature
read Read-only access to the feature
none No access to the feature (hidden from navigation)

Available Features

Feature ID Name
discover Discover
dashboard Dashboards
visualize Visualizations
canvas Canvas
maps Maps
ml Machine Learning
alerting Alerting (Rules)
actions Connectors (Actions)
stackAlerts Stack Alerts
siem Security (SIEM)
dev_tools Dev Tools
advancedSettings Advanced Settings
savedObjectsManagement Saved Objects Management

Setting Kibana Privileges via UI

  1. In the role editor, scroll to Kibana privileges
  2. Click Add Kibana privilege
  3. Select the Space(s) — one specific space, multiple spaces, or all spaces
  4. Set the base privilege:
    • All — read-write access to all features
    • Read — read-only access to all features
    • Custom — set per-feature access
  5. If Custom, toggle each feature individually

Setting Kibana Privileges via API

{
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": [
        "feature_discover.read",
        "feature_dashboard.all",
        "feature_alerting.read"
      ],
      "resources": ["space:platform"]
    },
    {
      "application": "kibana-.kibana",
      "privileges": ["feature_dashboard.read"],
      "resources": ["space:executive"]
    }
  ]
}

Assigning Roles to Users

Via the UI

  1. Open Stack Management → Users
  2. Click Create user or edit an existing user
  3. In the Roles field, add one or more roles
  4. Click Save

Via the API

curl -X POST "https://localhost:9200/_security/user/jane.doe" \
  -H "Content-Type: application/json" \
  -u elastic:changeme \
  -d '{
    "password": "s3cur3Pa$$w0rd",
    "roles": ["platform-readonly", "kibana_admin"],
    "full_name": "Jane Doe",
    "email": "jane.doe@company.com"
  }'

Listing Users

curl -X GET "https://localhost:9200/_security/user" \
  -u elastic:changeme

Spaces + RBAC — Putting It All Together

The combination of Spaces and RBAC gives you a complete multi-tenant setup:

Example — Three-Team Setup

Role 1: platform-team

curl -X PUT "https://localhost:9200/_security/role/platform-team" \
  -H "Content-Type: application/json" \
  -u elastic:changeme \
  -d '{
    "cluster": ["monitor"],
    "indices": [
      {
        "names": ["logs-platform-*", "metrics-platform-*"],
        "privileges": ["read", "view_index_metadata"]
      }
    ],
    "applications": [
      {
        "application": "kibana-.kibana",
        "privileges": [
          "feature_discover.all",
          "feature_dashboard.all",
          "feature_alerting.all",
          "feature_dev_tools.all"
        ],
        "resources": ["space:platform"]
      }
    ]
  }'

Role 2: security-team

curl -X PUT "https://localhost:9200/_security/role/security-team" \
  -H "Content-Type: application/json" \
  -u elastic:changeme \
  -d '{
    "cluster": ["monitor"],
    "indices": [
      {
        "names": ["logs-*", "filebeat-*", ".siem-*"],
        "privileges": ["read", "view_index_metadata"]
      }
    ],
    "applications": [
      {
        "application": "kibana-.kibana",
        "privileges": [
          "feature_discover.all",
          "feature_dashboard.all",
          "feature_maps.all",
          "feature_ml.all",
          "feature_siem.all",
          "feature_alerting.all"
        ],
        "resources": ["space:security"]
      }
    ]
  }'

Role 3: executive-viewer

curl -X PUT "https://localhost:9200/_security/role/executive-viewer" \
  -H "Content-Type: application/json" \
  -u elastic:changeme \
  -d '{
    "cluster": [],
    "indices": [
      {
        "names": ["metrics-business-*"],
        "privileges": ["read", "view_index_metadata"]
      }
    ],
    "applications": [
      {
        "application": "kibana-.kibana",
        "privileges": [
          "feature_dashboard.read",
          "feature_canvas.read"
        ],
        "resources": ["space:executive"]
      }
    ]
  }'

Each team is isolated — platform engineers cannot see security dashboards, security analysts cannot access Dev Tools, and executives have a clean read-only Canvas experience.


Quick Reference

Task Method
Create role (UI) Stack Management → Roles → Create role
Create role (API) PUT /_security/role/<name>
Create user (API) POST /_security/user/<username>
Assign roles to user User editor → Roles field
Field-level security Role → Index privileges → field_security
Document-level security Role → Index privileges → query
Kibana feature privileges Role → Kibana privileges → Custom → per-feature
Space-scoped privileges "resources": ["space:<space-id>"]
List all roles GET /_security/role
List all users GET /_security/user
Delete a role DELETE /_security/role/<name>

Next: Practice Exercises →