I am using tar distro
I ran this
curl -sk -XPOST --key /opt/opensearch-2.6.0-alpha/config/opensearch_admin_key.pem --cert /opt/opensearch-2.6.0-alpha/config/opensearch_admin_cert.pem https://localhost:9200/_nodes/reload_secure_settings
and it loads secure settings on all the nodes as a response json
@stecino After initial deployment the security plugin will create the .opensearch_security index which will contain all the security configurations.
To update the security settings you’ll need to use securityadmin.sh script
I am using this certificate for communication with all the nodes in the cluster, so the certificate and path are valid
./securityadmin.sh
** This tool will be deprecated in the next major release of OpenSearch **
** [DEPRECATION] Security Plugin Tools will be replaced · Issue #1755 · opensearch-project/security · GitHub **
Security Admin v7
Will connect to nodem01.corp.pvt:9200 … done
ERR: An unexpected SSLHandshakeException occured: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
See Java high-level REST client - OpenSearch documentation for troubleshooting.
Trace:
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
See Java high-level REST client - OpenSearch documentation for troubleshooting.
at org.opensearch.client.RestClient.extractAndWrapCause(RestClient.java:947)
at org.opensearch.client.RestClient.performRequest(RestClient.java:332)
at org.opensearch.client.RestClient.performRequest(RestClient.java:320)
at org.opensearch.security.tools.SecurityAdmin.execute(SecurityAdmin.java:462)
at org.opensearch.security.tools.SecurityAdmin.main(SecurityAdmin.java:159)
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:371)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:314)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:309)
This is what bash script looks like
#!/bin/bash
JAVA_HOME=/opt/opensearch-2.6.0-alpha/jdk
export -p JAVA_HOME
"/opt/opensearch-2.6.0-alpha/plugins/opensearch-security/tools/securityadmin.sh" -cd "/opt/opensearch-2.6.0-alpha/config/opensearch-security" -icl -key "/opt/opensearch-2.6.0-alpha/config/opensearch_hosts_key.pem" -cert "/opt/opensearch-2.6.0-alpha/config/combined.pem" -cacert "/opt/opensearch-2.6.0-alpha/config/private_root_ca.pem" -nhnv --accept-red-cluster -h nodem01.corp.pvt
@stecino You must use the certificate defined in admin_dn in opensearch.yml
Worked!!
Clusterstate: GREEN
Number of nodes: 14
Number of data nodes: 10
.opendistro_security index already exists, so we do not need to create one.
Populate config from /opt/opensearch-2.6.0-alpha/config/opensearch-security/
Will update ‘/config’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/config.yml
SUCC: Configuration for ‘config’ created or updated
Will update ‘/roles’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/roles.yml
SUCC: Configuration for ‘roles’ created or updated
Will update ‘/rolesmapping’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/roles_mapping.yml
SUCC: Configuration for ‘rolesmapping’ created or updated
Will update ‘/internalusers’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/internal_users.yml
SUCC: Configuration for ‘internalusers’ created or updated
Will update ‘/actiongroups’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/action_groups.yml
SUCC: Configuration for ‘actiongroups’ created or updated
Will update ‘/tenants’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/tenants.yml
SUCC: Configuration for ‘tenants’ created or updated
Will update ‘/nodesdn’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/nodes_dn.yml
SUCC: Configuration for ‘nodesdn’ created or updated
Will update ‘/whitelist’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/whitelist.yml
SUCC: Configuration for ‘whitelist’ created or updated
Will update ‘/audit’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/audit.yml
SUCC: Configuration for ‘audit’ created or updated
Will update ‘/allowlist’ with /opt/opensearch-2.6.0-alpha/config/opensearch-security/allowlist.yml
SUCC: Configuration for ‘allowlist’ created or updated
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
SUCC: Expected 10 config types for node {“updated_config_types”:[“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”],“updated_config_size”:10,“message”:null} is 10 ([“allowlist”,“tenants”,“rolesmapping”,“nodesdn”,“audit”,“roles”,“whitelist”,“internalusers”,“actiongroups”,“config”]) due to: null
Done with success
This is what I get from the security config call
"ldap" : {
"http_enabled" : false,
"transport_enabled" : false,
"order" : 2,
"http_authenticator" : {
"challenge" : false,
"type" : "basic",
"config" : { }
},
"authentication_backend" : {
"type" : "ldap",
"config" : {
"enable_ssl" : false,
"enable_start_tls" : false,
"enable_ssl_client_auth" : false,
"verify_hostnames" : true,
"hosts" : "ca01-ldap.corp.pvt:389",
"bind_dn" : "CN=LogstashServer,OU=Service Accounts,OU=System Accounts,DC=corp,DC=pvt",
"password" : "xxxxxxxx",
"userbase" : [
"OU=Employees,OU=people,DC=corp,DC=pvt",
"OU=Service Accounts,OU=System Accounts,DC=corp,DC=pvt"
],
"usersearch" : "(CN={0})",
"username_attribute" : "CN"
}
},
"description" : "Authenticate via LDAP or Active Directory"
},
~
@stecino Can you log in now?
I don’t see your autz section. Did you configure it in config.yml?
I still can’t login.
No I didn’t, documentation said I should be able to set this up in roles.yml? Shouldn’t I be able to login without the authz setup though?
@stecino You will only authenticate without authz. Authz must be configured in config.yml.
Could you share the documentation that mentions roles.yml?
Let me check where I found it
Did I misunderstood?
Active Directory and LDAP can be used for both authentication and authorization (the
authc
andauthz
sections of the configuration, respectively). Authentication checks whether the user has entered valid credentials. Authorization retrieves any backend roles for the user.
In most cases, you want to configure both authentication and authorization. You can also use authentication only and map the users retrieved from LDAP directly to security plugin roles.
@pablo so added the authz to my to my config.yml, updated the configs and reloaded the secure setting, still can’t login
Johndoe123 is memberOf bunch of groups under OU=Roles,OU=Groups,DC=corp,DC=pvt, so how do autherize the access? I
authz:
roles_from_myldap:
description: "Authorize via LDAP or Active Directory"
http_enabled: false
transport_enabled: false
authorization_backend:
# LDAP authorization backend (gather roles from a LDAP or Active Directory, you have to configure the above LDAP authentication backend settings too)
type: ldap
config:
# enable ldaps
enable_ssl: false
# enable start tls, enable_ssl should be false
enable_start_tls: false
# send client certificate
enable_ssl_client_auth: false
# verify ldap hostname
verify_hostnames: true
hosts: 'ca01-ldap.corp.pvt:389'
bind_dn: 'CN=LogstashServer,OU=Service Accounts,OU=System Accounts,DC=corp,DC=yp,DC=com'
password: 'xxxxxxxxxxxx'
rolebase: 'OU=Roles,OU=Groups,DC=corp,DC=pvt'
# Filter to search for roles (currently in the whole subtree beneath rolebase)
# {0} is substituted with the DN of the user
# {1} is substituted with the username
# {2} is substituted with an attribute value from user's directory entry, of the authenticated user. Use userroleattribute to specify the name of the attribute
rolesearch: '(member={0})'
# Specify the name of the attribute which value should be substituted with {2} above
userroleattribute: null
# Roles as an attribute of the user entry
userrolename: disabled
#userrolename: memberOf
# The attribute in a role entry containing the name of that role, Default is "name".
# Can also be "dn" to use the full DN as rolename.
rolename: cn
# Resolve nested roles transitive (roles which are members of other roles and so on ...)
resolve_nested_roles: true
userbase:
- 'OU=Employees,OU=people,DC=corp,DC=pvt'
- 'OU=Service Accounts,OU=System Accounts,DC=corp,DC=pvt'
# Filter to search for users (currently in the whole subtree beneath userbase)
# {0} is substituted with the username
usersearch: '(CN={0})'
# Skip users matching a user name, a wildcard or a regex pattern
#skip_users:
# - 'cn=Michael Jackson,ou*people,o=TEST'
# - '/\S*/'
@stecino This part of the documentation doesn’t say anything about roles.yml. It only states that authz section is not mandatory (Configuring the Security backend - OpenSearch documentation).
There are 2 scenarios with LDAP authentication/authorization.
-
Configure authc and authz in cofig.yml.
In this scenario after authenticating LDAP user, authorization (roles/groups) will also be performed with the LDAP server.
The LDAP user’s groups must be mapped as backend_roles to OpenSearch roles in roles_mapping.yml
Modifying the YAML files - OpenSearch documentation -
Configure only authc.
In this scenario, the LDAP user will be only authenticated through the LDAP server. The authorization part will be done through roles_mapping.yml
The LDAP user must be mapped inusers
field of the OpenSearch role of roles_mapping.yml (See the example shared in scenario 1).
Regarding further troubleshooting. Please share the output of the below command.
curl --insecure -u <LDAP_user> -XGET https://<OpenSearch_node_IP_or_FQDN>:9200/_plugins/_security/authinfo?pretty
Ran the command
curl --insecure -u johndoe123 -XGET https://localhost:9200/_plugins/_security/authinfo?pretty
Enter host password for user 'johndoe123':
Authentication finally failed
Log shows
Authentication finally failed for null from 127.0.0.1:48524
Question for you. Do I need to make changes to config.yml and other yml files in the opensearch-security folder on all the nodes, or just on one of the nodes and run the securityadmin.sh
johndoe123 is member of
CN=SiteReliability,OU=Roles,OU=Groups,DC=corp,DC=pvt
what’s the syntax of adding this group to the following role_mapping?
all_access:
reserved: true
backend_roles:
- admin
- App-Okta-OpenSearch-Admin
Just add this?
- CN=SiteReliability,OU=Roles,OU=Groups,DC=corp,DC=pvt
@pablo I am trying to convert my authc and authz configs into ldapsearch command to better understand what’s being queried from AD:
ldap:
description: "Authenticate via LDAP or Active Directory"
http_enabled: false
transport_enabled: false
order: 2
http_authenticator:
type: basic
challenge: false
authentication_backend:
type: ldap
config:
enable_ssl: false
enable_start_tls: false
enable_ssl_client_auth: false
verify_hostnames: true
hosts:
- 'ca01-ldap.corp.corp.pvt:389'
bind_dn: 'CN=LogstashServer,OU=Service Accounts,OU=System Accounts,DC=corp,DC=pvt'
password: 'xxxxxxxxxx'
userbase:
- 'OU=Employees,OU=people,DC=corp,DC=pvt'
- 'OU=Service Accounts,OU=System Accounts,DC=corp,DC=pvt'
usersearch: '(CN={0})'
username_attribute: 'CN'
and corresponding ldapsearch query execution and returned results
ldapsearch -h ca01-ldap.corp.pvt -p 389 -b "dc=corp,dc=pvt" -D "CN=LogstashServer,OU=Service Accounts,OU=System Accounts,DC=corp,DC=pvt" -W '(CN=johndoe123)' cn
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <dc=corp,dc=pvt> with scope subtree
# filter: (CN=johndoe123)
# requesting: cn
# with pagedResults control: size=100
#
# johndoe123, Employees, People, corp.pvt
dn: CN=johndoe123,OU=Employees,OU=People,DC=corp,DC=pvt
cn: johndoe123
# search reference
ref: ldap://DomainDnsZones.corp.pvt/DC=DomainDnsZones,DC=corp,DC=pvt
# search reference
ref: ldap://ForestDnsZones.corp.pvt/DC=ForestDnsZones,DC=corp,DC=pvt
# search reference
ref: ldap://corp.pvt/CN=Configuration,DC=corp,DC=pvt
# search result
search: 2
result: 0 Success
control: 1.2.840.113556.1.4.319 false MIQAAAAFAgEABAA=
pagedresults: cookie=
# numResponses: 5
authz:
roles_from_myldap:
description: "Authorize via LDAP or Active Directory"
http_enabled: false
transport_enabled: false
authorization_backend:
type: ldap
config:
enable_ssl: false
enable_start_tls: false
enable_ssl_client_auth: false
verify_hostnames: true
hosts:
- 'ca01-ldap.corp.pvt:389'
bind_dn: 'CN=LogstashServer,OU=Service Accounts,OU=System Accounts,DC=corp,DC=pvt'
password: 'xxxxxxxxx'
rolebase: 'OU=Roles,OU=Groups,DC=corp,DC=pvt'
rolesearch: '(member={0})'
userroleattribute: null
userrolename: disabled
rolename: cn
resolve_nested_roles: true
userbase:
- 'OU=Employees,OU=people,DC=corp,DC=pvt'
- 'OU=Service Accounts,OU=System Accounts,DC=corp,DC=pvt'
usersearch: '(CN={0})'
and corresponding ldapsearch query execution, not sure if this is right
ldapsearch -h ca01-ldap.corp.pvt -p 389 -b 'OU=Roles,OU=Groups,DC=corp,DC=pvt' -D "CN=LogstashServer,OU=Service Accounts,OU=System Accounts,DC=corp,DC=pvt" -W '(member=CN=johndoe123,OU=Employees,OU=People,DC=corp,DC=pvt)' cn 'OU=Employees,OU=people,DC=corp,DC=pvt' '(CN=johndoe123)'
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <OU=Roles,OU=Groups,DC=corp,DC=pvt> with scope subtree
# filter: (member=CN=johndoe123,OU=Employees,OU=People,DC=corp,DC=pvt)
# requesting: cn OU=Employees,OU=people,DC=corp,DC=pvt (CN=johndoe123)
# with pagedResults control: size=100
#
# SiteReliability, Roles, Groups, corp.pvt
dn: CN=SiteReliability,OU=Roles,OU=Groups,DC=corp,DC=pvt
cn: SiteReliability
# All Employees, Roles, Groups, corp.pvt
dn: CN=All Employees,OU=Roles,OU=Groups,DC=corp,DC=pvt
cn: All Employees
# OS X Privileged, Roles, Groups, corp.pvt
dn: CN=OS X Privileged,OU=Roles,OU=Groups,DC=corp,DC=pvt
cn: OS X Privileged
# BEI_Manager, Roles, Groups, corp.pvt
dn: CN=BEI_Manager,OU=Roles,OU=Groups,DC=corp,DC=pvt
cn: BEI_Manager
# LIC_E3, Roles, Groups, corp.pvt
dn: CN=LIC_E3,OU=Roles,OU=Groups,DC=corp,DC=pvt
cn: LIC_E3
# search result
search: 2
result: 0 Success
control: 1.2.840.113556.1.4.319 false MIQAAAAFAgEABAA=
pagedresults: cookie=
@stecino Just add in one node and run securityadmin.sh.
The good habit is to first make a backup of the running security config with securitydadmin.sh script, make changes to the files and upload them back with the same script.
Regarding the mapping.
all_access:
reserved: true
backend_roles:
- admin
- App-Okta-OpenSearch-Admin
- SiteReliability <because you choose to read only CN in config.yml>
@stecino Could you try to create a test user and assign only a single LDAP group or none and try running the authinfo curl command?
Can I use the same user I use to bind to ldap?
@stecino Sure. Just test it with any LDAP user that has a few groups assigned or none.