Apply OpenSearch DLS/FLS as read controls, turn security events into audit evidence, use OpenSearch 3.8 scoped API keys for machine access, and design rotation without exposing long-lived credentials.

Document/Field-Level Security, Audit Logs, API Keys/Scoped Access Where Available, and Secrets Rotation

Build least-privilege OpenSearch security with observable identity, authorization, fine-grained read controls, credential lifecycle, and explicit Elasticsearch comparison boundaries.

Intermediate → Advanced120–160 minutesOpenSearch Security · Chapter 20 · Lesson 04OpenSearch 3.8.0 · OpenSearch Dashboards 3.8.0 · Elastic comparison: 9.5.3Last reviewed: September 2026

Learning outcomes

AtlasMart’s marketplace index contains several tenants and a sensitive cost_internal field. A reader role that can search every document and field violates the business boundary even if it cannot write. This lesson adds DLS/FLS, audit evidence and OpenSearch 3.8 API keys, while keeping the crucial rule that DLS/FLS are read restrictions—not write authorization.

01

Use DLS to filter readable documents and FLS to include/exclude readable fields for a role.

02

Explain why DLS/FLS do not prevent a user with write permissions from changing hidden documents or fields.

03

Enable and reason about audit logging without treating the protected cluster as the only durable audit destination.

04

Create, use, expire and revoke a scoped OpenSearch 3.8 API key while respecting its Security/system-index limitations.

05

Design secret rotation so old credentials are removed after a verified overlap rather than simply adding new secrets forever.

Chapter baseline

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.

OpenSearch API-key status

Upstream OpenSearch API keys were introduced in 3.7. In 3.8 they are Security-plugin scoped machine credentials with configurable duration, one-time plaintext return, hashed storage and explicit revocation. They are not Elastic API keys and do not share the same endpoints or permission model.

Execution note

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. DLS filters documents during reads

Document-level security (DLS) attaches a query to an index permission so reads expose only documents that satisfy the query. AtlasMart can therefore constrain a marketplace analyst to tenant-a. DLS does not become a write predicate: if the same role also has write/delete permissions, those operations are governed by index actions, not by the DLS query.

Tenant-A reader role with DLS and FLS
PUT _plugins/_security/api/roles/atlasmart_tenant_a_reader
{
  "cluster_permissions": [],
  "index_permissions": [{
    "index_patterns": ["atlasmart-products-secure-v1"],
    "dls": "{\"term\":{\"tenant_id\":\"tenant-a\"}}",
    "fls": ["sku", "name*", "tenant_id", "category", "price", "updated_at"],
    "masked_fields": [],
    "allowed_actions": ["read"]
  }],
  "tenant_permissions": []
}

The FLS include list omits cost_internal. Because name has a multi-field, name* intentionally includes both the text field and its subfields. When DLS references a field, ensure FLS does not hide that field in a way that breaks the DLS evaluation.

2. Prove what is hidden—and what is not guaranteed

Read acceptance tests
# As tenant-A reader: expect tenant-a hits and no cost_internal in _source.
GET atlasmart-products-secure-v1/_search
{
  "query": {"match_all": {}},
  "_source": true,
  "sort": [{"sku":"asc"}]
}

Validate both document set and returned fields. Also test aggregations, field capabilities, stored fields and any application-specific retrieval path your clients use. Fine-grained security can affect query semantics and performance; measure p95/p99 using the real workload rather than assuming the filtered query is free.

Critical non-guarantee

DLS and FLS apply to read operations. They do not safely turn a broadly writable role into a tenant-scoped writer. Keep write identities separately scoped by index/data model and application routing, or enforce write tenancy upstream with a stronger architecture.

3. Audit logs are evidence, not prevention

OpenSearch audit logging is disabled by default in the upstream self-managed configuration. Enabling it can record authentication, authorization and security events according to configured categories and storage. Audit data helps incident response and compliance; it does not prevent an over-privileged action.

Enable internal audit storage in a disposable lab
# opensearch.yml — lab illustration
plugins.security.audit.type: internal_opensearch

Production audit design should consider separation of duties: if an attacker controls the protected cluster, audit events stored only on that cluster may be altered or lost with it. Select a storage/forwarding design consistent with your threat model, retention and privacy rules.

4. API keys: scoped machine credentials in OpenSearch 3.8

OpenSearch API keys are created by security administrators and authenticate with Authorization: ApiKey <token>. The plaintext token is returned only once; the plugin stores a SHA-256 hash. Keys can expire and be revoked. Requests authenticated with an API key cannot access protected Security/system indexes or call Security APIs.

Enable API tokens in Security config
config:
  dynamic:
    api_tokens:
      enabled: true
      max_duration_seconds: 7776000   # example policy ceiling: 90 days
      max_tokens: 100

Apply this Security configuration through your reviewed deployment/security-admin workflow; do not overwrite unrelated active configuration.

Create a short-lived AtlasMart ingest key
POST /_plugins/_security/api/apitokens
{
  "name": "atlasmart_ingest_20260911",
  "cluster_permissions": ["indices:data/write/bulk"],
  "index_permissions": [{
    "index_pattern": ["atlasmart-products-secure-v1"],
    "allowed_actions": ["write"]
  }],
  "duration_seconds": 3600
}

Capture once: store the returned token in a secret manager/environment outside source control, record the key ID and expiry, then discard the API response from ordinary logs. The explicit bulk cluster permission reflects the current API-key limitation documented for bulk evaluation.

Use, then revoke, the API key
# Use only the token value returned at creation.
curl -k -H "Authorization: ApiKey $ATLASMART_OS_API_KEY"   'https://localhost:9201/_plugins/_security/authinfo?pretty'

# Administrator revokes by key ID.
curl -k -u "admin:$OPENSEARCH_INITIAL_ADMIN_PASSWORD"   -X DELETE "https://localhost:9201/_plugins/_security/api/apitokens/$ATLASMART_OS_API_KEY_ID"

# Repeat the API-key request: it must now fail authentication.

5. Rotation is an overlap protocol

A safe rotation creates credential B with the same or smaller scope, deploys B to consumers, proves B works and forbidden operations still fail, then revokes credential A. If you revoke A before every consumer has switched, rotation becomes an outage. If you never revoke A, “rotation” only increases the number of valid secrets.

Evidence Before cutover After cutover
Identity New key/user appears as intended in authinfo Old key/user no longer authenticates.
Authorization Required call succeeds; destructive/security calls fail Same tests remain true.
Audit Creation/use events visible where configured Revocation/failure evidence visible.
Performance Authenticated p95/p99 baseline recorded No unexplained tail-latency regression.

6. Production judgment

Fine-grained access can become complex when users receive multiple roles; test the combined effective result, not each role in isolation. Keep audit retention proportional to investigation/compliance needs. Prefer expiring, scoped machine credentials over long-lived shared passwords when supported, and ensure the administrative path that creates keys is more protected than the application path that consumes them.

Check your understanding

  1. Does DLS stop a writer from updating a document it cannot read?
  2. What does FLS protect?
  3. Are OpenSearch API keys available in 3.8?
  4. Why is a key token shown only once?
  5. What makes rotation complete?
Review the answers

1. No. DLS restricts reads; write permissions are evaluated separately.

2. Which fields a role can read from matching indexes; it does not replace write authorization.

3. Yes. They were introduced in 3.7 and support scoped permissions, duration and revocation.

4. Only its hash is stored; clients must capture the plaintext token securely at creation time.

5. The new credential is validated, consumers switch, and the old credential is revoked/removed with evidence.

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

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.