Document-level security

Document-level security lets you restrict a role to a subset of documents in an index. The easiest way to get started with document- and field-level security is open OpenSearch Dashboards and choose Security. Then choose Roles, create a new role, and review the Index permissions section.

Document- and field-level security screen in OpenSearch Dashboards

Simple roles

Document-level security uses the OpenSearch query DSL to define which documents a role grants access to. In OpenSearch Dashboards, choose an index pattern and provide a query in the Document level security section:

  1. {
  2. "bool": {
  3. "must": {
  4. "match": {
  5. "genres": "Comedy"
  6. }
  7. }
  8. }
  9. }

This query specifies that for the role to have access to a document, its genres field must include Comedy.

A typical request to the _search API includes { "query": { ... } } around the query, but in this case, you only need to specify the query itself.

In the REST API, you provide the query as a string, so you must escape your quotes. This role allows a user to read any document in any index with the field public set to true:

  1. PUT _plugins/_security/api/roles/public_data
  2. {
  3. "cluster_permissions": [
  4. "*"
  5. ],
  6. "index_permissions": [{
  7. "index_patterns": [
  8. "pub*"
  9. ],
  10. "dls": "{\"term\": { \"public\": true}}",
  11. "allowed_actions": [
  12. "read"
  13. ]
  14. }]
  15. }

These queries can be as complex as you want, but we recommend keeping them simple to minimize the performance impact that the document-level security feature has on the cluster.

Parameter substitution

A number of variables exist that you can use to enforce rules based on the properties of a user. For example, ${user.name} is replaced with the name of the current user.

This rule allows a user to read any document where the username is a value of the readable_by field:

  1. PUT _plugins/_security/api/roles/user_data
  2. {
  3. "cluster_permissions": [
  4. "*"
  5. ],
  6. "index_permissions": [{
  7. "index_patterns": [
  8. "pub*"
  9. ],
  10. "dls": "{\"term\": { \"readable_by\": \"${user.name}\"}}",
  11. "allowed_actions": [
  12. "read"
  13. ]
  14. }]
  15. }

This table lists substitutions.

TermReplaced with
${user.name}Username.
${user.roles}A comma-separated, quoted list of user roles.
${attr.<TYPE>.<NAME>}An attribute with name <NAME> defined for a user. <TYPE> is internal, jwt, proxy or ldap

Attribute-based security

You can use roles and parameter substitution with the terms_set query to enable attribute-based security.

Note that the security_attributes of the index need to be of type keyword.

User definition

  1. PUT _plugins/_security/api/internalusers/user1
  2. {
  3. "password": "asdf",
  4. "backend_roles": ["abac"],
  5. "attributes": {
  6. "permissions": "\"att1\", \"att2\", \"att3\""
  7. }
  8. }

Role definition

  1. PUT _plugins/_security/api/roles/abac
  2. {
  3. "index_permissions": [{
  4. "index_patterns": [
  5. "*"
  6. ],
  7. "dls": "{\"terms_set\": {\"security_attributes\": {\"terms\": [${attr.internal.permissions}], \"minimum_should_match_script\": {\"source\": \"doc['security_attributes'].length\"}}}}",
  8. "allowed_actions": [
  9. "read"
  10. ]
  11. }]
  12. }