Nếu bạn từng làm sysadmin Linux, mô hình RBAC của Elastic sẽ không xa lạ. Nó giống cách Linux dùng user, group, file permission, nhưng thay vì chmod 644 file.txt thì bạn ghép user vào role, gắn role vào index pattern và feature của Kibana. Cụm thực sự khó là biết privilege nào mở quyền gì, ai đứng đâu trong sơ đồ, và khi nào không nên cấp superuser cho service account.

Đây là bài 12 trong series Kibana từ A đến Z. Sau bài này bạn sẽ làm được:

  • Vẽ được mental model: user, role, privilege, realm
  • Tạo role chỉ đọc một index pattern và xem một space duy nhất
  • Map LDAP/OIDC user thành role bằng role mapping API
  • Tránh ba pitfall hay gặp với feature privileges và space privileges

Phần 1: Mental model trong 60 giây

Có ba lớp khái niệm cần phân biệt:

+-----------------------------+
|  User (native / LDAP / OIDC)|
+-----------+-----------------+
            | gắn n role
            v
+-----------------------------+
|  Role (collection privileges)|
+-----------+-----------------+
            | chứa
            v
+--------+--------+--------+
| Cluster| Index  | Kibana |
| priv   | priv   | priv   |
+--------+--------+--------+
  • User sống ở realm. Realm là nguồn xác thực: native (lưu trong ES), ldap, active_directory, oidc, saml, kerberos, pki. Một cluster có thể bật nhiều realm.
  • Role là bộ ba privilege: cluster (cấp cluster), indices (cấp index pattern), Kibana (cấp feature trong Kibana, có scope theo space).
  • Privilege là verb cụ thể: read, write, manage, monitor, all. Có loại built-in (read, all…) và loại granular (read_cross_cluster, view_index_metadata, create_doc…).

Quy tắc gộp: nếu user có nhiều role, quyền là union. Không có deny rule. Muốn “trừ quyền” thì gỡ bớt role.

Phần 2: Built-in role và khi nào KHÔNG dùng

Kibana 8.x ship sẵn một loạt role. Hai cái phổ biến nhất:

RoleQuyềnDùng cho
superuserToàn quyền cluster + KibanaChỉ DBA / platform team
kibana_adminTất cả feature Kibana, không có quyền clusterTech lead, không phải dev thường
viewerRead-only trên tất cả index + KibanaStakeholder, manager
editorEdit dashboard/visualization, không sửa securityDev backend
monitoring_userĐọc stack monitoringSRE on-call
reporting_userTạo PDF reportDev tạo weekly report

Pitfall điển hình tôi từng gặp ở một team: dev cần build dashboard, lead cấp superuser cho gọn. Hệ quả là API key dev tạo cũng kế thừa superuser. Khi key đó leak ra một public repo, attacker dùng nó delete app-logs-*. Bài học: không cấp superuser cho ai dùng hàng ngày. Dev chỉ cần editor plus một role read trên index.

Phần 3: Tạo role custom đầu tiên

Mục tiêu: role backend_dev_logs_reader cho dev backend, được:

  • Đọc index pattern app-logs-*nginx-*
  • Xem feature Discover, Dashboard, Lens trong space dev
  • KHÔNG xem được Stack Management
  • KHÔNG xoá index, không tạo data view ngoài space dev

Cách 1: qua GUI

Vào Stack Management plus Security plus Roles plus Create role.

  1. Đặt tên: backend_dev_logs_reader.
  2. Cluster privileges: bỏ trống. Dev không cần quyền cluster-level.
  3. Index privileges: thêm 1 block.
    • Indices: app-logs-*, nginx-*
    • Privileges: read, view_index_metadata
  4. Kibana privileges: click Add Kibana privilege.
    • Spaces: chọn dev (chỉ 1 space).
    • Customize: tick Discover (Read), Dashboard (Read), Visualize Library (Read).
    • Bỏ qua Stack Management, Dev Tools, Fleet.
  5. Save.

Kết quả: dev login vào space dev thấy đúng 3 menu Discover, Dashboard, Visualize. Mở space khác sẽ thấy báo No spaces available.

Cách 2: qua REST API

Phù hợp cho CI/CD và Terraform.

curl -s -u "$ES_USER:$ES_PASS" \
  -H "Content-Type: application/json" \
  -X PUT "$ES_URL/_security/role/backend_dev_logs_reader" \
  -d '{
    "cluster": [],
    "indices": [
      {
        "names": ["app-logs-*", "nginx-*"],
        "privileges": ["read", "view_index_metadata"]
      }
    ],
    "applications": [
      {
        "application": "kibana-.kibana",
        "privileges": ["feature_discover.read", "feature_dashboard.read", "feature_visualize.read"],
        "resources": ["space:dev"]
      }
    ]
  }'

Lưu ý cú pháp:

  • application luôn là kibana-.kibana (mặc định, trừ khi bạn đổi kibana.index).
  • resources dùng prefix space:. Muốn áp tất cả space ghi ["*"].
  • Feature privilege ghi dạng feature_<feature_id>.<level>. List feature id qua GET /_security/privilege/kibana-.kibana.

Phần 4: Cluster privileges phổ biến

Khi nào dev cần cluster privilege? Thường không. Nhưng nếu phải, đây là bảng tra:

PrivilegeCho phépKhi nào cấp
monitorXem stats cluster, index, nodeTool monitoring read-only
monitor_mlXem ML jobsDev xem anomaly detection
manage_index_templatesTạo/sửa index templatePlatform team
manage_ilmSửa ILM policyDevOps quản lý lifecycle
read_ccrCross-cluster replication readSetup DR cluster
manage_securityTạo user, roleKHÔNG cấp cho dev
allEverythingKHÔNG cấp ngoài DBA

Anti-pattern: cấp manage cluster cho service account của log shipper. Filebeat chỉ cần monitor plus index create_doc plus auto_configure trên index pattern của nó. Cấp manage mở rộng đến tận index template, policy, snapshot, hỏng một cái là full cluster lung lay.

Phần 5: Index privileges granular

Block indices chấp nhận nhiều record. Mỗi record gồm:

{
  "names": ["app-logs-*"],
  "privileges": ["read", "view_index_metadata"],
  "field_security": {
    "grant": ["@timestamp", "Level", "Properties.*"],
    "except": ["Properties.UserToken"]
  },
  "query": "{\"term\":{\"Properties.TenantId\":\"tenant-a\"}}"
}
  • field_security chính là Field-Level Security (FLS). Bài 14 sẽ đi sâu.
  • query là Document-Level Security (DLS), cũng bài 14.
  • Common index privileges:
PrivilegeVerbGhi chú
readSearch, get, mgetĐủ cho Discover/Dashboard
view_index_metadataHiển thị mappingCần để Kibana tạo data view
create_docIndex document mới, không updateCho log shipper
indexIndex plus updateCho ingest pipeline phức tạp
deleteDelete by idĐừng cấp cho user thường
manageMapping, settings, aliasPlatform team
allTất cảDBA only

Mẹo: chia role *_reader*_writer riêng. Service tài khoản ingest chỉ có writer, dashboard tool chỉ có reader. Khi bị compromise sẽ giới hạn bán kính.

Phần 6: Kibana feature privileges

Đây là phần dev hay nhầm nhất. Mỗi feature có 3 mức:

  • all: tạo, sửa, xoá object của feature đó
  • read: chỉ đọc
  • none (mặc định): không thấy menu

Một số feature có sub-feature, ví dụ Dashboard:

Sub-featureÝ nghĩa
dashboard.url_createTạo short URL chia sẻ
dashboard.show_write_controlsHiện nút Edit
dashboard.create_short_urlKhác cái trên, dùng cho permalink

Cấp dashboard.read plus dashboard.url_create cho user xem nội bộ và share link, nhưng không edit. Đây là pattern an toàn cho “executive dashboard”.

Pitfall thường gặp: dev cấp feature_dev_tools.all cho team backend. Dev Tools cho phép gọi mọi REST API của ES với danh tính user hiện tại. Nếu user còn có quyền manage trên một index thì có thể DELETE app-logs-* từ Dev Tools. Khoá Dev Tools ở space production, chỉ mở ở space sandbox.

Phần 7: Realm và authentication

Bật nhiều realm trong elasticsearch.yml:

xpack.security.authc.realms:
  native:
    native1:
      order: 0
  ldap:
    corp_ldap:
      order: 1
      url: "ldaps://ldap.example.internal:636"
      bind_dn: "cn=es-bind,ou=service,dc=example,dc=internal"
      user_search:
        base_dn: "ou=people,dc=example,dc=internal"
        filter: "(uid={0})"
      group_search:
        base_dn: "ou=groups,dc=example,dc=internal"
  oidc:
    azure_ad:
      order: 2
      rp.client_id: "<azure-app-id>"
      rp.redirect_uri: "https://kibana.example.com/api/security/oidc/callback"
      op.issuer: "https://login.microsoftonline.com/<tenant>/v2.0"
      op.authorization_endpoint: "https://login.microsoftonline.com/<tenant>/oauth2/v2.0/authorize"
      op.token_endpoint: "https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token"
      op.jwkset_path: "https://login.microsoftonline.com/<tenant>/discovery/v2.0/keys"
      claims.principal: "preferred_username"
      claims.groups: "groups"

order quyết định thứ tự thử realm. Native trước để admin local còn login được khi LDAP down.

Role mapping cho external realm

User LDAP/OIDC không nằm trong ES, nên cần map từ thuộc tính của họ sang role nội bộ.

curl -s -u "$ES_USER:$ES_PASS" \
  -H "Content-Type: application/json" \
  -X PUT "$ES_URL/_security/role_mapping/oidc_backend_devs" \
  -d '{
    "roles": ["backend_dev_logs_reader", "kibana_user"],
    "enabled": true,
    "rules": {
      "all": [
        { "field": { "realm.name": "azure_ad" } },
        { "field": { "groups": "ad-group-backend-devs" } }
      ]
    }
  }'

Quy tắc: tránh tạo role mapping kiểu wildcard "username": "*". Mapping luôn nên dựa trên group/role bên IdP để khi user rời team, IdP gỡ group là quyền tự rút.

Pitfall: realm chain dài và login chậm

Một team tôi từng làm cùng bật LDAP plus AD plus PKI plus native trên một cluster. Mỗi login Kibana mất 4-6 giây vì thử lần lượt. Fix: đặt LDAP order: 0 (vì 95% user qua LDAP), giảm timeout xuống 2s, đóng PKI nếu không dùng. Login về 800ms.

Phần 8: API key kế thừa role của user tạo

Khi user A tạo API key không khai báo role_descriptors, key được quyền bằng giao của:

  • Quyền hiện tại của user A
  • Role descriptor (nếu khai báo)

Hậu quả: nếu A là superuser và tạo key không scope, key đó là superuser cho tới khi expire. Đây là nguồn của hầu hết incident “key leak xoá cluster”.

Best practice:

POST /_security/api_key
{
  "name": "filebeat-staging",
  "expiration": "30d",
  "role_descriptors": {
    "filebeat_writer": {
      "cluster": ["monitor"],
      "indices": [
        {
          "names": ["filebeat-staging-*"],
          "privileges": ["create_doc", "auto_configure"]
        }
      ]
    }
  },
  "metadata": {
    "owner": "platform-team",
    "purpose": "filebeat ingest"
  }
}

Set expiration và role_descriptors luôn luôn. Audit thông qua GET /_security/api_key?active_only=true.

Phần 9: Debug “tại sao tôi không thấy menu X”

Quy trình 3 bước:

  1. Mở Stack Management plus Security plus Users plus click chính user của mình. Coi role nào được gán.
  2. Mỗi role: mở chi tiết, xem block Kibana privileges. Có feature đó với mức read trở lên không?
  3. Có chọn đúng space chứa privilege đó không? Nếu role chỉ mở feature ở space dev mà bạn đang ở space default, menu sẽ ẩn.

API debug nhanh:

curl -s -u "$ES_USER:$ES_PASS" \
  -H "Content-Type: application/json" \
  -X POST "$ES_URL/_security/user/_has_privileges" \
  -d '{
    "cluster": ["monitor"],
    "index": [
      {
        "names": ["app-logs-*"],
        "privileges": ["read"]
      }
    ]
  }'

Response trả về has_all_requested: true/false plus chi tiết từng privilege. Đây là cách nhanh nhất để chứng minh “tôi không có quyền X” với DBA.

Cheatsheet

ViệcCách làm
Tạo rolePUT /_security/role/<name> hoặc Stack Management plus Roles
Gắn role cho user nativePUT /_security/user/<u> field roles
Map LDAP/OIDC groupPUT /_security/role_mapping/<name>
Check user có quyền X chưaPOST /_security/user/_has_privileges
List built-in roleGET /_security/role
List feature idGET /_security/privilege/kibana-.kibana
Tạo API key có scopePOST /_security/api_key với role_descriptors
Audit key đang sốngGET /_security/api_key?active_only=true
Revoke keyDELETE /_security/api_key với ids hoặc name

Lời kết

RBAC trong Elastic không phức tạp nếu bạn nhớ 4 từ: realm, user, role, privilege. Khó là kỷ luật: không cấp superuser, không cấp manage_security, không tạo API key thiếu scope. Mỗi quyền thừa là một bán kính nổ thêm khi có incident.

Bài 13 sẽ đi vào Spaces: cách dùng spaces để tách dev, staging, prod và team con trên cùng một cluster mà không phải dựng 3 instance Kibana riêng. Đây là nền tảng để áp dụng RBAC theo chiều ngang. Sau đó bài 14 quay lại security với DLS và FLS để khoá data theo tenant.