ELK Stack — LDAP and SAML
LDAP and SAML
Enterprise environments rarely manage users directly in Elasticsearch. Instead, they integrate with external identity providers — LDAP (Lightweight Directory Access Protocol), Active Directory, or SAML (Security Assertion Markup Language) for single sign-on.
Elasticsearch supports these through a realm chain — an ordered list of authentication backends that Elasticsearch consults when a user attempts to authenticate.
The Realm Chain
When a user authenticates, Elasticsearch checks each realm in order until one successfully authenticates the user:
Request → native realm → file realm → LDAP realm → SAML realm → reject
Realm order matters — place the most commonly used realm first for performance.
Default realms (always active):
| Realm | Type | Priority |
|---|---|---|
| Reserved | reserved |
0 (internal users like elastic) |
| Native | native |
Built-in user store (via API) |
| File | file |
Users defined in users file on disk |
Native Realm
The native realm stores users in an internal Elasticsearch index. This is the default realm for users created via the API or Kibana.
# Create a user in the native realm
curl -k -u elastic:password -X POST "https://localhost:9200/_security/user/analyst_1" \
-H "Content-Type: application/json" -d'
{
"password": "SecurePassword!",
"roles": ["viewer"],
"full_name": "Analyst One"
}'
No additional configuration is needed — the native realm is enabled by default.
File Realm
The file realm stores credentials in flat files on each Elasticsearch node. It is useful for emergency access when the cluster is degraded.
Add users to /etc/elasticsearch/users:
/usr/share/elasticsearch/bin/elasticsearch-users useradd admin_backup \
-p EmergencyPassword123! \
-r superuser
File realm users are available immediately without a cluster restart. The files are:
/etc/elasticsearch/users— username and hashed password/etc/elasticsearch/users_roles— role assignments
LDAP Realm Configuration
Basic LDAP Configuration
# /etc/elasticsearch/elasticsearch.yml
xpack.security.authc.realms.ldap.ldap1:
order: 2
url: "ldaps://ldap.example.com:636"
bind.dn: "cn=elasticsearch,ou=services,dc=example,dc=com"
user_search.base_dn: "ou=users,dc=example,dc=com"
user_search.filter: "(uid={0})"
group_search.base_dn: "ou=groups,dc=example,dc=com"
ssl.certificate_authorities: ["/etc/elasticsearch/certs/ldap-ca.crt"]
unmapped_groups_as_roles: false
Store the bind password in the Elasticsearch keystore:
/usr/share/elasticsearch/bin/elasticsearch-keystore add \
xpack.security.authc.realms.ldap.ldap1.secure_bind_password
LDAP with User Templates (No Bind DN)
If your LDAP uses a predictable DN pattern, you can skip the bind search:
xpack.security.authc.realms.ldap.ldap1:
order: 2
url: "ldaps://ldap.example.com:636"
user_dn_templates:
- "uid={0},ou=users,dc=example,dc=com"
- "uid={0},ou=contractors,dc=example,dc=com"
group_search.base_dn: "ou=groups,dc=example,dc=com"
ssl.certificate_authorities: ["/etc/elasticsearch/certs/ldap-ca.crt"]
LDAP with Multiple Servers (Failover)
xpack.security.authc.realms.ldap.ldap1:
order: 2
url:
- "ldaps://ldap-primary.example.com:636"
- "ldaps://ldap-secondary.example.com:636"
load_balance.type: "failover"
bind.dn: "cn=elasticsearch,ou=services,dc=example,dc=com"
user_search.base_dn: "ou=users,dc=example,dc=com"
user_search.filter: "(sAMAccountName={0})"
group_search.base_dn: "ou=groups,dc=example,dc=com"
ssl.certificate_authorities: ["/etc/elasticsearch/certs/ldap-ca.crt"]
Active Directory Realm
Active Directory has its own dedicated realm type with AD-specific defaults:
# /etc/elasticsearch/elasticsearch.yml
xpack.security.authc.realms.active_directory.ad1:
order: 3
url: "ldaps://ad.example.com:636"
domain_name: "example.com"
bind.dn: "CN=elasticsearch,OU=Services,DC=example,DC=com"
ssl.certificate_authorities: ["/etc/elasticsearch/certs/ad-ca.crt"]
Store the bind password:
/usr/share/elasticsearch/bin/elasticsearch-keystore add \
xpack.security.authc.realms.active_directory.ad1.secure_bind_password
Role Mapping for External Authentication
After configuring LDAP or AD, map external groups to Elasticsearch roles:
# Map LDAP admins group to superuser
curl -k -u elastic:password -X POST "https://localhost:9200/_security/role_mapping/ldap_admins" \
-H "Content-Type: application/json" -d'
{
"enabled": true,
"roles": ["superuser"],
"rules": {
"all": [
{ "field": { "realm.name": "ldap1" } },
{ "field": { "groups": "cn=es-admins,ou=groups,dc=example,dc=com" } }
]
}
}'
# Map developers to editor role
curl -k -u elastic:password -X POST "https://localhost:9200/_security/role_mapping/ldap_developers" \
-H "Content-Type: application/json" -d'
{
"enabled": true,
"roles": ["editor"],
"rules": {
"all": [
{ "field": { "realm.name": "ldap1" } },
{ "field": { "groups": "cn=developers,ou=groups,dc=example,dc=com" } }
]
}
}'
# Map analysts to a custom viewer role
curl -k -u elastic:password -X POST "https://localhost:9200/_security/role_mapping/ldap_analysts" \
-H "Content-Type: application/json" -d'
{
"enabled": true,
"roles": ["log_viewer", "monitoring_user"],
"rules": {
"all": [
{ "field": { "realm.name": "ldap1" } },
{ "field": { "groups": "cn=analysts,ou=groups,dc=example,dc=com" } }
]
}
}'
SAML Realm for SSO
SAML enables single sign-on through identity providers like Okta, Azure AD, or OneLogin.
SAML Configuration in Elasticsearch
# /etc/elasticsearch/elasticsearch.yml
xpack.security.authc.realms.saml.saml1:
order: 4
idp.metadata.path: "/etc/elasticsearch/saml/idp-metadata.xml"
idp.entity_id: "https://idp.example.com/"
sp.entity_id: "https://kibana.example.com/"
sp.acs: "https://kibana.example.com/api/security/saml/callback"
sp.logout: "https://kibana.example.com/logout"
attributes.principal: "nameid"
attributes.groups: "groups"
attributes.name: "displayName"
attributes.mail: "email"
Downloading IdP Metadata
Most identity providers expose metadata at a URL:
# Download Okta metadata
curl -o /etc/elasticsearch/saml/idp-metadata.xml \
"https://your-org.okta.com/app/abc123/sso/saml/metadata"
# Download Azure AD metadata
curl -o /etc/elasticsearch/saml/idp-metadata.xml \
"https://login.microsoftonline.com/<tenant-id>/federationmetadata/2007-06/federationmetadata.xml"
Configuring Kibana for SAML Login
# /etc/kibana/kibana.yml
xpack.security.authc.providers:
saml.saml1:
order: 0
realm: "saml1"
description: "Log in with SSO"
basic.basic1:
order: 1
description: "Log in with username/password"
This configures Kibana to show both SAML and basic login options. The SAML option appears first.
SAML Role Mapping
curl -k -u elastic:password -X POST "https://localhost:9200/_security/role_mapping/saml_admins" \
-H "Content-Type: application/json" -d'
{
"enabled": true,
"roles": ["kibana_admin", "monitoring_user"],
"rules": {
"all": [
{ "field": { "realm.name": "saml1" } },
{ "field": { "groups": "elk-admins" } }
]
}
}'
OIDC Realm Overview
OpenID Connect (OIDC) is an alternative to SAML, commonly used with providers like Google, Auth0, and Keycloak.
# /etc/elasticsearch/elasticsearch.yml
xpack.security.authc.realms.oidc.oidc1:
order: 5
rp.client_id: "elasticsearch-client"
rp.response_type: "code"
rp.redirect_uri: "https://kibana.example.com/api/security/oidc/callback"
op.issuer: "https://auth.example.com/"
op.authorization_endpoint: "https://auth.example.com/authorize"
op.token_endpoint: "https://auth.example.com/oauth/token"
op.userinfo_endpoint: "https://auth.example.com/userinfo"
op.jwkset_path: "https://auth.example.com/.well-known/jwks.json"
claims.principal: "sub"
claims.groups: "groups"
Store the client secret:
/usr/share/elasticsearch/bin/elasticsearch-keystore add \
xpack.security.authc.realms.oidc.oidc1.rp.client_secret
Realm Ordering
The order in which realms are checked affects performance and behavior. Recommended ordering:
# /etc/elasticsearch/elasticsearch.yml
xpack.security.authc.realms:
native.native1:
order: 0
file.file1:
order: 1
ldap.ldap1:
order: 2
active_directory.ad1:
order: 3
saml.saml1:
order: 4
oidc.oidc1:
order: 5
Best Practice: Place
nativeandfilerealms first — they are fast local lookups. External realms (LDAP, SAML) involve network calls and should come later.
Quick Reference
| Task | Configuration / API |
|---|---|
| LDAP realm | xpack.security.authc.realms.ldap.<name> in elasticsearch.yml |
| Active Directory realm | xpack.security.authc.realms.active_directory.<name> |
| SAML realm | xpack.security.authc.realms.saml.<name> |
| OIDC realm | xpack.security.authc.realms.oidc.<name> |
| Store bind password | elasticsearch-keystore add xpack.security.authc.realms.ldap.<name>.secure_bind_password |
| Kibana SAML config | xpack.security.authc.providers.saml.<name> in kibana.yml |
| Role mapping | POST /_security/role_mapping/<name> |
| File realm users | elasticsearch-users useradd <user> -p <pass> -r <role> |
| Download IdP metadata | curl -o idp-metadata.xml <metadata-url> |
| Realm order | order: N (lower = checked first) |
Next: Security Exercises — hands-on practice with everything you’ve learned.