📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

适用版本: 6.8-7.15

1. 错误异常的基本描述 #

Alias requests are not allowed for users who have field or document level security enabled 是 Elasticsearch 安全模块在检测到冲突操作时抛出的异常。当用户同时具备以下两个条件时触发:

  1. 该用户在某一个(或多个)索引上启用了字段级安全(FLS)文档级安全(DLS)
  2. 该用户尝试执行与**别名(alias)**相关的操作,例如查询、写入或通过别名执行搜索。

Elasticsearch 的安全设计规定:一旦对某个索引开启了 FLS/DLS,该索引的别名请求将被禁止,因为别名可能绕过已定义的安全过滤规则,从而造成数据泄露风险。

常见现象 #

  • 执行搜索、写入或别名管理请求时,返回 HTTP 400 Bad Request
  • 客户端收到如下错误信息:
    {
      "error": {
        "root_cause": [
          {
            "type": "security_exception",
            "reason": "Alias requests are not allowed for users who have field or document level security enabled on one of the indices"
          }
        ],
        "type": "security_exception",
        "reason": "Alias requests are not allowed for users who have field or document level security enabled on one of the indices"
      },
      "status": 400
    }
    
  • 应用日志中出现 security_exception 且包含 Alias requests are not allowed 关键字。
  • 仅影响启用了 FLS/DLS 的用户,不影响具备完整索引权限的管理员用户。

典型报错与异常栈 #

ElasticsearchSecurityException: Alias requests are not allowed for users who have field or
document level security enabled on one of the indices
    at org.elasticsearch.xpack.security.support.SecurityIndexAuditTrail.onFailure(SecurityIndexAuditTrail.java)
    at org.elasticsearch.xpack.security.action.filter.SecurityActionFilter.applyFlsDls(SecurityActionFilter.java)
    at org.elasticsearch.xpack.security.action.filter.SecurityActionFilter.checkAliasAction(SecurityActionFilter.java)

2. 为什么会发生这个错误 #

Elasticsearch 的字段级安全(FLS)和文档级安全(DLS)通过重写查询来限制用户可见的数据范围。然而,别名(alias)本质上是一个间接引用,在查询解析阶段,别名会被解析为实际索引名。如果允许 FLS/DLS 用户通过别名访问索引,攻击者可能通过构造别名操作绕过安全过滤。

具体触发场景包括:

  • 场景一:用户通过角色配置对索引 app-logs-* 启用了 DLS({"term": {"env": "prod"}}),随后尝试通过别名 app-logs 执行搜索。
  • 场景二:用户配置了 FLS,仅允许访问 nameemail 字段,却通过别名发起聚合查询,试图访问被屏蔽的字段。
  • 场景三:在 Kibana 或应用中使用了别名作为查询目标,而底层索引恰好被 FLS/DLS 覆盖。

常见原因总结:

  • 用户角色中同时配置了 FLS/DLS 和别名访问权限,两者互斥。
  • 应用层使用别名作为统一查询入口,但未考虑安全策略限制。
  • 索引迁移或重构后,新增了安全策略,但客户端仍通过旧别名访问。

3. 如何排查这个异常 #

建议按以下步骤定位问题:

步骤一:确认报错用户及其角色 #

# 查看当前用户绑定的角色
GET /_security/user/<username>

# 查看角色详情,重点关注 indices 权限配置
GET /_security/role/<role_name>

检查返回结果中是否存在 field_securityquery 字段:

{
  "app_user": {
    "indices": [
      {
        "names": ["app-logs-*"],
        "privileges": ["read"],
        "field_security": {
          "grant": ["timestamp", "level", "message"]
        },
        "query": "{\"term\": {\"env\": \"prod\"}}"
      }
    ]
  }
}

步骤二:确认请求中是否使用了别名 #

检查应用代码或请求体,确认目标索引是否为别名:

# 查看别名与实际索引的映射关系
GET /_cat/aliases/<alias_name>?v

# 或使用
GET /<alias_name>/_alias

步骤三:验证 FLS/DLS 与别名的冲突 #

如果角色配置了 FLS/DLS,且请求目标包含别名,则冲突必然触发。可通过以下方式验证:

# 直接查询实际索引名(绕过别名),验证是否正常工作
GET /app-logs-2024-01/_search
{
  "query": { "match_all": {} }
}

4. 如何解决这个错误 #

方案一:绕过别名,直接访问实际索引 #

修改应用代码或查询请求,将别名替换为实际索引名(或索引模式):

# 修改前(会报错)
GET /app-logs/_search

# 修改后(直接指定索引模式)
GET /app-logs-*/_search

注意:此方法适用于索引命名规范统一、可通过通配符覆盖的场景。

方案二:调整角色配置,移除 FLS/DLS 限制 #

如果该用户确实需要访问别名,且数据安全要求允许,可移除对应索引的 FLS/DLS 配置:

# 更新角色,移除字段级安全限制
PUT /_security/role/app_user
{
  "indices": [
    {
      "names": ["app-logs-*"],
      "privileges": ["read"]
    }
  ]
}

警告:此方案会降低数据安全性,仅在确认无数据泄露风险时使用。

方案三:为不同用户创建独立角色 #

将需要别名访问的用户与需要 FLS/DLS 的用户分离,分别创建角色:

# 角色 A:仅用于别名访问,不配置 FLS/DLS
PUT /_security/role/app_user_alias
{
  "indices": [
    {
      "names": ["app-logs"],
      "privileges": ["read"]
    }
  ]
}

# 角色 B:用于直接索引访问,配置 FLS/DLS
PUT /_security/role/app_user_secure
{
  "indices": [
    {
      "names": ["app-logs-*"],
      "privileges": ["read"],
      "field_security": {
        "grant": ["timestamp", "level", "message"]
      }
    }
  ]
}

方案四:使用 INFINI Gateway 做请求重写 #

通过 INFINI Gateway 拦截请求,在网关层将别名自动重写为实际索引名,从而绕过 Elasticsearch 的安全限制:

# INFINI Gateway 请求重写示例配置
entry:
  - name: es-entry
    enabled: true
    router: rewrite-router

router:
  - name: rewrite-router
    rules:
      - method: GET
        pattern: "/app-logs/_search"
        rewrite: "/app-logs-*/_search"

5. 预防建议与最佳实践 #

  • 统一索引访问规范:在启用 FLS/DLS 的集群中,建议应用层统一使用索引模式(如 logs-*)而非别名,避免触发此限制。
  • 角色设计最小化:为每个用户或应用创建最小权限角色,避免一个角色同时覆盖 FLS/DLS 和别名访问场景。
  • 在测试环境验证安全策略:每次调整角色或索引结构后,在测试环境模拟真实请求,提前发现 FLS/DLS 与别名的冲突。
  • 使用 INFINI Console 监控安全异常INFINI Console 可集中展示 Elasticsearch 安全异常趋势,帮助快速定位受影响的用户和索引。
  • 文档化索引命名与访问规则:将哪些索引使用别名、哪些启用了 FLS/DLS 记录在运维文档中,减少后续配置冲突。

6. 小结 #

Alias requests are not allowed 是 Elasticsearch 安全模块的一种保护机制,防止 FLS/DLS 规则被别名绕过。解决此问题的核心思路是:要么移除 FLS/DLS 限制,要么避免使用别名访问。在实际生产环境中,推荐通过角色分离或网关层请求重写来兼顾安全性与访问灵活性。

相关错误 #

附:源码上下文 #

以下为触发此异常的 Elasticsearch 安全模块核心代码片段,便于深入理解其判断逻辑:

indicesAccessControl.getIndexPermissions(index);

if (indexAccessControl != null) {
    final boolean fls = indexAccessControl.getFieldPermissions().hasFieldLevelSecurity();
    final boolean dls = indexAccessControl.getDocumentPermissions().hasDocumentLevelPermissions();
    if ((fls || dls) && licenseChecker.get()) {
        listener.onFailure(new ElasticsearchSecurityException(
            "Alias requests are not allowed for users who have field or document level security " +
            "enabled on one of the indices",
            RestStatus.BAD_REQUEST
        ));
        return;
    }
}