4、跨集群搜索的权限控制:跨集群搜索的用户权限、角色配置、安全最佳实践

跨集群搜索这个功能,说白了就是把多个 Elasticsearch 集群的数据拉到一起查。但问题来了——你总不能让人随便查吧?权限控制搞不好,数据泄露就是分分钟的事。我刚开始做跨集群搜索时,就吃过这个亏,后面慢慢摸索出一套比较稳妥的做法。

4.1 跨集群搜索的权限模型

先理清一个概念。跨集群搜索涉及两个角色:

  • 本地集群:你发起查询的那个集群
  • 远程集群:被查询的那个集群

权限控制要管两头。本地集群要控制「谁能发起跨集群查询」,远程集群要控制「允许谁查哪些索引」。嗯,这里要注意,两个集群的安全配置是独立的,但必须协同工作。

核心原则:最小权限原则。只给查询所需的索引权限,不要给全部。

4.2 用户权限配置实战

假设我有两个集群:cluster-a(本地)和 cluster-b(远程)。我想让 cluster-a 上的用户 search_user 能查询 cluster-b 的 logs-* 索引。

4.2.1 远程集群(cluster-b)的配置

首先,在 cluster-b 上创建一个角色,专门给跨集群搜索用:

PUT /_security/role/remote_search_role
{
  "cluster": ["cross_cluster_search"],
  "indices": [
    {
      "names": ["logs-*"],
      "privileges": ["read", "read_cross_cluster"]
    }
  ]
}

然后创建用户并分配这个角色:

POST /_security/user/remote_search_user
{
  "password": "StrongPassword123!",
  "roles": ["remote_search_role"],
  "full_name": "Remote Search User"
}

我个人习惯把这种专用用户的名字起得明确一点,比如 ccs_user_prod,一看就知道是干跨集群搜索用的。

4.2.2 本地集群(cluster-a)的配置

在 cluster-a 上,你需要配置远程集群的连接信息,并且给本地用户分配相应的权限:

PUT /_cluster/settings
{
  "persistent": {
    "search.remote": {
      "cluster-b": {
        "seeds": ["cluster-b-node1:9300", "cluster-b-node2:9300"]
      }
    }
  }
}

然后创建本地用户,并赋予它使用远程集群的权限:

PUT /_security/role/local_search_role
{
  "indices": [
    {
      "names": ["*"],
      "privileges": ["read"]
    }
  ],
  "cluster": [
    "cross_cluster_search"
  ]
}

POST /_security/user/search_user
{
  "password": "AnotherStrongPass!",
  "roles": ["local_search_role"]
}

小技巧:本地集群的 cross_cluster_search 集群权限是必须的,否则用户连发起跨集群查询的资格都没有。

4.3 角色配置的进阶玩法

你想想看,如果远程集群有几十个索引,难道每个都要列出来?当然不是。Elasticsearch 支持通配符和索引模板,可以批量控制。

4.3.1 使用索引模板控制权限

PUT /_security/role/advanced_remote_role
{
  "indices": [
    {
      "names": ["logs-*", "metrics-*", "app-*-prod"],
      "privileges": ["read", "read_cross_cluster"]
    }
  ],
  "run_as": ["ccs_user_prod"]
}

这里我用了 run_as 功能。什么意思呢?就是本地用户可以用 ccs_user_prod 的身份去查询远程集群。我在项目中遇到过一种场景:多个团队共享一个远程集群,每个团队只能查自己的索引。用 run_as 就能做到精细隔离。

4.3.2 限制查询范围

有时候你不想让用户查全部字段,可以这样:

PUT /_security/role/restricted_remote_role
{
  "indices": [
    {
      "names": ["logs-*"],
      "privileges": ["read", "read_cross_cluster"],
      "field_security": {
        "grant": ["@timestamp", "level", "message", "service.name"],
        "except": ["password", "token", "secret"]
      }
    }
  ]
}

说白了,就是只让用户看到业务需要的字段,敏感字段直接屏蔽掉。我曾经因为没做字段级权限控制,导致一个测试账号查到了生产环境的密钥——嗯,那次之后我就再也不敢偷懒了。

4.4 安全最佳实践

光配置权限还不够,运维层面也得跟上。我总结了几条经验:

实践项 说明 我的建议
使用 TLS 加密 跨集群通信必须加密 别用明文传输,哪怕在内网
专用用户 不要用 admin 账号做跨集群搜索 创建只读专用用户,权限最小化
审计日志 记录谁在什么时候查了什么 开启 audit log,出事好追溯
定期轮换密码 远程用户的密码要定期更换 配合密钥管理工具自动轮换
网络隔离 只开放必要的端口和 IP 用防火墙限制远程集群的访问来源

警告:千万不要把远程集群的 elastic 超级用户密码写在本地集群的配置文件中。我见过有人这么干,结果本地集群被攻破后,远程集群也跟着沦陷了。

4.5 避坑指南

最后分享几个我踩过的坑:

  • 证书过期:跨集群搜索用 TLS 时,证书过期会导致查询失败。我曾经半夜被叫起来处理过这事。建议设置证书过期告警。
  • 角色缓存:修改角色后,有时不会立即生效。可以调用 POST /_security/role/{name}/_clear_cache 手动清除缓存。
  • 版本兼容:跨集群搜索要求两个集群的主版本号一致。比如 7.x 可以查 7.x,但 7.x 查 6.x 就不行。升级前一定要确认。
  • 索引名冲突:如果本地和远程都有同名的索引,查询时要用 cluster-b:logs-2024 这种格式指定集群。否则可能查到本地数据。

嗯,权限控制这块其实不难,但细节很多。你只要记住一个原则:给最少的权限,做最全的审计。这样即使出了问题,也能快速定位和修复。

总结:跨集群搜索的权限控制,核心是「本地控制发起权,远程控制查询范围」。配合 TLS、专用用户、审计日志,基本就能做到安全可控。