elasticsearch-security-troubleshooting by elastic/agent-skills
npx skills add https://github.com/elastic/agent-skills --skill elasticsearch-security-troubleshooting诊断并解决常见的 Elasticsearch 安全问题。此技能提供结构化的分类工作流,用于处理身份验证失败、授权错误、TLS 问题、API 密钥问题、角色映射不匹配、Kibana 登录失败以及许可证过期锁定等问题。
关于身份验证方法和 API 密钥管理,请参阅 elasticsearch-authn 技能。关于角色、用户和角色映射,请参阅 elasticsearch-authz 技能。关于许可证管理,请参阅 elasticsearch-license 技能。
关于诊断 API 端点,请参阅 references/api-reference.md。
部署说明: 诊断 API 的可用性在自托管、ECH 和 Serverless 部署之间有所不同。详情请参阅部署兼容性部分。
| 项目 | 描述 |
|---|---|
| Elasticsearch URL | 集群端点(例如 https://localhost:9200 或 Cloud 部署 URL) |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 身份验证 | 任何有效的凭证——即使权限最小——只要能连接到集群 |
| 集群权限 | monitor 用于只读诊断;manage_security 用于修复 |
向用户询问任何缺失的值。如果用户完全无法进行身份验证,请从 TLS 和证书错误或许可证过期恢复开始。
根据症状引导至正确的部分:
| 症状 | 对应部分 |
|---|---|
HTTP 401, authentication_exception | 身份验证失败 |
HTTP 403, security_exception, 访问被拒绝 | 授权失败 |
| SSL/TLS 握手错误,证书被拒绝 | TLS 和证书错误 |
| API 密钥被拒绝、过期或无效 | API 密钥问题 |
| 角色映射未授予预期角色 | 角色映射问题 |
| Kibana 登录中断、重定向循环、CORS 错误 | Kibana 身份验证问题 |
| 所有用户被锁定,付费功能被禁用 | 许可证过期恢复 |
每个部分都遵循 收集 - 诊断 - 解决 的模式。
在任何安全调查开始时使用这些 API:
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate"
确认身份、领域和角色。如果此调用返回 401,则问题是身份验证。
curl <auth_flags> "${ELASTICSEARCH_URL}/_xpack"
确认安全功能是否启用(features.security.enabled)。如果安全功能被禁用,所有安全 API 都会返回错误。
curl -X POST "${ELASTICSEARCH_URL}/_security/user/_has_privileges" \
<auth_flags> \
-H "Content-Type: application/json" \
-d '{
"index": [
{ "names": ["'"${INDEX_PATTERN}"'"], "privileges": ["read"] }
]
}'
测试经过身份验证的用户是否拥有特定权限,而无需 manage_security 权限。
curl <auth_flags> "${ELASTICSEARCH_URL}/_license"
检查许可证类型和状态。过期的付费许可证会禁用付费领域和功能。
401 响应意味着 Elasticsearch 无法验证调用者的身份。
curl -v <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate" 2>&1
-v 标志显示响应头和响应体。查找:
WWW-Authenticate 响应头 —— 指示集群接受哪些身份验证方案。authentication_exception —— reason 字段描述了失败的原因。| 症状 | 可能原因 |
|---|---|
unable to authenticate user | 错误的用户名或密码 |
unable to authenticate with provided credentials | 凭证与领域链中的任何领域都不匹配 |
user is not enabled | 原生用户帐户被禁用 |
token is expired | API 密钥或承载令牌已过期 |
没有 WWW-Authenticate 响应头 | 安全功能可能被禁用;检查 GET /_xpack |
如果用户通过外部领域(LDAP、AD、SAML、OIDC)进行身份验证,领域链的顺序很重要。Elasticsearch 按配置顺序尝试各个领域,并在第一个匹配项处停止。如果更高优先级的领域在到达预期领域之前拒绝了凭证,则身份验证失败。
| 原因 | 操作 |
|---|---|
| 错误的凭证 | 验证用户名/密码或 API 密钥值。参见 elasticsearch-authn。 |
| 用户被禁用 | PUT /_security/user/{name}/_enable。参见 elasticsearch-authz。 |
| API 密钥过期 | 创建新的 API 密钥。参见 API 密钥问题。 |
| 领域链顺序 | 检查 elasticsearch.yml 中的领域顺序(仅限自托管)。 |
| 安全功能被禁用 | 在 elasticsearch.yml 中启用 xpack.security.enabled: true 并重启。 |
| 许可证过期后的付费领域 | 许可证已过期 —— 参见许可证过期恢复。 |
403 响应意味着用户已通过身份验证,但缺少所需的权限。
测试操作所需的特定权限:
curl -X POST "${ELASTICSEARCH_URL}/_security/user/_has_privileges" \
<auth_flags> \
-H "Content-Type: application/json" \
-d '{
"index": [
{ "names": ["logs-*"], "privileges": ["read", "view_index_metadata"] }
],
"cluster": ["monitor"]
}'
响应包含一个 has_all_requested 布尔值和每个资源的详细分解。
同时检查用户的有效角色:
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate"
检查 roles 数组和 authentication_realm 以确认用户身份符合预期。
| 症状 | 可能原因 |
|---|---|
索引的 has_all_requested: false | 角色缺少所需的索引权限 |
集群的 has_all_requested: false | 角色缺少所需的集群权限 |
| 用户的角色比预期的少 | 上次更新时角色数组被替换(而非合并) |
| API 密钥在先前允许的操作上返回 403 | API 密钥权限是快照 —— 创建后的角色更改不会传播到现有密钥 |
| 原因 | 操作 |
|---|---|
| 缺少索引权限 | 将权限添加到角色或创建新角色。参见 elasticsearch-authz。 |
| 缺少集群权限 | 添加集群权限。参见 elasticsearch-authz。 |
| 更新时角色被替换 | 先获取当前角色,然后用完整数组进行更新。参见 elasticsearch-authz。 |
| API 密钥权限过时 | 使用更新的 role_descriptors 创建新的 API 密钥。参见 elasticsearch-authn。 |
TLS 错误会完全阻止客户端建立连接。
curl -v --cacert "${CA_CERT}" "https://${ELASTICSEARCH_HOST}:9200/" 2>&1 | head -30
查找:
SSL certificate problem: unable to get local issuer certificate —— CA 不受信任。SSL certificate problem: certificate has expired —— 证书已过有效期。SSL: no alternative certificate subject name matches target host name —— 主机名不匹配。进行更深入的检查(仅限自托管):
openssl s_client -connect "${ELASTICSEARCH_HOST}:9200" -showcerts </dev/null 2>&1
这将显示完整的证书链、过期日期和主题备用名称。
| 错误信息 | 可能原因 |
|---|---|
unable to get local issuer certificate | 缺少或错误的 CA 证书 |
certificate has expired | 服务器或 CA 证书已过期 |
no alternative certificate subject name matches | 证书 SAN 不包含主机名 |
self-signed certificate | 自签名证书不在信任存储中 |
SSLHandshakeException (Java 客户端) | 信任存储缺少 CA 或密码错误 |
| 原因 | 操作 |
|---|---|
| 错误的 CA 证书 | 使用 --cacert 传递正确的 CA 或将其添加到系统信任存储。 |
| 证书过期 | 使用 elasticsearch-certutil 重新生成证书(自托管)。 |
| 主机名不匹配 | 使用正确的 SAN 条目重新生成证书。 |
| 自签名证书 | 将 CA 证书分发给所有客户端或使用公共受信任的 CA。 |
| 快速解决方法 | 使用 curl -k / --insecure 跳过验证。不适用于生产环境。 |
在 ECH 上,TLS 由 Elastic 管理 —— 证书错误通常表示客户端未使用正确的 Cloud 端点 URL。在 Serverless 上,TLS 完全由 Elastic 管理且对用户透明。
检索密钥的元数据:
curl "${ELASTICSEARCH_URL}/_security/api_key?name=${KEY_NAME}" <auth_flags>
检查响应中的 expiration、invalidated 和 role_descriptors。
| 症状 | 可能原因 |
|---|---|
| 使用密钥时返回 401 | 密钥已过期或已失效 |
| 在应允许的操作上返回 403 | 创建密钥时 role_descriptors 权限不足 |
| 派生密钥无访问权限 | API 密钥创建了另一个 API 密钥 —— 派生密钥没有权限 |
| 密钥对某些索引有效,对其他无效 | role_descriptors 范围太窄 |
| 原因 | 操作 |
|---|---|
| 密钥过期 | 创建具有适当 expiration 的新密钥。参见 elasticsearch-authn。 |
| 密钥失效 | 创建新密钥。失效的密钥无法恢复。 |
| 范围错误 | 使用正确的 role_descriptors 创建新密钥。参见 elasticsearch-authn。 |
| 派生密钥问题 | 使用用户凭证通过 POST /_security/api_key/grant 创建。参见 elasticsearch-authn。 |
角色映射将角色授予来自外部领域的用户。当它们静默失败时,用户可以通过身份验证但无法获得任何角色。
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate"
记录 username、authentication_realm.name 和 roles 数组。
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/role_mapping"
列出所有映射并检查其 rules 和 enabled 字段。
| 症状 | 可能原因 |
|---|---|
用户的 roles 数组为空 | 没有映射匹配用户的属性 |
| 用户获得错误的角色 | 不同的映射首先匹配或规则太宽泛 |
| 映射存在但不适用 | enabled 为 false |
| Mustache 模板产生错误的角色名 | 模板语法错误或意外的属性值 |
将用户的 authentication_realm.name 和 groups(来自 _authenticate)与每个映射的 rules 进行比较,以找出不匹配之处。
| 原因 | 操作 |
|---|---|
| 没有匹配的规则 | 更新映射规则以匹配用户的领域和属性。 |
| 映射被禁用 | 在映射上设置 "enabled": true。 |
| 模板错误 | 使用已知属性值测试 Mustache 模板。参见 elasticsearch-authz。 |
| 规则太宽泛 | 添加 all / except 条件以缩小匹配范围。参见 elasticsearch-authz。 |
kbn-xsrf 响应头所有修改 Kibana API 的请求都需要 kbn-xsrf 响应头:
curl -X PUT "${KIBANA_URL}/api/security/role/my-role" \
<auth_flags> \
-H "kbn-xsrf: true" \
-H "Content-Type: application/json" \
-d '{ ... }'
如果没有此响应头,Kibana 会返回 400 Bad Request 并提示 "Request must contain a kbn-xsrf header"。
常见原因:
elasticsearch.yml 中 xpack.security.authc.realms.saml.*.sp.acs 或 idp.metadata.path 配置不正确。server.publicBaseUrl 与 SAML ACS URL 不匹配。验证 SAML 领域配置:
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate"
如果此调用通过非 SAML 领域返回有效用户,则表示未到达 SAML 领域本身。检查领域链顺序。
Kibana 日志显示 Unable to retrieve version information from Elasticsearch nodes。验证 kibana.yml 中的 elasticsearch.hosts 设置指向可访问的端点,并且凭证(elasticsearch.username / elasticsearch.password 或 elasticsearch.serviceAccountToken)有效。
当付费许可证过期时,集群进入 security-closed 状态:付费领域(SAML、LDAP、AD、PKI)停止工作,通过它们进行身份验证的用户将被锁定。原生和文件领域仍可正常工作。
curl <auth_flags> "${ELASTICSEARCH_URL}/_license"
如果 license.status 是 "expired",则进行恢复。
按照 elasticsearch-license 技能中的详细恢复工作流进行操作。关键的第一步取决于部署类型:
| 部署类型 | 第一步 |
|---|---|
| 自托管 | 使用基于文件的用户(elasticsearch-users CLI)或原生用户登录。 |
| ECH | 联系 Elastic 支持或通过 Cloud 控制台续订。 |
| Serverless | 不适用 —— 许可证完全由 Elastic 管理。 |
症状: "我在搜索 logs-* 时收到 403。"
验证身份:
curl -u "joe:${PASSWORD}" "${ELASTICSEARCH_URL}/_security/_authenticate"
响应显示 "roles": ["viewer"]。
测试权限:
curl -X POST "${ELASTICSEARCH_URL}/_security/user/_has_privileges" \
-u "joe:${PASSWORD}" \
-H "Content-Type: application/json" \
-d '{"index": [{"names": ["logs-*"], "privileges": ["read"]}]}'
响应:"has_all_requested": false —— viewer 角色不包含对 logs-* 的 read 权限。
修复:创建一个 logs-reader 角色并将其分配给 Joe。参见 elasticsearch-authz。
症状: "我的 API 密钥从昨天开始返回 401。"
检查密钥:
curl -u "admin:${PASSWORD}" "${ELASTICSEARCH_URL}/_security/api_key?name=my-key"
响应显示 "expiration": 1709251200000 —— 密钥已过期。
修复:创建一个具有合适 expiration 的新 API 密钥。参见 elasticsearch-authn。
症状: "点击 Kibana 中的 SSO 按钮会重定向到错误页面。"
通过非 SAML 方法进行身份验证,检查 SAML 领域是否可达:
curl -u "elastic:${PASSWORD}" "${ELASTICSEARCH_URL}/_security/_authenticate"
验证 IdP 元数据 URL 是否可以从 Elasticsearch 节点访问(自托管):
curl -s "${IDP_METADATA_URL}" | head -5
检查时钟偏差 —— SAML 断言对时间敏感。确保所有节点都配置了 NTP。
验证 kibana.yml 中的 server.publicBaseUrl 是否与 IdP 中配置的 SAML ACS URL 匹配。
症状: "没有人能登录到 Kibana。我们使用 SAML。"
检查许可证:
curl -u "admin:${PASSWORD}" "${ELASTICSEARCH_URL}/_license"
响应显示 "status": "expired", "type": "platinum"。
SAML 领域因付费许可证过期而被禁用。按照 elasticsearch-license 中的恢复步骤操作:使用基于文件的用户或原生用户登录,然后上传续订的许可证或回退到基础版。
_authenticate 开始将 GET /_security/_authenticate 作为第一个诊断步骤运行。它在一个调用中揭示了用户的身份、领域、角色和身份验证类型。大多数问题仅从这个响应中就能变得明显。
在调查领域或权限问题之前,使用 GET /_license 验证许可证是否处于活动状态。过期的付费许可证会禁用领域和功能,产生类似于配置错误的症状。
_has_privileges与其阅读角色定义并在脑海中计算有效访问权限,不如使用 POST /_security/user/_has_privileges 直接测试特定权限。这更快,并且考虑了角色组合、DLS 和 FLS。
切勿在日常故障排除中使用内置的 elastic 超级用户。创建一个具有 manage_security 权限的专用管理员用户或 API 密钥。仅将 elastic 用户保留用于初始设置和紧急恢复。
使用 curl -k 或 --insecure 会跳过证书验证并掩盖真正的 TLS 问题。仅将其用于初始诊断,然后修复底层的证书问题。
诊断工具和 API 的可用性因部署类型而异。
| 工具 / API | 自托管 | ECH | Serverless |
|---|---|---|---|
_security/_authenticate | 是 | 是 | 是 |
_security/user/_has_privileges | 是 | 是 | 是 |
_xpack | 是 | 是 | 有限 |
_license | 是 | 是(只读) | 不可用 |
_security/api_key (GET) | 是 | 是 | 是 |
_security/role_mapping | 是 | 是 | 是 |
elasticsearch-users CLI | 是 | 不可用 | 不可用 |
节点上的 openssl s_client | 是 | 不可用 | 不可用 |
| Elasticsearch 日志 | 是 | 通过 Cloud UI | 通过 Cloud UI |
ECH 注意事项:
elasticsearch-users CLI 和直接的日志/证书检查不可用。Serverless 注意事项:
每周安装次数
140
代码仓库
GitHub 星标数
89
首次出现
11 天前
安全审计
安装于
cursor125
github-copilot118
opencode117
gemini-cli117
codex117
amp116
Diagnose and resolve common Elasticsearch security issues. This skill provides a structured triage workflow for authentication failures, authorization errors, TLS problems, API key issues, role mapping mismatches, Kibana login failures, and license-expiry lockouts.
For authentication methods and API key management, see the elasticsearch-authn skill. For roles, users, and role mappings, see the elasticsearch-authz skill. For license management, see the elasticsearch-license skill.
For diagnostic API endpoints, see references/api-reference.md.
Deployment note: Diagnostic API availability differs between self-managed, ECH, and Serverless. See Deployment Compatibility for details.
| Item | Description |
|---|---|
| Elasticsearch URL | Cluster endpoint (e.g. https://localhost:9200 or a Cloud deployment URL) |
| Authentication | Any valid credentials — even minimal — to reach the cluster |
| Cluster privileges | monitor for read-only diagnostics; manage_security for fixes |
Prompt the user for any missing values. If the user cannot authenticate at all, start with TLS and Certificate Errors or License Expiry Recovery.
Route the symptom to the correct section:
| Symptom | Section |
|---|---|
HTTP 401, authentication_exception | Authentication Failures |
HTTP 403, security_exception, access denied | Authorization Failures |
| SSL/TLS handshake error, certificate rejected | TLS and Certificate Errors |
| API key rejected, expired, or ineffective | API Key Issues |
| Role mapping not granting expected roles | Role Mapping Issues |
| Kibana login broken, redirect loop, CORS error | Kibana Authentication Issues |
| All users locked out, paid features disabled | License Expiry Recovery |
Each section follows a Gather - Diagnose - Resolve pattern.
Use these APIs at the start of any security investigation:
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate"
Confirms identity, realm, and roles. If this fails with 401, the problem is authentication.
curl <auth_flags> "${ELASTICSEARCH_URL}/_xpack"
Confirms whether security is enabled (features.security.enabled). If security is disabled, all security APIs return errors.
curl -X POST "${ELASTICSEARCH_URL}/_security/user/_has_privileges" \
<auth_flags> \
-H "Content-Type: application/json" \
-d '{
"index": [
{ "names": ["'"${INDEX_PATTERN}"'"], "privileges": ["read"] }
]
}'
Tests whether the authenticated user holds specific privileges without requiring manage_security.
curl <auth_flags> "${ELASTICSEARCH_URL}/_license"
Check license type and status. An expired paid license disables paid realms and features.
A 401 response means Elasticsearch could not verify the caller's identity.
curl -v <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate" 2>&1
The -v flag shows headers and the response body. Look for:
WWW-Authenticate header — indicates which auth schemes the cluster accepts.authentication_exception in the response body — the reason field describes what failed.| Symptom | Likely cause |
|---|---|
unable to authenticate user | Wrong username or password |
unable to authenticate with provided credentials | Credentials do not match any realm in the chain |
user is not enabled | The native user account is disabled |
token is expired | API key or bearer token has expired |
No WWW-Authenticate header | Security may be disabled; check GET /_xpack |
If the user authenticates via an external realm (LDAP, AD, SAML, OIDC), the realm chain order matters. Elasticsearch tries realms in configured order and stops at the first match. If a higher-priority realm rejects the credentials before the intended realm is reached, authentication fails.
| Cause | Action |
|---|---|
| Wrong credentials | Verify username/password or API key value. See elasticsearch-authn. |
| Disabled user | PUT /_security/user/{name}/_enable. See elasticsearch-authz. |
| Expired API key | Create a new API key. See API Key Issues. |
| Realm chain order | Check elasticsearch.yml realm order (self-managed only). |
| Security disabled | Enable xpack.security.enabled: true in elasticsearch.yml and restart. |
| Paid realm after expiry | License expired — see License Expiry Recovery. |
A 403 response means the user is authenticated but lacks the required privileges.
Test the specific privileges the operation requires:
curl -X POST "${ELASTICSEARCH_URL}/_security/user/_has_privileges" \
<auth_flags> \
-H "Content-Type: application/json" \
-d '{
"index": [
{ "names": ["logs-*"], "privileges": ["read", "view_index_metadata"] }
],
"cluster": ["monitor"]
}'
The response contains a has_all_requested boolean and per-resource breakdowns.
Also check the user's effective roles:
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate"
Inspect the roles array and authentication_realm to confirm the user is who you expect.
| Symptom | Likely cause |
|---|---|
has_all_requested: false for an index | Role is missing the required index privilege |
has_all_requested: false for a cluster | Role is missing the required cluster privilege |
| User has fewer roles than expected | Roles array was replaced (not merged) on last update |
| API key returns 403 on previously allowed | API key privileges are a snapshot — role changes after |
| operation | creation do not propagate to existing keys |
| Cause | Action |
|---|---|
| Missing index privilege | Add the privilege to the role or create a new role. See elasticsearch-authz. |
| Missing cluster privilege | Add the cluster privilege. See elasticsearch-authz. |
| Roles replaced on update | Fetch current roles first, then update with the full array. See elasticsearch-authz. |
| Stale API key privileges | Create a new API key with updated role_descriptors. See elasticsearch-authn. |
TLS errors prevent the client from establishing a connection at all.
curl -v --cacert "${CA_CERT}" "https://${ELASTICSEARCH_HOST}:9200/" 2>&1 | head -30
Look for:
SSL certificate problem: unable to get local issuer certificate — CA not trusted.SSL certificate problem: certificate has expired — certificate past its validity date.SSL: no alternative certificate subject name matches target host name — hostname mismatch.For deeper inspection (self-managed only):
openssl s_client -connect "${ELASTICSEARCH_HOST}:9200" -showcerts </dev/null 2>&1
This displays the full certificate chain, expiry dates, and subject alternative names.
| Error message | Likely cause |
|---|---|
unable to get local issuer certificate | Missing or wrong CA certificate |
certificate has expired | Server or CA certificate past expiry |
no alternative certificate subject name matches | Certificate SAN does not include the hostname |
self-signed certificate | Self-signed cert not in the trust store |
SSLHandshakeException (Java client) | Truststore missing the CA or wrong password |
| Cause | Action |
|---|---|
| Wrong CA cert | Pass the correct CA with --cacert or add it to the system trust store. |
| Expired certificate | Regenerate certificates with elasticsearch-certutil (self-managed). |
| Hostname mismatch | Regenerate the certificate with the correct SAN entries. |
| Self-signed cert | Distribute the CA cert to all clients or use a publicly trusted CA. |
| Quick workaround | Use curl -k / --insecure to skip verification. Not for production. |
On ECH, TLS is managed by Elastic — certificate errors usually indicate the client is not using the correct Cloud endpoint URL. On Serverless, TLS is fully managed and transparent.
Retrieve the key's metadata:
curl "${ELASTICSEARCH_URL}/_security/api_key?name=${KEY_NAME}" <auth_flags>
Check expiration, invalidated, and role_descriptors in the response.
| Symptom | Likely cause |
|---|---|
| 401 when using the key | Key expired or invalidated |
| 403 on operations that should be allowed | Key was created with insufficient role_descriptors |
| Derived key has no access | API key created another API key — derived keys have no privilege |
| Key works for some indices but not others | role_descriptors scope is too narrow |
| Cause | Action |
|---|---|
| Expired key | Create a new key with appropriate expiration. See elasticsearch-authn. |
| Invalidated key | Create a new key. Invalidated keys cannot be reinstated. |
| Wrong scope | Create a new key with correct role_descriptors. See elasticsearch-authn. |
| Derived key problem | Use POST /_security/api_key/grant with user credentials instead. See elasticsearch-authn. |
Role mappings grant roles to users from external realms. When they fail silently, users authenticate but get no roles.
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate"
Note the username, authentication_realm.name, and roles array.
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/role_mapping"
List all mappings and inspect their rules and enabled fields.
| Symptom | Likely cause |
|---|---|
User has empty roles array | No mapping matches the user's attributes |
| User gets wrong roles | A different mapping matched first or the rule is too broad |
| Mapping exists but does not apply | enabled is false |
| Mustache template produces wrong role name | Template syntax error or unexpected attribute value |
Compare the user's authentication_realm.name and groups (from _authenticate) against each mapping's rules to find the mismatch.
| Cause | Action |
|---|---|
| No matching rule | Update the mapping rules to match the user's realm and attributes. |
| Mapping disabled | Set "enabled": true on the mapping. |
| Template error | Test the Mustache template with known attribute values. See elasticsearch-authz. |
| Rule too broad | Add all / except conditions to narrow the match. See elasticsearch-authz. |
kbn-xsrf headerAll mutating Kibana API requests require the kbn-xsrf header:
curl -X PUT "${KIBANA_URL}/api/security/role/my-role" \
<auth_flags> \
-H "kbn-xsrf: true" \
-H "Content-Type: application/json" \
-d '{ ... }'
Without it, Kibana returns 400 Bad Request with "Request must contain a kbn-xsrf header".
Common causes:
xpack.security.authc.realms.saml.*.sp.acs or idp.metadata.path in elasticsearch.yml.server.publicBaseUrl does not match the SAML ACS URL.Verify the SAML realm configuration:
curl <auth_flags> "${ELASTICSEARCH_URL}/_security/_authenticate"
If this returns a valid user via a non-SAML realm, the SAML realm itself is not being reached. Check realm chain order.
Kibana logs Unable to retrieve version information from Elasticsearch nodes. Verify the elasticsearch.hosts setting in kibana.yml points to a reachable endpoint and the credentials (elasticsearch.username / elasticsearch.password or elasticsearch.serviceAccountToken) are valid.
When a paid license expires, the cluster enters a security-closed state: paid realms (SAML, LDAP, AD, PKI) stop working and users authenticating through them are locked out. Native and file realms remain functional.
curl <auth_flags> "${ELASTICSEARCH_URL}/_license"
If license.status is "expired", proceed with recovery.
Follow the detailed recovery workflow in the elasticsearch-license skill. The critical first step depends on deployment type:
| Deployment | First step |
|---|---|
| Self-managed | Log in with a file-based user (elasticsearch-users CLI) or native user. |
| ECH | Contact Elastic support or renew via the Cloud console. |
| Serverless | Not applicable — licensing is fully managed by Elastic. |
Symptom: "I get a 403 when searching logs-*."
curl -u "joe:${PASSWORD}" "${ELASTICSEARCH_URL}/_security/_authenticate"
Response shows "roles": ["viewer"].
curl -X POST "${ELASTICSEARCH_URL}/_security/user/_has_privileges" \
-u "joe:${PASSWORD}" \
-H "Content-Type: application/json" \
-d '{"index": [{"names": ["logs-*"], "privileges": ["read"]}]}'
Response: "has_all_requested": false — the viewer role does not include read on logs-*.
logs-reader role and assign it to Joe. See elasticsearch-authz.Symptom: "My API key returns 401 since yesterday."
curl -u "admin:${PASSWORD}" "${ELASTICSEARCH_URL}/_security/api_key?name=my-key"
Response shows "expiration": 1709251200000 — the key expired.
expiration. See elasticsearch-authn.Symptom: "Clicking the SSO button in Kibana redirects to an error page."
curl -u "elastic:${PASSWORD}" "${ELASTICSEARCH_URL}/_security/_authenticate"
curl -s "${IDP_METADATA_URL}" | head -5
server.publicBaseUrl in kibana.yml matches the SAML ACS URL configured in the IdP.Symptom: "Nobody can log in to Kibana. We use SAML."
curl -u "admin:${PASSWORD}" "${ELASTICSEARCH_URL}/_license"
Response shows "status": "expired", "type": "platinum".
_authenticateRun GET /_security/_authenticate as the first diagnostic step. It reveals the user's identity, realm, roles, and authentication type in a single call. Most issues become apparent from this response alone.
Before investigating realm or privilege issues, verify the license is active with GET /_license. An expired paid license disables realms and features, producing symptoms that mimic misconfiguration.
_has_privileges before manual inspectionInstead of reading role definitions and mentally computing effective access, use POST /_security/user/_has_privileges to test specific privileges directly. This is faster and accounts for role composition, DLS, and FLS.
Never use the built-in elastic superuser for day-to-day troubleshooting. Create a dedicated admin user or API key with manage_security privileges. Reserve the elastic user for initial setup and emergency recovery only.
Using curl -k or --insecure skips certificate verification and masks real TLS issues. Use it only for initial diagnosis, then fix the underlying certificate problem.
Diagnostic tool and API availability differs across deployment types.
| Tool / API | Self-managed | ECH | Serverless |
|---|---|---|---|
_security/_authenticate | Yes | Yes | Yes |
_security/user/_has_privileges | Yes | Yes | Yes |
_xpack | Yes | Yes | Limited |
_license | Yes | Yes (read) | Not available |
| (GET) |
ECH notes:
elasticsearch-users CLI and direct log/certificate inspection are not available.Serverless notes:
Weekly Installs
140
Repository
GitHub Stars
89
First Seen
11 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykFail
Installed on
cursor125
github-copilot118
opencode117
gemini-cli117
codex117
amp116
_security/api_key| Yes |
| Yes |
| Yes |
_security/role_mapping | Yes | Yes | Yes |
elasticsearch-users CLI | Yes | Not available | Not available |
openssl s_client on nodes | Yes | Not available | Not available |
| Elasticsearch logs | Yes | Via Cloud UI | Via Cloud UI |