Elasticsearch API访问权限控制:禁用外部端点访问

发布于:2025-06-24 ⋅ 阅读:(17) ⋅ 点赞:(0)

背景与需求

在实际的生产环境中,我们经常遇到这样的需求:

  • Elasticsearch需要对外提供基本的API服务
  • 内部系统(如Grafana)需要完整的ES访问权限
  • 但要禁用某些敏感的API端点(如/_cat)防止信息泄露

本文记录了在Docker部署的Elasticsearch中实现这种细粒度权限控制的完整过程,包括遇到的各种坑点和解决方案。

环境信息

  • 操作系统: Ubuntu 服务器
  • Elasticsearch: 8.17.0 (Docker部署)
  • Grafana: 需要访问ES的完整功能
  • 目标: 禁用外部对/_cat API的访问,保留其他功能

方案对比

方案一:修改网络配置(不推荐)

最初尝试通过修改ES的网络配置来限制访问:

network.host: 127.0.0.1
http.host: 127.0.0.1

踩坑点:这种方案会完全禁用外部访问,包括Grafana也无法访问,不符合需求。

方案二:使用nginx代理

通过nginx反向代理实现精确的端点控制。(太麻烦不想做)

方案三:ES原生安全功能(推荐)

使用Elasticsearch的X-Pack Security功能,通过角色和权限实现细粒度控制。

经过对比,方案三最为优雅,既充分利用了ES的原生安全机制,又便于管理和维护。

实施步骤详解

第一步:确认当前ES部署方式

首先检查ES容器的部署情况:

# 查看ES容器
sudo docker ps | grep elasticsearch

# 查看原始启动命令(重要!)
docker inspect es | grep -A 20 "Cmd"

踩坑点1:发现原启动命令中有 -e "xpack.security.enabled=false",这会强制禁用安全功能。

第二步:数据安全确认

在重建容器前,确认数据不会丢失:

# 检查数据挂载
ls -la /srv/elasticsearch/data/
du -sh /srv/elasticsearch/data/

# 确认数据大小和内容
docker exec es curl -s http://127.0.0.1:9200/_cat/indices

踩坑点2:很多人担心重建容器会丢失数据。实际上,由于使用了数据卷挂载 (-v /srv/elasticsearch/data:/usr/share/elasticsearch/data),数据存储在主机上,重建容器不会影响数据。

第三步:配置ES安全功能

3.1 修改配置文件
vi /srv/elasticsearch/config/elasticsearch.yml
cluster.name: es-docker-cluster
node.name: single-node
path.data: /usr/share/elasticsearch/data
path.logs: /usr/share/elasticsearch/logs
discovery.type: single-node
bootstrap.memory_lock: true
network.host: 0.0.0.0
http.host: 0.0.0.0

# 启用X-Pack安全功能
xpack.security.enabled: true
xpack.security.enrollment.enabled: false
xpack.security.authc.api_key.enabled: true

# 禁用SSL(简化配置,生产环境建议启用)
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: false
3.2 重建容器
# 停止并删除容器
docker stop es
docker rm es

# 重新运行with安全功能
docker run -itd --restart always --name es \
  -p 9200:9200 \
  -p 9300:9300 \
  -e "ES_JAVA_OPTS=-Xms4g -Xmx4g" \
  -e "ELASTIC_PASSWORD=YourStrongPassword123" \
  -v /srv/elasticsearch/data:/usr/share/elasticsearch/data \
  -v /srv/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro \
  docker.elastic.co/elasticsearch/elasticsearch:8.17.0

踩坑点3:配置文件挂载使用了:ro(只读)模式,所以无法在容器内直接修改配置文件。必须在主机上修改。

第四步:创建角色和权限

4.1 为Grafana创建超级用户角色
curl -X POST "http://elastic:YourStrongPassword123@10.6.110.86:9200/_security/role/grafana_superuser" \
-H "Content-Type: application/json" -d'
{
  "cluster": ["all"],
  "indices": [
    {
      "names": ["*"],
      "privileges": ["all"]
    }
  ],
  "applications": [
    {
      "application": "*",
      "privileges": ["*"],
      "resources": ["*"]
    }
  ]
}'

4.2 创建受限角色(无cat权限)
curl -X POST "http://elastic:YourStrongPassword123@10.6.110.86:9200/_security/role/external_limited" \
-H "Content-Type: application/json" -d'
{
  "cluster": [],
  "indices": [
    {
      "names": ["*"],
      "privileges": ["read", "view_index_metadata"]
    }
  ]
}'

第五步:API Key认证尝试与踩坑

5.1 创建API Key
curl -X POST "http://elastic:YourStrongPassword123@10.6.110.86:9200/_security/api_key" \
-H "Content-Type: application/json" -d'
{
  "name": "grafana-full-access",
  "expiration": "365d",
  "role_descriptors": {
    "grafana_access": {
      "cluster": ["all"],
      "indices": [
        {
          "names": ["*"],
          "privileges": ["all"]
        }
      ]
    }
  }
}'

返回结果示例:

{
  "id":"U6mEm5cB7ZDEudMvimns",
  "name":"grafana-full-access",
  "api_key":"Ik4YfdYTS1yGnidQaKXC9g",
  "encoded":"VTZtRW01Y0I3WkRFdWRNdmltbnM6SWs0WWZkWVRTMXlHbmlkUWFLWEM5Zw=="
}

踩坑点4:很多人错误地使用api_key字段,实际应该使用encoded字段。

# 错误用法
curl -H "Authorization: ApiKey Ik4YfdYTS1yGnidQaKXC9g" http://10.6.110.86:9200/

# 正确用法  
curl -H "Authorization: ApiKey VTZtRW01Y0I3WkRFdWRNdmltbnM6SWs0WWZkWVRTMXlHbmlkUWFLWEM5Zw==" http://10.6.110.86:9200/
5.2 Grafana集成踩坑

踩坑点5:发现Grafana的Basic Auth无法直接使用API Key。

# 这种方式不工作
curl -u api_key:VTZtRW01Y0I3WkRFdWRNdmltbnM6SWs0WWZkWVRTMXlHbmlkUWFLWEM5Zw== http://10.6.110.86:9200/
# 返回401错误

第六步:最终解决方案 - 用户名密码认证

由于Grafana的限制,最终采用传统的用户名密码认证:

6.1 创建Grafana专用用户
curl -X POST "http://elastic:YourStrongPassword123@10.6.110.86:9200/_security/user/grafana_user" \
-H "Content-Type: application/json" -d'
{
  "password": "GrafanaPassword123",
  "roles": ["grafana_superuser"],
  "full_name": "Grafana Service User",
  "metadata": {
    "application": "grafana"
  }
}'

6.2 验证用户权限
# 测试Grafana用户的完整权限
curl -u grafana_user:GrafanaPassword123 http://10.6.110.86:9200/
curl -u grafana_user:GrafanaPassword123 http://10.6.110.86:9200/_cat/health

# 测试受限API Key
curl -H "Authorization: ApiKey LIMITED_API_KEY" http://10.6.110.86:9200/_cat/health
# 应该返回403权限不足

配置管理

密码修改

# 修改用户密码
curl -X POST "http://elastic:YourStrongPassword123@10.6.110.86:9200/_security/user/grafana_user/_password" \
-H "Content-Type: application/json" -d'
{
  "password": "NewPassword456"
}'

Grafana数据源配置

在Grafana中配置:

  • URLhttp://10.6.110.86:9200
  • Access: Server (default)
  • Auth: ✅ Basic Auth
  • Usergrafana_user
  • PasswordGrafanaPassword123

最终架构与验证

权限矩阵

用户类型 基本API _cat API _search API 集群管理
elastic (超级管理员)
grafana_user
受限API Key
无认证用户

完整验证脚本

#!/bin/bash

echo "=== 1. 测试Grafana用户(应该全部成功) ==="
curl -u grafana_user:GrafanaPassword123 http://10.6.110.86:9200/
curl -u grafana_user:GrafanaPassword123 http://10.6.110.86:9200/_cat/health

echo "=== 2. 测试受限API Key(cat应该失败) ==="
LIMITED_KEY="VmFtSG01Y0I3WkRFdWRNdkpHbXg6NFYtSEJtdWpUTXkwQ3NDSmRPdmF0Zw=="
curl -H "Authorization: ApiKey $LIMITED_KEY" http://10.6.110.86:9200/
curl -H "Authorization: ApiKey $LIMITED_KEY" http://10.6.110.86:9200/_cat/health

echo "=== 3. 测试无认证访问(应该全部失败) ==="
curl http://10.6.110.86:9200/
curl http://10.6.110.86:9200/_cat/health

​​​​​​​

总结与最佳实践

主要踩坑点总结

  1. 容器重建数据安全性:使用数据卷挂载的容器重建不会丢失数据
  2. 配置文件只读挂载:无法在容器内修改配置,必须在主机上操作
  3. API Key使用方式:必须使用encoded字段,不是api_key字段
  4. Grafana认证限制:Basic Auth无法直接使用API Key,需要创建用户
  5. 权限配置细节:角色权限需要精确配置,避免意外的权限泄露

最佳实践建议

  1. 分层权限设计

    • 超级管理员:完全权限
    • 应用服务:必要权限
    • 外部用户:最小权限
  2. 密码安全管理

    • 使用强密码
    • 定期轮换密码
    • 考虑使用密钥管理服务
  3. 监控与审计

    • 启用ES安全日志
    • 监控异常访问模式
    • 定期审查用户权限
  4. 生产环境增强

    • 启用TLS加密
    • 使用证书认证
    • 设置IP白名单

适用场景

这个方案特别适合以下场景:

  • 需要对外提供ES服务但要保护敏感信息
  • 多系统共享ES集群但需要不同权限
  • 需要精确控制API访问权限的企业环境

通过ES原生的安全功能,我们成功实现了细粒度的权限控制,既满足了业务需求,又保证了系统安全。

相关rep:

https://github.com/TIMPICKLE/mitmproxy_log_to_EShttps://github.com/TIMPICKLE/mitmproxy_log_to_ES


网站公告

今日签到

点亮在社区的每一天
去签到