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:
| Role | Quyền | Dùng cho |
|---|---|---|
superuser | Toàn quyền cluster + Kibana | Chỉ DBA / platform team |
kibana_admin | Tất cả feature Kibana, không có quyền cluster | Tech lead, không phải dev thường |
viewer | Read-only trên tất cả index + Kibana | Stakeholder, manager |
editor | Edit dashboard/visualization, không sửa security | Dev backend |
monitoring_user | Đọc stack monitoring | SRE on-call |
reporting_user | Tạo PDF report | Dev 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-*và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.
- Đặt tên:
backend_dev_logs_reader. - Cluster privileges: bỏ trống. Dev không cần quyền cluster-level.
- Index privileges: thêm 1 block.
- Indices:
app-logs-*,nginx-* - Privileges:
read,view_index_metadata
- Indices:
- 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.
- Spaces: chọn
- 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:
applicationluôn làkibana-.kibana(mặc định, trừ khi bạn đổikibana.index).resourcesdùng prefixspace:. Muốn áp tất cả space ghi["*"].- Feature privilege ghi dạng
feature_<feature_id>.<level>. List feature id quaGET /_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:
| Privilege | Cho phép | Khi nào cấp |
|---|---|---|
monitor | Xem stats cluster, index, node | Tool monitoring read-only |
monitor_ml | Xem ML jobs | Dev xem anomaly detection |
manage_index_templates | Tạo/sửa index template | Platform team |
manage_ilm | Sửa ILM policy | DevOps quản lý lifecycle |
read_ccr | Cross-cluster replication read | Setup DR cluster |
manage_security | Tạo user, role | KHÔNG cấp cho dev |
all | Everything | KHÔ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_securitychính là Field-Level Security (FLS). Bài 14 sẽ đi sâu.querylà Document-Level Security (DLS), cũng bài 14.- Common index privileges:
| Privilege | Verb | Ghi chú |
|---|---|---|
read | Search, get, mget | Đủ cho Discover/Dashboard |
view_index_metadata | Hiển thị mapping | Cần để Kibana tạo data view |
create_doc | Index document mới, không update | Cho log shipper |
index | Index plus update | Cho ingest pipeline phức tạp |
delete | Delete by id | Đừng cấp cho user thường |
manage | Mapping, settings, alias | Platform team |
all | Tất cả | DBA only |
Mẹo: chia role *_reader và *_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ỉ đọcnone(mặc định): không thấy menu
Một số feature có sub-feature, ví dụ Dashboard:
| Sub-feature | Ý nghĩa |
|---|---|
dashboard.url_create | Tạo short URL chia sẻ |
dashboard.show_write_controls | Hiện nút Edit |
dashboard.create_short_url | Khá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:
- Mở Stack Management plus Security plus Users plus click chính user của mình. Coi role nào được gán.
- Mỗi role: mở chi tiết, xem block Kibana privileges. Có feature đó với mức
readtrở lên không? - Có chọn đúng space chứa privilege đó không? Nếu role chỉ mở feature ở space
devmà bạn đang ở spacedefault, 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ệc | Cách làm |
|---|---|
| Tạo role | PUT /_security/role/<name> hoặc Stack Management plus Roles |
| Gắn role cho user native | PUT /_security/user/<u> field roles |
| Map LDAP/OIDC group | PUT /_security/role_mapping/<name> |
| Check user có quyền X chưa | POST /_security/user/_has_privileges |
| List built-in role | GET /_security/role |
| List feature id | GET /_security/privilege/kibana-.kibana |
| Tạo API key có scope | POST /_security/api_key với role_descriptors |
| Audit key đang sống | GET /_security/api_key?active_only=true |
| Revoke key | DELETE /_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.