Unauthorized message when using clent certification authentification

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

Blockquote

Describe the issue:

Hello, I am trying to configure opensearch in a secure way. I have set up Opensearch and an LDAP server, now all user can connect with no issue through the dashboard.
I also use Jenkins, so I wanted to configure client certificate athentication. I use the first certificate i configure to try connecting to opensearch node but i got an error of Unauthorized as follow :

Here is the command i run :

**elasticdump --input=kibana.json --ca root-ca.pem --cert client.pem --key client-key.pem --output=https://xxxxx.xxxx.xxxx/.kibana_2**

I use the same certificate that the dashboard is using but i get an error.

Configuration:
Here is my configuration :

plugins.security.ssl.transport.pemkey_filepath: node1-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: root-ca.pem
plugins.security.ssl.transport.enforce_hostname_verification: false
plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: node1.pem
plugins.security.ssl.http.pemkey_filepath: node1-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: root-ca.pem
plugins.security.ssl.http.clientauth_mode: OPTIONAL
plugins.security.allow_default_init_securityindex: true
plugins.security.authcz.admin_dn:
          - 'CN=admin,OU=XX,O=XXXXXXX,L=XXXXX,C=XX'
plugins.security.nodes_dn:
          - 'CN=node1.xxx.x-xxxxxx,OU=XX,O=XXXXXXX,L=XXXXX,C=XX'
plugins.security.audit.type: internal_opensearch
plugins.security.enable_snapshot_restore_privilege: true
plugins.security.check_snapshot_restore_write_privileges: true
plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]
cluster.routing.allocation.disk.threshold_enabled: false
opendistro_security.audit.config.disabled_rest_categories: NONE
opendistro_security.audit.config.disabled_transport_categories: NONE

Thanks,

Relevant Logs or Screenshots:

Hi @maestro57,

Is your client.pem DN included in plugins.security.authcz.admin_dn?

Could you please share your config.yml?

You might be interested in:

Best,
mj

1 Like

Hello @Mantas

That for the reactivity
here is my config.yml

    authc:
      clientcert_auth_domain:
        description: "Authenticate via SSL client certificates"
        http_enabled: true
        transport_enabled: true
        order: 1
        http_authenticator:
          type: clientcert
          config:
            username_attribute: cn #optional, if omitted DN becomes username
          challenge: false
        authentication_backend:
          type: noop
      ldap:
        description: "Authenticate via LDAP or Active Directory"
            verify_hostnames: true
            hosts:
            - xxxxxxxxxxxxxxxxxx:xxx
            bind_dn: 'cn=admin,dc=xxxxxxxx,dc=xxx,dc=xxx'
            userbase: 'ou=XXXX,dc=xxxxxxxx,dc=xxx,dc=xxx'
            usersearch: '(uid={0})'
            username_attribute: 'uid'

Thanks

I have the same issue. Did everything that was needed to do based on the documentation but it still does not work.

Hello,

please, can i have some help ?

Thanks again

Hi @maestro57 (same to you @hm21),

How are you assigning roles to your common name (CN)?
Would you mind sharing your roll mapping - you can run the bellow to get roll mapping:


 curl --insecure -u <admin_username>:<admin_password> -XGET https://<OS_node>:9200/_plugins/_security/api/rolesmapping?pretty

You also might be interested in:

best,
mj

Hello @Mantas, I now know why it didn’t work for me.
It was because the order of the authentication methods in config.yml file.

Previous config.yml file which had the wrong order of authentication methods:

---
_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    do_not_fail_on_forbidden: true
    do_not_fail_on_forbidden_empty: true
    http:
      anonymous_auth_enabled: false
    authc:
      internal_auth:
        order: 0
        description: "HTTP basic authentication using the internal user database"
        http_enabled: true
        transport_enabled: true
        http_authenticator:
          type: basic
          challenge: true
        authentication_backend:
          type: internal
      clientcert_auth_domain:
        description: "Authenticate via SSL client certificates"
        http_enabled: true
        transport_enabled: true
        order: 1
        http_authenticator:
          type: clientcert
          config:
            username_attribute: cn #optional, if omitted DN becomes username
          challenge: false
        authentication_backend:
          type: noop

The fix was to change the order, so it looks like the following:

---
_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    do_not_fail_on_forbidden: true
    do_not_fail_on_forbidden_empty: true
    http:
      anonymous_auth_enabled: false
    authc:
      clientcert_auth_domain:
        description: "Authenticate via SSL client certificates"
        http_enabled: true
        transport_enabled: true
        order: 0
        http_authenticator:
          type: clientcert
          config:
            username_attribute: cn #optional, if omitted DN becomes username
          challenge: false
        authentication_backend:
          type: noop
      internal_auth:
        order: 1
        description: "HTTP basic authentication using the internal user database"
        http_enabled: true
        transport_enabled: true
        http_authenticator:
          type: basic
          challenge: true
        authentication_backend:
          type: internal

the client cert authentication needs to be the authentication method with order 0 for it to work.
If it has the order of 1 after and internal_auth has the order of 0 then the client certificate authentication works along the basic authentication, providing two layers of security.

@Mantas is this the right approach I’m having now or does the order not matter?

Because in the documentation example (Client certificate authentication - OpenSearch Documentation) the order is set to “1” for the clientcert_auth_domain

1 Like

Yes, you are correct the order is of great importance and in your particular case the order of the clientcert_auth_domain: should be lower than internal_auth:- as it sets the authentication order.

clientcert_auth_domain.http_authenticator.challenge: false should be disabled too in this particular case, for both authentication methods to work, as it is correctly done in your example.

Thanks for sharing @hm21.

Best,
mj

1 Like

Hello @Mantas

Here is my rolemapping

{
  "manage_snapshots" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "snapshotrestore"
    ],
    "and_backend_roles" : [ ]
  },
  "logstash" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "logstash"
    ],
    "and_backend_roles" : [ ]
  },
  "kibana_user" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "kibanauser"
    ],
    "and_backend_roles" : [ ]
  },
  "kibana_read_only" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "kibanareadonly"
    ],
    "and_backend_roles" : [ ]
  },
  "all_access" : {
    "hosts" : [ ],
    "users" : [
      "*",
      "client.dns.a-record"
    ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [ ],
    "and_backend_roles" : [ ]
  },
  "readall" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "readall"
    ],
    "and_backend_roles" : [ ]
  }
}

Thanks

Hi @maestro57,

What is the CN in the cert used for authentication?

Can you confirm orders of all your authentication methods or share a full config.yml file?

Thanks,
mj

Hello @Mantas

Here is my CN :

CN = client.dns.a-record

And for the authentification order, the first one is client certificate and the second one is ldap.

Thanks a lot,

Hi @maestro57,

Could you run the below and share the output:

curl --insecure -u <admin_username>:<admin_password> -XGET https://<OS_node>:9200/_plugins/_security/api/securityconfig?pretty

Thanks,
mj

Bonjour @Mantas

Ici le resultat de la commande :

{
  "config" : {
    "dynamic" : {
      "filtered_alias_mode" : "warn",
      "disable_rest_auth" : false,
      "disable_intertransport_auth" : false,
      "respect_request_indices_options" : false,
      "kibana" : {
        "multitenancy_enabled" : false,
        "server_username" : "kibanaserver",
        "index" : ".kibana"
      },
      "http" : {
        "anonymous_auth_enabled" : false,
        "xff" : {
          "enabled" : false,
          "internalProxies" : "192\\.168\\.0\\.10|192\\.168\\.0\\.11",
          "remoteIpHeader" : "X-Forwarded-For"
        }
      },
      "authc" : {
        "ldap" : {
          "http_enabled" : true,
          "transport_enabled" : true,
          "order" : 2,
          "http_authenticator" : {
            "challenge" : true,
            "type" : "basic",
            "config" : { }
          },
          "authentication_backend" : {
            "type" : "ldap",
            "config" : {
              "enable_ssl" : false,
              "enable_start_tls" : false,
              "enable_ssl_client_auth" : false,
              "verify_hostnames" : false,
              "hosts" : [
                "xxxxxxxx:389"
              ],
              "bind_dn" : "cn=XXXX,dc=XXXXXXXX,dc=XXX,dc=XX",
              "password" : "XXXXXXXXXXXX",
              "userbase" : "ou=Users,dc=XXXXXXXXX,dc=XXX,dc=XXX",
              "usersearch" : "(uid={0})",
              "username_attribute" : "uid"
            }
          },
          "description" : "Authenticate via LDAP or Active Directory"
        },
        "clientcert_auth_domain" : {
          "http_enabled" : true,
          "transport_enabled" : true,
          "order" : 1,
          "http_authenticator" : {
            "challenge" : false,
            "type" : "clientcert",
            "config" : {
              "username_attribute" : "cn"
            }
          },
          "authentication_backend" : {
            "type" : "noop",
            "config" : { }
          },
          "description" : "Authenticate via SSL client certificates"
        }
      },
      "authz" : { },
      "auth_failure_listeners" : { },
      "do_not_fail_on_forbidden" : false,
      "multi_rolespan_enabled" : true,
      "hosts_resolver_mode" : "ip-only",
      "do_not_fail_on_forbidden_empty" : false
    }
  }
}

Merci d’avance,

all looks in order.

Could you also run the below:

curl --insecure --cacert root-ca.pem --cert client.pem --key client-key.pem -H "Content-Type:application/json" -XGET https://localhost:9200/_plugins/_security/authinfo?pretty

One more thing, can you try with --cacert instead of --ca

Best,
mj

i try the following command :

curl --insecure --cacert root-ca.pem --cert client.pem --key client-key.pem -H "Content-Type:application/json" -XGET https://xxxxxxxx:9200/_plugins/_security/authinfo?pretty

but got an Unauthorized.

Could you share the output of:


openssl x509 -noout -subject -in client.pem

Best,
mj

Here is the output :

subject=C = FR, L = PARIS, O = XXXXXXX, OU = IT, CN = client.dns.a-record

Could you please add the subject to your plugins.security.authcz.admin_dn: to test your cert:

plugins.security.authcz.admin_dn:
          - 'CN=admin,OU=XX,O=XXXXXXX,L=XXXXX,C=XX'
          - 'CN=client.dns.a-record,OU=IT,O=XXXXXXX,L=PARIS,C=FR'

best,
mj

I did as you told me, but i still get the same error :

Thu, 18 Apr 2024 10:18:00 GMT | starting dump
Thu, 18 Apr 2024 10:18:00 GMT | got 89 objects from source file (offset: 0)
Thu, 18 Apr 2024 10:18:00 GMT | Error Emitted => Unauthorized
Thu, 18 Apr 2024 10:18:00 GMT | Error Emitted => Unauthorized
Thu, 18 Apr 2024 10:18:00 GMT | Total Writes: 0
Thu, 18 Apr 2024 10:18:00 GMT | dump ended with error (get phase) => UNAUTHORIZED: Unauthorized

Thanks,

Did you reboot your cluster after updating the config file (opensearch.yml)?

How did you generate your certificates?

Please try the below:

best,
mj