Đa số team mới setup ELK đều rơi vào một trong hai cực: hoặc dựng 3 cluster Kibana riêng cho dev, staging, prod (đắt và lệch version), hoặc nhét tất cả dashboard vào space default rồi cuộn tay đi tìm (rối). Spaces là điểm cân bằng. Một cluster, nhiều “namespace” UI, mỗi namespace có saved object riêng, RBAC riêng, feature toggle riêng.

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

  • Hiểu space khác gì index, khác gì cluster
  • Tạo space dev, staging, prod và copy dashboard giữa các space
  • Hạn chế feature (ẩn Dev Tools ở prod) để giảm bán kính rủi ro
  • Gán role chỉ truy cập 1 space, kết hợp với RBAC bài 12
  • Tránh pitfall data view shared và pitfall search nhầm space

Phần 1: Space là gì, không là gì

Tóm tắt nhanh:

TầngVai trò
ClusterProcess Elasticsearch và Kibana. Cấp hạ tầng.
SpaceNamespace UI trong Kibana. Saved object có scope theo space.
IndexData trong ES. KHÔNG bị space cô lập.

Quan trọng: space không cô lập data. Nếu user có quyền read trên app-logs-*, dù ở space nào cũng đọc được index đó. Space chỉ cô lập Kibana saved object: dashboard, visualization, data view, lens, map, machine learning job (tính theo cấu hình).

Khi cần cô lập data thì dùng DLS (bài 14) hoặc tách index. Đừng kỳ vọng space tự giấu data.

Sơ đồ:

+----------------------- Cluster --------------------+
|                                                     |
|   Index: app-logs-*, nginx-*, audit-* (chung)       |
|                                                     |
|  +---- Kibana ----+                                 |
|  |  +-- Space 'default'  -- dashboards, dataviews   |
|  |  +-- Space 'dev'      -- dashboards (dev only)   |
|  |  +-- Space 'prod'     -- dashboards (prod only)  |
|  |  +-- Space 'security' -- audit dashboard         |
|  +----------------+                                 |
+-----------------------------------------------------+

Phần 2: Tạo space đầu tiên

Vào Stack Management plus Spaces plus Create space.

Các field cần điền:

  • Name: hiển thị trên UI. Ví dụ dev, staging, prod.
  • URL identifier: phần xuất hiện trong URL, ví dụ kibana.example.com/s/dev/app/discover. Mặc định Kibana sinh từ name, có thể override.
  • Avatar: chữ và màu. Đặt khác biệt rõ ràng để dev không bấm nhầm.
  • Feature visibility: tick các feature bật trong space. Tắt feature ở đây chỉ ẩn UI, không phải gỡ quyền (vẫn cần role).
  • Solution view: Classic, Observability, Security, hay Search. Để Classic cho space dev/prod multi-purpose.

Một pattern an toàn cho prod space: tắt Dev Tools, Console, Advanced Settings. User không vô tình chạy DELETE /app-logs-*.

Tạo qua API:

curl -s -u "$KB_USER:$KB_PASS" \
  -H "kbn-xsrf: true" \
  -H "Content-Type: application/json" \
  -X POST "$KB_URL/api/spaces/space" \
  -d '{
    "id": "prod",
    "name": "Production",
    "description": "Production dashboards. Read-only for non-platform.",
    "color": "#D94040",
    "initials": "PR",
    "disabledFeatures": ["dev_tools", "advancedSettings"]
  }'

List feature id để biết tắt được cái gì:

curl -s -u "$KB_USER:$KB_PASS" \
  "$KB_URL/api/features"

Phần 3: URL routing và default space

Mặc định Kibana redirect login về space cuối user vừa vào. Có 3 cách chuyển space:

  1. Click avatar góc trên trái plus Change current space.
  2. Sửa URL: /s/<space-id>/app/.... Không có prefix /s/<id>/ nghĩa là space default.
  3. Set default space qua user profile: Stack Management plus Users plus click user plus Default space.

Nếu user chỉ có quyền 1 space, Kibana auto redirect vào space đó sau login. Đây là pattern để tạo “Kibana riêng cho từng team”: tạo space team-payments, tạo role chỉ có quyền team-payments, login auto vào đó, không thấy space khác.

Phần 4: Copy saved object giữa các space

Use case kinh điển: build dashboard ở dev, test xong copy sang prod.

GUI

  1. Vào space nguồn (dev).
  2. Stack Management plus Saved objects.
  3. Tick object cần copy (dashboard + dependencies).
  4. Click Copy to space.
  5. Chọn space đích, tick Include related objects, chọn:
    • Create new objects with random IDs: tách bạch, không đè cái cũ
    • Check for existing objects: cập nhật bản hiện có
  6. Copy.

API

curl -s -u "$KB_USER:$KB_PASS" \
  -H "kbn-xsrf: true" \
  -H "Content-Type: application/json" \
  -X POST "$KB_URL/s/dev/api/spaces/_copy_saved_objects" \
  -d '{
    "spaces": ["prod"],
    "objects": [
      { "type": "dashboard", "id": "<DASHBOARD_ID>" }
    ],
    "includeReferences": true,
    "createNewCopies": false,
    "overwrite": true
  }'

Lưu ý: URL có prefix /s/dev/ để chỉ rõ space nguồn. Endpoint là API của space dev, trong body chỉ định space đích.

Resolve conflict

Nếu cùng ID nhưng nội dung khác, response 200 nhưng có field successResults[].destinationId mới, và errors[] cho object conflict. Có 2 chiến lược:

  • overwrite: true: ghi đè bản đích bằng nguồn.
  • createNewCopies: true: sinh ID mới, dashboard ở đích vẫn còn cùng tên nhưng ID khác. Dùng khi muốn tách bạch.

Trong workflow dashboard-as-code (bài 22), pattern phổ biến: source of truth là NDJSON trong git, copy giữa space chỉ làm trong giai đoạn promotion thủ công.

Phần 5: Data view dùng chung hay riêng

Mặc định data view tạo trong 1 space chỉ thấy ở space đó. Nhưng Kibana có khái niệm shared data view: data view có namespaces: ["*"] thấy ở mọi space.

Cách tạo shared data view:

  1. Tạo data view ở space default.
  2. Stack Management plus Data Views plus click data view.
  3. Phần Spaces, chọn All spaces.

Hoặc API:

curl -s -u "$KB_USER:$KB_PASS" \
  -H "kbn-xsrf: true" \
  -H "Content-Type: application/json" \
  -X POST "$KB_URL/api/spaces/_update_objects_spaces" \
  -d '{
    "objects": [
      { "type": "index-pattern", "id": "<DV_ID>" }
    ],
    "spacesToAdd": ["*"]
  }'

Khi nào shared, khi nào tách:

  • Shared khi data view trỏ vào index pattern toàn cluster (app-logs-*) và mọi team cần truy cập như nhau.
  • Tách khi mỗi space có data view riêng với runtimeFieldMap khác nhau, hoặc team không nên thấy field cluster level.

Pitfall: bật shared cho data view có runtime field nặng. Một lần ở dự án trước, runtime field painless để tính request_duration_p99 chạy được trong space dev (vài trăm doc), bật shared sang space prod (vài triệu doc) thì Discover treo 30s mỗi query. Fix: tạo bản copy data view ở space prod, gỡ runtime field, dùng index field thay thế.

Phần 6: RBAC theo space

Bài 12 đã giới thiệu Kibana feature privileges có scope theo space. Mẫu role cho dev team chỉ vào space dev:

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

Có thể gắn nhiều applications entry để cấp quyền khác nhau cho từng space. Ví dụ cùng 1 role: feature_discover.all ở space dev, feature_discover.read ở space prod.

"applications": [
  {
    "application": "kibana-.kibana",
    "privileges": ["feature_discover.all"],
    "resources": ["space:dev"]
  },
  {
    "application": "kibana-.kibana",
    "privileges": ["feature_discover.read"],
    "resources": ["space:prod"]
  }
]

Phần 7: Pattern thiết kế space cho team

Pattern 1: theo môi trường

- default (admin)
- dev
- staging
- prod

Mỗi space có data view trỏ vào pattern index riêng (dev-app-logs-*, staging-app-logs-*, prod-app-logs-*).

Phù hợp: 1 product, nhiều env.

Pattern 2: theo team

- default (platform)
- team-payments
- team-onboarding
- team-search

Mỗi team có space riêng, data view chỉ trỏ vào index của họ. RBAC khoá user team-payments chỉ thấy space của mình.

Phù hợp: monorepo / nhiều team chia sản phẩm.

Pattern 3: lai

- default (platform)
- team-payments-dev
- team-payments-prod
- team-onboarding-dev
- team-onboarding-prod

Trade-off: số space nhân lên nhanh. Kibana hỗ trợ unlimited space nhưng quản lý saved object cross-space sẽ vất hơn. Cân nhắc dùng tag thay vì nhân space khi số space quá nhiều.

Pattern 4: chỉ 1 space (default)

Hợp lệ với team nhỏ (under 10 dev), 1 sản phẩm. Đừng over-engineer. Khi nào dashboard quá nhiều hoặc team đông lên hãy chia.

Phần 8: Pitfall hay gặp

Pitfall 1: alert rule không tự theo space

Alert rule có scope theo space, nhưng connector (Slack, Email) là cluster level. Khi copy dashboard từ space dev sang prod, alert rule liên kết KHÔNG được copy tự động. Phải tạo lại rule ở space prod.

Pitfall 2: search nhầm space

User có quyền trên cả devprod. Tạo dashboard ở dev, gửi URL chia sẻ kèm prefix /s/dev/.... Đồng nghiệp click vào, làm việc một lúc rồi nhầm tưởng đang ở prod. Fix: avatar màu sắc khác biệt rõ rệt, prepend tên môi trường vào title dashboard ([DEV] Error overview).

Pitfall 3: tag không có scope theo space đúng cách

Tag là cross-space resource. Tag compliance ở space default không tự nhân ra space khác. Khi copy dashboard có gắn tag, cần copy cả tag (tag cũng là saved object). Nhớ tick Include related objects khi copy.

Pitfall 4: feature visibility nhầm với role

Tắt Dev Tools trong space settings KHÔNG đồng nghĩa với gỡ quyền. User có role feature_dev_tools.all vẫn vào được Dev Tools qua URL trực tiếp /s/<space>/app/dev_tools mặc dù menu bị ẩn. Muốn thực sự khoá thì phải gỡ feature privilege khỏi role.

Phần 9: Audit space (cleanup định kỳ)

Mỗi quý chạy script kiểm tra space “ma”:

curl -s -u "$KB_USER:$KB_PASS" \
  "$KB_URL/api/spaces/space" | jq '.[] | {id, name, disabledFeatures}'

Cho từng space, đếm saved object:

for sid in dev staging prod; do
  count=$(curl -s -u "$KB_USER:$KB_PASS" \
    "$KB_URL/s/$sid/api/saved_objects/_find?type=dashboard&per_page=1" \
    | jq '.total')
  echo "$sid: $count dashboards"
done

Space có dưới 3 dashboard và không có user gắn role là ứng viên xoá. Xoá space cũng xoá toàn bộ saved object scope theo space đó. Confirm với team trước khi xoá.

Cheatsheet

ViệcCách
Tạo spacePOST /api/spaces/space hoặc Stack Management plus Spaces
Tắt feature spacefield disabledFeatures lúc tạo space
Copy saved objectPOST /s/<src>/api/spaces/_copy_saved_objects
Share data view nhiều spacePOST /api/spaces/_update_objects_spaces với spacesToAdd: ["*"]
RBAC scope spaceresources: ["space:<id>"] trong role
Switch space qua URL/s/<id>/app/<app>
Default space cho userStack Management plus Users plus Default space
Audit dashboard mỗi space/s/<id>/api/saved_objects/_find?type=dashboard

Lời kết

Spaces là tầng cô lập rẻ và linh hoạt. Đừng vội dựng 3 cluster Kibana khi 3 space đã đủ. Tận dụng feature visibility plus RBAC theo space để giảm bán kính rủi ro ở prod, và copy saved object có kiểm soát để dashboard không loạn.

Bài 14 sẽ quay lại security ở tầng data: API keys nâng cao với Document-Level Security và Field-Level Security. Bạn sẽ thấy một key có thể chỉ đọc document có tenant id cụ thể, hoặc che hết field PII trước khi trả về user, giúp đáp ứng SOC2 và GDPR.