OpenSearch Authentication and Authorization with mutual TLS

Why?

If you have an existing PKI infrastructure, mutual TLS is a convenient way to do authentication and authorization. OpenSearch supports it, although the documentation is lacking in practical examples. Let's fix that!

Configuring OpenSearch Security

Files we're touching

This post uses the OpenSearch security YAML files for configuration. While the docs recommend "creat[ing] other users, roles, mappings, action groups, and tenants using OpenSearch Dashboards or the REST API," we're going against that advice to make things a bit more clear.

In a typical Deb or RPM installation, all files listed are found in /etc/opensearch/opensearch-security.

Filename Purpose
config.yml define valid auth methods, ordering
internal_users.yml Define/configure internal users (not needed for mTLS auth)
roles.yml assigns permissions to roles
roles_mapping.yml assigns roles created in roles.yml with users

Working Example with mTLS

Below is a working snippet of config.yml from my lab. Basic auth is enabled as well.

_meta:
  type: "config"
  config_version: "2"
config:
  dynamic:
    http:
      anonymous_auth_enabled: true
    authc:
      basic_internal_auth_domain:
        http_enabled: true
        transport_enabled: true
        order: "4"
        http_authenticator:
          type: basic
          challenge: false
        authentication_backend:
          type: intern
      clientcert_auth_domain:
        description: "Authenticate via SSL client certificates"
        http_enabled: true
        transport_enabled: false
        order: 2
        http_authenticator:
          type: clientcert
          config:
            username_attribute: cn #optional, if omitted DN becomes username
          challenge: false
        authentication_backend:
          type: noop

Note username_attribute: cn above. That means we are using the client certificate's Common Name to determine role mappings. The default is to use the full Distingushed Name (DN).

In my lab, I have a vector client that needs to write to OpenSearch. Let's look at its certificate CN:

cat vector-client.service.rl.crt | certtool -i | grep "Subject:"
        Subject: CN=vector-client.service.rl,OU=clients,O=🀚🀛🀜 🀈🀉🀊 🀓🀔🀕 🀀🀀 🀄︎🀄︎ RIICHILAB 🀄︎

We also need to make sure the client cert has "TLS WWW Client" listed as a Key Purpose.

cat vector-client.service.rl.crt | certtool -i | grep -3 "Purpose"
       Extensions:
               Key Purpose (not critical):
                       TLS WWW Client.

The CN in the certificate has to match sure the user definition in roles_mapping.yml:

vector_role:
  users:
  - "vector-client.service.rl"

And the role vector_role must be defined in roles.yml:

vector_role:
  reserved: false
  hidden: false
  cluster_permissions:
    - "indices:data/write/bulk"
    - "cluster_monitor"
  index_permissions:
    - index_patterns:
        - "logs-*"
      allowed_actions:
        - "data_access"
        - "create_index"

Once all these things are in place, run the apply-security-admin.sh script to activate the config. See my earlier blog post for more details on this script and how it works.

Troubleshooting

It doesn't always work the first time. Or the second, third, etc...

Here are some ways to troubleshoot when you don't get the results you're expecting.

For the API calls below, I am invoking cURL as follows:

curl -XGET -H 'accept: application/json' --cert ${client_cert} --key ${client_key} --cacert ${ca} https://${opensearch_endpoint}:9200/${api_route}

Some API calls require super admin permissions, others should be run using the client certificate. Consult the table below for more details. (And sorry the table renders poorly, I'm working on it ;)

API Route As Purpose Example Output
_plugins/_security/authinfo?pretty client What users and roles does OpenSearch associate with this certificate? { "user" : "User [name=vector-client.service.rl, backend_roles=[], requestedTenant=null]", "user_name" : "vector-client.service.rl", "user_requested_tenant" : null, "remote_address" : "172.19.98.22:58992", "backend_roles" : [ ], "custom_attribute_names" : [ ], "roles" : [ "vector_role" ], "tenants" : { "vector-client.service.rl" : true }, "principal" : "CN=vector-client.service.rl,OU=clients,O=🀚🀛🀜 🀈🀉🀊 🀓🀔🀕 🀀🀀 🀄︎🀄︎ RIICHILAB 🀄︎", "peer_certificates" : "2", "sso_logout_url" : null }
_plugins/_security/api/roles/vector_role super admin Does this role exist, and does it have the permissions I expect? {"vector_role":{"cluster_permissions":["indices:data/write/bulk","cluster_monitor"],"hidden":false,"index_permissions":[{"allowed_actions":["data_access","create_index"],"fls":[],"index_patterns":["logs-*"],"masked_fields":[]}],"reserved":false,"static":false,"tenant_permissions":[]}}
_plugins/_security/api/rolesmapping super admin Is the client certificate CN associated with the role I expect it to be? {"rbac_admin_role":{"and_backend_roles":[],"backend_roles":["rbac_admin_role"],"hidden":false,"hosts":[],"reserved":false,"users":[]},"kibana_server_role":{"and_backend_roles":[],"backend_roles":[],"hidden":false,"hosts":[],"reserved":false,"users":["dashboards-client.service.rl"]},"operator_role":{"and_backend_roles":[],"backend_roles":[],"hidden":false,"hosts":[],"reserved":false,"users":["operator","[email protected]"]},"anonymous_users_role":{"and_backend_roles":[],"backend_roles":["opendistro_security_anonymous_backendrole"],"hidden":false,"hosts":[],"reserved":false,"users":[]},"all_access":{"and_backend_roles":[],"backend_roles":["admin"],"description":"Maps admin to all_access","hidden":false,"hosts":[],"reserved":true,"users":[]},"vector_role":{"and_backend_roles":[],"backend_roles":[],"hidden":false,"hosts":[],"reserved":false,"users":["vector-client.service.rl"]}}

Permissions are a whole 'nother ball of wax...

You now have a better idea of how to configure OpenSearch security with mutual TLS. However, figuring out what permissions are needed for which use cases is a bit more of a hassle. I hope to share more details on specific clients (such as vector) in future blog posts. Stay tuned!