Translate AtlasMart application jobs into OpenSearch internal users, narrowly scoped roles, role mappings, action groups, index permissions, cluster permissions, and explicit 403 acceptance tests.
Users, Roles, Role Mappings, Action Groups, Index Permissions, and Cluster Permissions
Build least-privilege OpenSearch security with observable identity, authorization, fine-grained read controls, credential lifecycle, and explicit Elasticsearch comparison boundaries.
Learning outcomes
AtlasMart now has a trustworthy OpenSearch endpoint, but the
application still authenticates as admin. A stolen
frontend secret would therefore become a cluster-administration
incident. This lesson decomposes application access into
internal users, roles, role mappings and action groups, then
treats a 403 as positive evidence that the boundary works.
Explain the difference between an internal user, backend role, OpenSearch security role and role mapping.
Create separate reader and ingester roles with narrow index/cluster permissions instead of wildcard application access.
Use action groups as named permission bundles without assuming every bundle is safe for every application.
Prove role resolution with authinfo and explicit 2xx/403 tests.
Distinguish Dashboards tenant permission from data-index permission.
Examples target upstream self-managed
OpenSearch 3.8.0 / OpenSearch Dashboards 3.8.0, released 4 August 2026, with the bundled Security plugin.
The lab reuses the earlier single-node
atlasmart-os container at
https://localhost:9201 and
OPENSEARCH_INITIAL_ADMIN_PASSWORD only for the
disposable demo bootstrap. The upstream demo certificate is
intentionally not a production PKI contract, so earlier local
labs may use -k only against this isolated demo
endpoint. Production must use hostname-valid certificates and
normal CA verification. OpenSearch 3.8 distributions use the
bundled Java runtime unless you intentionally supply a
supported alternative. Elasticsearch 9.5.3 / Kibana 9.5.3
appears only for equivalent-intent comparisons; its
/_security APIs, realms, Spaces and
service-account model are not OpenSearch Security-plugin APIs.
The Security plugin stores active configuration in its
security system index. The YAML files are
initialization/deployment inputs, not automatically live
state. Before using securityadmin.sh on an
established cluster, back up the current configuration; a
broad directory load can overwrite resources created later
through REST/Dashboards. Prefer REST/Dashboards for ongoing
non-reserved users/roles and apply individual configuration
types only when file-based administration is genuinely
required.
The generation environment does not run the AtlasMart Docker
cluster. Requests below are deterministic lab instructions and
response fragments are expected shapes/invariants, not
fabricated captures. Record your own certificate
DN/fingerprint/expiry, authinfo identity,
role-resolution evidence, 200/403 behavior, tenant visibility,
DLS/FLS results, API-key ID/expiry/revocation, audit events,
and p95/p99 latency under authenticated load.
1. Identity and authorization vocabulary
| Object | Meaning | Common mistake |
|---|---|---|
| Internal user | Username/password identity stored by the Security plugin | Embedding the admin user in an application. |
| Backend role | Group/role attribute arriving from an identity backend or attached to a user | Assuming it grants access by itself. |
| Security role | OpenSearch permission document: cluster, index, DLS/FLS, tenant permissions |
Using all_access because a single request
failed.
|
| Role mapping | Connects users/backend roles/hosts to security roles | Mapping an overly broad LDAP group to a powerful role. |
| Action group | Named bundle of low-level actions | Treating a convenient broad bundle as automatically least-privilege. |
Authentication can succeed while authorization remains empty. That state is useful: it proves the backend accepted the identity but no mapping grants actions. Diagnose mappings rather than adding wildcard permissions.
2. Create the AtlasMart fixture and reader role
PUT atlasmart-products-secure-v1
{
"settings": {"number_of_shards": 1, "number_of_replicas": 0},
"mappings": {
"dynamic": "strict",
"properties": {
"sku": {"type":"keyword"},
"name": {"type":"text", "fields":{"keyword":{"type":"keyword"}}},
"tenant_id": {"type":"keyword"},
"category": {"type":"keyword"},
"price": {"type":"scaled_float", "scaling_factor":100},
"cost_internal": {"type":"scaled_float", "scaling_factor":100},
"updated_at": {"type":"date"}
}
}
}
PUT _plugins/_security/api/roles/atlasmart_reader
{
"cluster_permissions": [],
"index_permissions": [
{
"index_patterns": ["atlasmart-products-secure-v1"],
"fls": [],
"masked_fields": [],
"allowed_actions": ["read"]
}
],
"tenant_permissions": []
}
For a backend service that only executes direct searches, no Dashboards tenant permission is needed. If a human must use OpenSearch Dashboards, add the appropriate Dashboards role/tenant permissions separately rather than widening the data role.
3. Create a lab internal user and map it to the role
PUT _plugins/_security/api/internalusers/atlasmart_reader_user
{
"password": "<SET_OUT_OF_BAND>"
}
PUT _plugins/_security/api/rolesmapping/atlasmart_reader
{
"users": ["atlasmart_reader_user"],
"backend_roles": [],
"hosts": []
}
Do not place the real password in Git, lesson HTML, shell history or screenshots. Use a local secret workflow and rotate/delete the lab user during cleanup. The internal database is excellent for a deterministic lab; a production organization with central identity may instead map backend roles from LDAP/OIDC/JWT or another supported mechanism.
curl -k -u "$OS_READER_USER:$OS_READER_PASSWORD" https://localhost:9201/_plugins/_security/authinfo?pretty
4. Make denials part of the application contract
# Expected 200.
curl -k -u "$OS_READER_USER:$OS_READER_PASSWORD" 'https://localhost:9201/atlasmart-products-secure-v1/_search?size=1'
# Expected 403. If this succeeds, the role is too broad.
curl -k -u "$OS_READER_USER:$OS_READER_PASSWORD" -X DELETE 'https://localhost:9201/atlasmart-products-secure-v1'
A 401 means identity authentication failed. A 403 means the principal authenticated but lacks the requested action. Keep both cases in integration tests because they diagnose different layers.
5. Build a separate ingester role
PUT _plugins/_security/api/roles/atlasmart_ingester
{
"cluster_permissions": [],
"index_permissions": [
{
"index_patterns": ["atlasmart-products-secure-v1"],
"fls": [],
"masked_fields": [],
"allowed_actions": ["write"]
}
],
"tenant_permissions": []
}
The static write action group is convenient, but
always inspect whether its included actions match the business
contract. If AtlasMart is append-only, a narrower custom action
group or API-specific permission set can reduce accidental
update/delete capability. Do not blindly use *,
indices_all or all_access to silence
authorization errors.
6. Tenants do not authorize data
OpenSearch Dashboards tenants isolate saved objects such as
dashboards and visualizations. Index permissions still decide
what the user can query through OpenSearch. A user can have read
access to an atlasmart_ops tenant yet receive 403
from the product index, or have direct API read access to the
index while lacking the tenant. Those are independent controls.
PUT _plugins/_security/api/roles/atlasmart_analyst
{
"cluster_permissions": ["cluster_composite_ops_ro"],
"index_permissions": [{
"index_patterns": ["atlasmart-products-secure-v1"],
"allowed_actions": ["read"]
}],
"tenant_permissions": [{
"tenant_patterns": ["atlasmart_ops"],
"allowed_actions": ["kibana_all_read"]
}]
}
7. Production judgment
Version-control role intent, not secrets. Review every wildcard. Keep service roles separate from human roles. Monitor authorization failures for both regressions and attack signals. When a request fails after an upgrade, compare the exact missing action against current role/action-group documentation rather than immediately broadening permissions.
Check your understanding
- What does a backend role do by itself?
- Why test a 403 deliberately?
- Is a Dashboards tenant a data-security boundary?
- Why avoid all_access for an application?
- When should YAML files be preferred over REST for routine users?
Review the answers
1. Nothing until a role mapping connects it to an OpenSearch security role.
2. It proves the authenticated principal cannot perform an operation outside its contract.
3. It is a saved-object/UI tenancy boundary; index authorization is separate.
4. It creates cluster-wide blast radius far beyond normal search or ingest needs.
5. Generally not for routine non-reserved resources; current guidance favors REST/Dashboards after initialization.
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
- OpenSearch 3.8 release/version history — Pinned OpenSearch 3.8.0 release baseline.
- OpenSearch Security overview — Security-plugin architecture, TLS, authentication and authorization overview.
- Configure TLS certificates — Transport/HTTP TLS, node DNs and admin certificate concepts.
- Apply Security configuration safely — Security-index initialization, backup and narrow apply guidance.
- Security APIs — Internal users, roles, mappings, tenants, certificate and related APIs.
- Users and roles — Internal users, roles, role mappings and built-in roles.
- Authentication backends — Authentication flow and chained backend concepts.
- Multi-tenancy — OpenSearch Dashboards tenant mechanics and permissions.
- Document-level security — DLS read filtering and limitations.
- Field-level security — FLS include/exclude semantics and interactions.
- Audit logs — Security audit categories, storage and enablement.
- API keys — OpenSearch 3.7+ scoped API-key lifecycle and limitations.
- OpenSearch downloads/license — Current distribution and Apache-2.0 licensing context.