Security REST API not working when authenticating as internal user

Versions (relevant - OpenSearch/Dashboard/Server OS/Browser):
2.7.0

Describe the issue:
The official docs describe that there is a possibility to authenticate using an internal user mapped to a role that is included in these setting:

plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]
plugins.security.ssl_cert_reload_enabled: true

So, I created an internal user and mapped him on security_rest_api_access role.

However, these are the results of my testing:

GET _plugins/_security/api/tenants → 200
GET _plugins/_security/api/roles → 200
GET _plugins/_security/allowlist → 403 Forbidden
PUT _plugins/_security/api/ssl/http/reloadcerts → 400 Bad request
PUT _opendistro/_security/api/ssl/http/reloadcerts → 403 Forbidden
GET _plugins/_security/api/ssl/certs → 403 Forbidden

while all the above, using cert authentication work fine. With one exception, PUT _plugins/_security/api/ssl/http/reloadcerts still gives 400 Bad request. So, this API is not working, while PUT _opendistro/_security/api/ssl/http/reloadcerts works fine.

Any info on why the above discrepancies are happening? Am I missing anything?

Hi @spapadop

In order to check whether the role was mapped, could you please share the output of the following command?

GET _plugins/_security/api/internalusers/<username>

Thanks for the answer @Eugene7,

FYI, the above tests were done on 2.7.0, I ran the same on 2.9.0. Now errors are returned as response from the API, which is better.
Here are the results alongside with further info as requested.

GET _plugins/_security/api/internalusers/trelo
{
  "trelo" : {
    "hash" : "",
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      ""
    ],
    "attributes" : { },
    "opendistro_security_roles" : [ ],
    "static" : false
  }
}
GET _plugins/_security/api/account?pretty
{
  "user_name" : "trelo",
  "is_reserved" : false,
  "is_hidden" : false,
  "is_internal_user" : true,
  "user_requested_tenant" : null,
  "backend_roles" : [
    ""
  ],
  "custom_attribute_names" : [ ],
  "tenants" : {
    "global_tenant" : true,
    "audit_logs" : true,
    "trelo" : true
  },
  "roles" : [
    "own_index",
    "kibana_user",
    "security_rest_api_access",
    "all_access"
  ]
}
GET _plugins/_security/health
{
  "message" : null,
  "mode" : "strict",
  "status" : "UP"
}
GET _plugins/_security/api/tenants
{
  "global_tenant" : {
    "reserved" : true,
    "hidden" : false,
    "description" : "Global tenant",
    "static" : true
  },
  "audit_logs" : {
    "reserved" : false,
    "hidden" : false,
    "description" : "Tenant for the audit logs",
    "static" : false
  }
}
GET _plugins/_security/api/allowlist
{
  "status" : "FORBIDDEN",
  "message" : "API allowed only for super admin."
}
GET _plugins/_security/api/ssl/certs
{
  "status" : "FORBIDDEN",
  "message" : ""
}
PUT _plugins/_security/api/ssl/http/reloadcerts
{
  "status" : "FORBIDDEN",
  "message" : ""
}
PUT _plugins/_security/api/ssl/transport/reloadcerts
{
  "status" : "FORBIDDEN",
  "message" : ""
}

Finally, I ran the last three commands authenticating with certificate, and this time everything worked as expected:

curl --cert admin.pem --key admin.key  https://localhost:9200/_plugins/_security/api/allowlist
{ }
curl --cert admin.pem --key admin.key  https://localhost:9200/_plugins/_security/api/ssl/certs
{
  "http_certificates_list" : [
    {
      "issuer_dn" : "blah blah",
      "subject_dn" : "blah blah",
      "san" : "blah blah",
      "not_before" : "blah blah",
      "not_after" : "blah blah"
    }
  ],
  "transport_certificates_list" : [
    {
      "issuer_dn" : "blah blah",
      "subject_dn" : "blah blah",
      "san" : "blah blah",
      "not_before" : "blah blah",
      "not_after" : "blah blah"
    }
  ]
}
curl -XPUT --cert admin.pem --key admin.key  https://localhost:9200/_plugins/_security/api/ssl/http/reloadcerts
{
  "message" : "updated http certs"
}
curl -XPUT --cert admin.pem --key admin.key  https://localhost:9200/_plugins/_security/api/ssl/transport/reloadcerts
{
  "message" : "updated transport certs"
}

So in the end, the question is, why as trelo user I cannot use the APIs:

  • GET _plugins/_security/api/allowlist
  • GET _plugins/_security/api/ssl/certs
  • PUT _plugins/_security/api/ssl/http/reloadcerts
  • PUT _plugins/_security/api/ssl/transport/reloadcerts

And how to enable that (if possible). Thanks again in advance for your time.

The certificate and allowlist APIs require a user defined in admin_dn. This must be set in the opensearch.yml of every OpenSearch node. Once it is set either _opendistro/security or _plugins/security will reload the certs. The _opendistro is legacy endpoint and probably will be deprecated in the future.

But then in plugins.security.authcz.admin_dn setting, I can only set distinguished names of certificates, as per documentation:

# Defines the DNs (distinguished names) of certificates
# to which admin privileges should be assigned (mandatory)
plugins.security.authcz.admin_dn:
  - "CN=kirk,OU=client,O=client,l=tEst, C=De"

So, my understanding is that an OpenSearch internal user (e.g. trelo as mentioned above) cannot be listed there, so in the end there is no way to use basic authentication curl -u trelo:pass https://localhost:9200/_plugins/_security/api/ssl/certs to achieve any of these super admin actions. Is my understanding correct?

Just for fun, I tried something like this unsuccessfully, to give internal user trelo superadmin access:

plugins.security.authcz.admin_dn:
- "CN=testuser,CN=32132,CN=testusers,OU=Users,OU=Organic Units,DC=test,DC=test"
- "trelo"

Thanks again for your input.

According to the tests, these permissions can be assigned only through yml files and securityadmin.sh. OpenSearch Dashboards doesn’t allow to either duplicate the role or map users.

Also, these permissions don’t allow to use internal users to access these endpoints and admin certificates are still required.

Many thanks for all the input, it’s all clear now.