Design AtlasMart human and service access with narrowly scoped Elasticsearch roles, index privileges, Kibana-space privileges, and observable authorization failures instead of shared superuser credentials.
Users, Roles, Cluster/Index/Application Privileges, Spaces, and Least-Privilege Design
Design equivalent AtlasMart retention intent in Elastic and OpenSearch while documenting non-equivalent lifecycle, tiering, policy-update, simulation, and managed-service behavior.
Learning outcomes
AtlasMart needs a search frontend, an ingest worker, an analyst-facing Kibana space and an operations team. Giving every component the same “app-user” role is convenient until the search frontend can delete indices or the ingest worker can read internal cost fields. This lesson designs privileges around jobs-to-be-done and proves denials are part of the contract.
Build separate search and ingest roles with the minimum cluster/index privileges required by their workflows.
Distinguish Elasticsearch cluster/index privileges from Kibana application/space privileges.
Use users as test principals while planning machine credentials separately.
Validate least privilege with positive requests, explicit 403 failures and has-privileges evidence.
Explain why Kibana Spaces organize and authorize Kibana content but do not replace Elasticsearch index authorization.
Examples target the official self-managed
Elasticsearch 9.5.3 / Kibana 9.5.3
distribution, reviewed 11 September 2026. The lab reuses
atlasmart-es at
https://localhost:9200, the generated HTTP CA
copied earlier as atlasmart-es-http-ca, and
ELASTIC_PASSWORD only as a bootstrap
administrator credential. Use curl --cacert;
never teach -k as an Elasticsearch security
shortcut. The official distribution includes a bundled OpenJDK
and Elastic recommends using it; no external JVM is required
by this lab. Kibana examples assume 9.5.3 when UI behavior
matters. OpenSearch 3.8.0 is mentioned only to mark
non-portable boundaries; Chapter 20 teaches its Security
plugin separately.
Encrypted communications, native/file authentication, core role-based access control, Kibana Spaces, and API-key management are available in the free Basic self-managed distribution. Document/field-level security and Elasticsearch/Kibana audit logging are subscription-sensitive features; verify the current Elastic subscription matrix for your deployment before using them as mandatory controls. The mandatory lab therefore succeeds on Basic with index-level RBAC, separate identities and short-lived API keys, and presents DLS/FLS/audit as an optional extension plus a deterministic fallback.
The generation environment does not run the AtlasMart Docker cluster, so requests are deterministic lab instructions and response fragments are expected shapes/invariants, not fabricated captures. Record your own certificate fingerprints/expiry, 401/403 evidence, key identifiers/expiration, audit events where licensed, and application p95/p99 latency under authenticated load.
1. Start from operations, then choose privileges
| Principal | Required operations | Privileges deliberately excluded |
|---|---|---|
| atlasmart-search | Search/get field metadata on product index | write, delete, mappings, security admin, snapshots |
| atlasmart-ingest | Create/index product documents in prepared index | read/search if not operationally required; cluster admin; security admin |
| atlasmart-analyst | Read approved data plus Kibana feature/space access | index writes and cluster admin |
| atlasmart-security-admin | Manage identities/roles/keys during controlled administration | Not embedded in application runtime |
Privilege names are versioned API contracts, not English
suggestions. Read the current privilege reference and test the
exact requests your application issues. For example, Kibana
commonly needs view_index_metadata alongside
read; a bare search-only role may break
field-capability discovery.
2. Create a read/search role
PUT /_security/role/atlasmart_search_role
{
"cluster": [],
"indices": [
{
"names": ["atlasmart-products-secure-v1"],
"privileges": ["read", "view_index_metadata"]
}
]
}
POST /_security/user/atlasmart_search_user
{
"password": "$SET_OUT_OF_BAND",
"roles": ["atlasmart_search_role"],
"full_name": "AtlasMart search lab principal"
}
Do not literally send $SET_OUT_OF_BAND. Set the
password through your local secure workflow. The HTML
intentionally contains no reusable secret.
# Allowed: expect HTTP 200.
curl --cacert "$ES_CA" -u "$SEARCH_USER:$SEARCH_PASSWORD" \
"$ES_URL/atlasmart-products-secure-v1/_search?size=1"
# Forbidden: expect HTTP 403, not 200.
curl --cacert "$ES_CA" -u "$SEARCH_USER:$SEARCH_PASSWORD" \
-X DELETE "$ES_URL/atlasmart-products-secure-v1"
A 403 is a successful security test: authentication succeeded, then authorization denied the action. A 401 instead points to an authentication problem.
3. Create a distinct ingest role
For a pre-created index with strict mappings, the ingest worker
does not need security-management or snapshot privileges. Choose
create_doc if the contract is append-only and
duplicate IDs should fail rather than overwrite; choose broader
write privileges only when the application genuinely
updates/deletes documents.
PUT /_security/role/atlasmart_ingest_role
{
"cluster": [],
"indices": [
{
"names": ["atlasmart-products-secure-v1"],
"privileges": ["create_doc"]
}
]
}
POST /_security/user/atlasmart_ingest_user
{
"password": "$SET_OUT_OF_BAND",
"roles": ["atlasmart_ingest_role"]
}
# Expected success: create a new id.
PUT atlasmart-products-secure-v1/_create/P-SEC-1
{
"sku":"AM-SEC-1", "name":"Secure Lab Keyboard", "category":"office",
"tenant_id":"tenant-a", "price":109.00, "cost_internal":71.20,
"updated_at":"2026-09-11T14:00:00Z"
}
# Expected authorization failure if read was not granted.
GET atlasmart-products-secure-v1/_search
4. Measure the role, not your memory of the role
POST /_security/user/_has_privileges
{
"cluster": ["manage_security", "manage", "monitor"],
"index": [
{
"names": ["atlasmart-products-secure-v1"],
"privileges": ["read", "create_doc", "delete_index", "view_index_metadata"]
}
]
}
Use this API in security regression tests. It makes privilege drift visible when roles are changed. A role name such as “read_only” is not evidence; the evaluated privileges and real request outcomes are.
5. Kibana Spaces add UI/saved-object authorization, not index security
A Kibana space scopes saved objects and feature access. Users can see only spaces granted by their roles. However, hiding Discover or placing dashboards in a space does not revoke Elasticsearch index privileges. Conversely, a user can have Elasticsearch read privileges but no Kibana-space access. Keep both layers explicit.
“The Finance dashboard is in a private Kibana space, therefore the underlying index is private.” That is false unless Elasticsearch index privileges also restrict access. Kibana feature visibility is not an index-access control.
When Kibana is part of AtlasMart, manage Kibana feature/space privileges with the Kibana role-management APIs/UI appropriate to 9.5.3 rather than hand-editing opaque application privilege strings without validation.
6. Role accumulation can widen access
Elasticsearch privileges are additive across roles. A narrow AtlasMart role can be defeated by assigning a second broad role. Security review must therefore inspect the complete effective role set. This becomes especially important with DLS/FLS in Lesson 4, where another unrestricted role on the same index can widen what a user sees.
GET /_security/user/atlasmart_search_user
GET /_security/role/atlasmart_search_role
GET /_security/user/atlasmart_ingest_user
GET /_security/role/atlasmart_ingest_role
7. Production judgment
Least privilege reduces blast radius but adds operational work:
role versioning, deployment ordering, smoke tests and
break-glass procedures. Store role definitions as reviewed
configuration artifacts. Test them against actual client
behavior in staging. Avoid granting broad wildcard index
patterns such as * merely to “make Kibana work.”
When a service needs a new operation, add the smallest privilege
after observing the concrete failure.
Check your understanding
- What is the key difference between 401 and 403 in this lab?
- Why separate search and ingest identities?
- What does view_index_metadata provide?
- Do Kibana Spaces secure Elasticsearch indices by themselves?
- Why inspect all assigned roles?
Review the answers
1. 401 means the request was not authenticated; 403 means it authenticated but authorization denied the operation.
2. They require different privileges, so compromise of one should not automatically grant the other’s capabilities.
3. Read access to index/data-stream metadata such as field capabilities/mappings needed by many read/Kibana workflows without granting document writes.
4. No. Space/feature privileges govern Kibana content and UI access; index authorization is enforced separately by Elasticsearch roles.
5. Privileges are additive; a second broad role can silently defeat a narrow least-privilege role.
Summary and next step
Preserve the evidence, assumptions, version boundaries, and safety checks established in this lesson. Carry them into the next lesson—or, at the end of the capstone, into the production runbook—rather than treating this lesson as an isolated recipe.
References
- Elastic: Secure your cluster — Current security architecture and deployment-type responsibility.
- Elastic: Automatic security setup — First-start TLS, elastic password, and Kibana enrollment-token behavior.
- Elastic: TLS for cluster communications — HTTP versus transport TLS and trust boundaries.
- Elastic: Users and roles — Authentication and RBAC model.
- Elasticsearch privileges reference — Cluster, index, application and run-as privilege semantics.
- Elastic: API key API — Expiration and role-descriptor scoping.
- Elastic: Service accounts — Predefined service accounts and service tokens.
- Elastic: DLS/FLS — Read-oriented document/field restrictions and limitations.
- Elastic: Run as — Delegated request semantics and supported authenticators.
- Elastic: Audit logging — Audit-event configuration and subscription notice.
- Elastic self-managed subscriptions — Current Basic/paid feature boundaries.
- Elastic downloads — Pinned Elasticsearch 9.5.3 release baseline.