Kibana Spaces Architecture: Isolation, Design, and Operational Considerations
An architecture note describing how Kibana Spaces achieve team‑level isolation using a space_id field in the .kibana index, the trust boundaries involved, operational checks, and failure modes that would prompt a redesign.
10 Jul 2026, 04:17 UTC

Requirements
Organizations often need to let multiple teams work in Kibana while keeping each team’s saved objects (dashboards, visualizations, searches) invisible to others. The solution must share a single Elasticsearch cluster to avoid operational overhead, yet provide logical isolation that respects the principle of least privilege.
Smallest Suitable Design
The minimal change that satisfies the requirement is to add a space_id field to every document in the Kibana index (default .kibana or version‑specific .kibana_7, etc.). The Kibana server middleware then:
- Extracts the Space ID from the authenticated user’s session (or from the URL when navigating between Spaces).
- Injects that ID into all read and write requests against the
.kibanaindex. - Filters results so that a query without an explicit
space_idclause still returns only objects belonging to the current Space.
No new indices or clusters are required; the existing .kibana index stores all Spaces, differentiated solely by the space_id value.
Trust/Data Boundaries
The space_id field forms the trust boundary:
- Kibana never returns objects whose
space_iddoes not match the user’s current Space, unless an explicit cross‑space export/import operation is performed. - If Elasticsearch document‑level security (DLS) is enabled, a DLS rule can grant read/write on the
.kibanaindex only to documents wherespace_idmatches the user’s attribute, adding a second enforcement layer. - Direct Elasticsearch access bypasses Kibana’s middleware; therefore, Space IDs alone do not protect against a user with cluster‑level privileges.
Operational Checks
Kibana includes several runtime guards to help operators verify that Space isolation is working:
- At login, Kibana validates that the session contains a non‑empty, alphanumeric Space ID; missing or malformed IDs cause the request to be rejected with a 400 response.
- Audit logs emit a
space_accessevent for each saved‑object read/write, recording the user, Space ID, and object type. - The
/api/statusendpoint returns aspacessection showing the count of active Spaces and any indexing errors in the.kibanaindex. - Operators can run the following Elasticsearch query to confirm tagging (run with a user that has read access to the
.kibanaindex):
GET .kibana/_search
{
"size": 0,
"aggs": {
"spaces": {
"terms": { "field": "space_id" }
}
}
}
The aggregation lists each distinct space_id found; documents lacking the field appear under a null or missing bucket, indicating a potential problem.
Failure Modes and Conditions That Would Change the Design
Missing or Corrupted Space ID
If a document’s space_id field is absent or contains an invalid value, Kibana’s fallback logic assigns the object to the "default" Space. This can unintentionally expose the object to users of the default Space. Operators should monitor for an increase in objects residing in the default Space after bulk imports or migrations.
Loss of Write Access to the .kibana Index
Should Elasticsearch lose write permission (e.g., due to a cluster‑wide block or incorrect role mapping), all Spaces become read‑only. Users can still view existing dashboards but cannot create or modify saved objects. Restoring write access resolves the issue; no data loss occurs because the index remains intact.
Adoption of Multi‑Cluster Elasticsearch or Cross‑Cluster Search
The current design assumes a single Elasticsearch cluster holding the .kibana index. Moving to a multi‑cluster layout would require either replicating the .kibana index across clusters (with conflict‑resolution logic) or redesigning Space isolation to be cluster‑aware. In either case, the simple space_id field would no longer be sufficient without additional routing or federation mechanisms.
Enforcing Stronger Isolation via Document‑Level Security
If an organization decides that Space IDs must be enforced at the Elasticsearch layer (e.g., to protect against a compromised Kibana server), enabling DLS and disabling the middleware’s fallback to the default Space would be necessary. This change would increase operational complexity because DLS rules must be kept in sync with Space creation/deletion.
Practical Verification Steps
- Create two Spaces and verify UI isolation: Log in to Kibana, navigate to Spaces → Create a space named "team‑a". Repeat for "team‑b". In each Space, add a distinct dashboard (e.g., "Dashboard‑A" and "Dashboard‑B"). Switch between Spaces and confirm that the dashboard list shows only the dashboard belonging to the current Space.
- Check Space ID tagging via Elasticsearch: With a user that has read access to the
.kibanaindex, run the aggregation query shown above. Verify that each dashboard document appears in the bucket matching its Space ID and that no document appears in a bucket for the other Space. - Simulate missing Space ID: Using Elasticsearch
_update_by_query(requires write access), remove thespace_idfield from a known dashboard document:POST .kibana/_update_by_query?conflicts=proceed { "script": "ctx._source.remove('space_id')" }. Restart Kibana (or reload the Space) and observe that the dashboard either disappears from the UI or appears under the default Space, confirming the fallback behavior.
These steps provide confidence that the Space identifier is being stored, respected, and handled correctly when anomalous.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.