
1. 默认裸奔的集群为什么Elasticsearch上线第一天就被要求加认证如果你刚接触Elasticsearch大概率会经历这么一幕照着官方文档装好ELK启动瞬间看到那个经典的“You Know, for Search”然后高高兴兴地打开http://localhost:9200发现所有索引都能直接查、直接删连账密都不用输。测试环境这么玩很爽但一旦这个端口暴露到公网或局域网基本等同于把你的数据文件放在马路上。我见过不止一个团队因为嫌认证麻烦把Elasticsearch裸奔了几个月直到某天发现某个索引被清空甚至被塞进了挖矿脚本才想起来当初应该加认证。所谓“认证添加”本质上就是启用Elasticsearch的Security特性以前叫X-Pack Security现在已经免费开放让每个请求都带上身份标识只有通过验证的用户才能访问对应资源。认证解决的是“你是谁”的问题配合后面的授权RBAC才能解决“你能干什么”的问题。这篇内容我按实际动手的顺序来写先说清楚为什么要加、加之前要准备什么再手把手走一遍内置用户和自定义用户的操作流程最后是角色权限配置、常见的翻车现场以及接入方的适配。适合正在搭ES环境、刚被安全扫描报告逼着加认证的运维和开发同学也适合需要给已有集群“补课”的团队参考。先说一个容易让新手上头的点ES的认证不是一个开关能一键搞定的。它牵扯到HTTP层和Transport层两层安全生产环境还得处理证书、节点间加密不是设置一个密码就算完。我接下来写的内容是我在一台8G内存的CentOS测试机上加三节点集群时摸出来的完整流程单节点和集群都适用只是需要注意的地方不同。2. 动手前的准备版本差异、配置文件与证书方案2.1 确认你的ES版本和许可证范围开始配置之前必须先确认你的Elasticsearch版本。为什么版本重要因为不同大版本安全特性的默认行为差别很大。7.x系列Security默认关闭需要手动在elasticsearch.yml里设置xpack.security.enabled: true。7.1之后基础安全功能免费。8.x系列默认开启Security而且首次启动会自动生成一套TLS证书和内置用户密码命令行输出里会打印。如果你是从8.x起步反而少了“手动开启”这一步但要处理一堆自动生成的凭据很多人不习惯。6.x及更早需要安装单独的X-Pack插件而且部分功能收费我不建议新项目再用了。如果你用的是8.x第一次启动时终端会直接显示类似The generated password for the elastic user is XXXXX这样的信息建议立即抄下来。如果不小心关了终端别慌可以执行bin/elasticsearch-reset-password -u elastic重置。我这次主要基于7.x来写因为8.x的默认开启已经把流程简化了不少7.x则需要你手动走完整个开启链更能理解底层原理。许可证方面从7.1开始Security的认证和授权功能已经免费不过一些高级特性比如基于LDAP/AD的集成或SSO可能需要白金版试用。我们自己搭环境用免费版足够了。2.2 elasticsearch.yml里需要改哪些配置在加认证前先想清楚一个问题你只是要HTTP层的用户密码认证还是连节点间通信的Transport层也要加密如果只是在单机上测试只开HTTP认证也能跑但一旦涉及两个以上节点就必须处理Transport层的TLS否则节点之间会因为安全配置不一致而互相拒绝。我的建议是哪怕只有一台机器也把Transport层的TLS一起配了。因为你后面很可能要扩容到时候补配置要重启集群平白多一次半夜排队上线。何况自签证书的成本很低用官方工具几分钟就能生成。下面是一份最小化的elasticsearch.yml配置以7.17为例cluster.name: es-test-cluster node.name: node-1 network.host: 0.0.0.0 http.port: 9200 xpack.security.enabled: true xpack.security.transport.ssl.enabled: true xpack.security.transport.ssl.verification_mode: certificate xpack.security.transport.ssl.keystore.path: elastic-certificates.p12 xpack.security.transport.ssl.truststore.path: elastic-certificates.p12这里有几个点要说明network.host不要随便暴露到公网。如果你只在服务器本机用可以写成127.0.0.1或者用防火墙限制来源IP。真正要暴露到内网访问请搭配Kibana和反向代理一起用ES这个端口越少人知道越好。xpack.security.transport.ssl.verification_mode: certificate表示节点间验证证书但不验证域名。如果主机名容易变化用这个模式能避免很多麻烦。如果必须严格校验hostname可以改成full。证书文件路径是相对ES_PATH_CONF通常是$ES_HOME/config的所以路径不要写错。如果写在其他目录最好用绝对路径。2.3 用官方工具生成节点间通信证书ES自带的elasticsearch-certutil就是干这个的。生成证书前确保所有节点都能访问到同一个证书文件。我的做法是在第一台节点上生成然后拷到其他节点。cd $ES_HOME/bin ./elasticsearch-certutil cert -out /etc/elasticsearch/elastic-certificates.p12 -pass -pass 表示证书密码为空。生产环境建议你设一个强密码但那样每个节点的elasticsearch.yml里还要额外声明xpack.security.transport.ssl.keystore.password和xpack.security.transport.ssl.truststore.password。测试环境空密码最省事。执行完之后elastic-certificates.p12就是一个同时包含私钥和证书的PKCS12格式文件。把它复制到每个节点config目录下并确保运行ES的用户有读权限。证书生成完毕不要手贱去解压p12或者转成别的格式ES直接能认。如果你以后要加新节点最好用同一个证书文件不要每个节点单独生成。单独生成意味着各节点需要互相导入对方的证书麻烦不说还容易漏。3. 实操用内置用户体系给Elasticsearch加上认证3.1 设置内置用户的密码配置文件改好、证书就位、节点重启起来之后ES的HTTP接口会立刻拒绝你。比如你curl localhost:9200会收到一条security_exception错误提示内容大致是“missing authentication credentials”。此时认证已经被激活但内置用户还是默认的空白密码所以下一步就是给内置用户设置密码。官方提供了两条路auto和interactive。bin/elasticsearch-setup-passwords auto这条命令会为elastic、kibana_system、logstash_system、beats_system、apm_system、remote_monitoring_user等一组内置用户分别生成随机强密码然后在终端一次性列出来。优点是快缺点是我这种记性差的人很容易把终端关了才想起来没保存。所以我更推荐bin/elasticsearch-setup-passwords interactive交互模式会让你挨个输入每个用户的密码适合需要对接多个组件、想把密码统一管理的场景。比如Kibana需要kibana_system的密码Logstash需要logstash_system的密码如果你用auto模式必须把那串随机密码抄进Kibana的配置里。交互模式则可以统一设成带特定规律的密码后续维护省心不少。填密码的时候有两点注意每个用户的密码建议不一样且不要用弱密码。虽然测试环境里1qaz2wsx这种能用但集群一旦被扫到几乎瞬间被爆破。记好密码与用户的对应关系。后面Kibana、Beats、Logstash、任何排查环节都要用。设置完以后用curl验证一下curl -u elastic:your_password http://localhost:9200/_cluster/health?pretty能看到状态输出说明HTTP层的认证已经生效。3.2 让Kibana也穿上账号密码Kibana和服务端通信用的不是elastic这个超级用户而是专用的kibana_system用户。原因很简单elastic用户拥有集群全权限如果日志里出现它的使用记录你很难区分到底是管理员在操作还是某个组件出了幺蛾子。Kibana用最小权限的专用用户连接ES是官方推荐做法。配置在kibana.yml里elasticsearch.hosts: [http://localhost:9200] elasticsearch.username: kibana_system elasticsearch.password: your_kibana_system_password如果你启用了HTTPS这里elasticsearch.hosts也要改写成https://并且需要指定证书或关闭校验。测试环境可以设elasticsearch.ssl.verificationMode: none生产环境千万别这么干。改完重启Kibana访问Kibana界面时会让你登录用elastic或者其他有Kibana访问权限的账号登录就行。但这里经常有个坑Kibana初次启动时需要往ES里写入Kibana的索引如果kibana_system的密码没设置好Kibana会一直停在Kibana server is not ready yet而且日志里看不到明确原因。我的排查习惯是先看Kibana日志里有没有status为红色或黄色的服务依赖然后再去ES日志里找有没有authentication failed。3.3 其他组件如何接入Logstash、Beats、Spring Boot弄完Kibana你可能会发现自己搭建的管道里还有Logstash和Filebeat。给ES加了认证之后这些组件如果还按老配置连接会直接报401。需要把它们各自的ES输出配置也改成带用户名密码。比如Logstash的output段output { elasticsearch { hosts [http://localhost:9200] user logstash_system password your_logstash_system_password index app-logs-%{YYYY.MM.dd} } }注意如果Logstash需要向ES写入自定义索引、执行ILM、甚至创建索引模板默认的logstash_system用户其实没有那么大的权限。我更倾向单独建一个专用用户用后面的自定义角色授权而不是直接把logstash_system的密码到处乱塞。Spring Boot项目连接Elasticsearch时配置方式也类似。拿spring-data-elasticsearch举例在application.yml里spring: elasticsearch: uris: http://localhost:9200 username: springboot_es password: your_password如果你用的是RestHighLevelClient老写法则在createClient()里设置CredentialsProvider基于HTTP Basic认证的setDefaultCredentials就行。对于7.x和8.x的低版本RestClient密码明文写在代码里这个问题建议放到配置中心或环境变量里。4. 角色与权限让认证从“能进”变成“该进”4.1 我为什么不建议所有人直接拿elastic账号干活认证加好之后很多团队就停在“能登录就行”这一步。这其实是最危险的状态所有人共用elastic这个超级账号出了问题完全查不到是谁干的。更现实的是有些开发者误删索引一个DELETE /logstash-*就把日志数据全清了想恢复只能等手慢无的快照。正确的姿势是为不同场景创建独立用户并通过角色控制权限。比如给业务日志索引的读写用户、给Kibana的访问用户、给运维的只读用户分开管理。ES安全模型里用户归属于一组角色角色界定“能对哪些索引执行哪些操作”。这里涉及两个核心API创建角色POST /_security/role/my_role创建用户POST /_security/user/my_user我下面用一个实际案例来说我们要给一个叫bigdata-app的应用创建一个用户让它只能读写app-*索引不能删除索引不能访问集群管理API。4.2 通过API创建角色和用户先创建角色app_rwcurl -u elastic:your_password -X POST http://localhost:9200/_security/role/app_rw -H Content-Type: application/json -d { indices: [ { names: [app-*], privileges: [read, write], allow_restricted_indices: false } ], cluster: [monitor] } 这里privileges数组里的read和write是最常用的。如果你要允许应用自己创建索引、管理别名那得加上manage或create_index否则应用想写入一个不存在的索引时会失败。我踩过这个坑开发反馈“写不进数据”结果查权限角色里只有write没有create_index。接着创建用户并把这角色挂上去curl -u elastic:your_password -X POST http://localhost:9200/_security/user/bigdata_app -H Content-Type: application/json -d { password: Passw0rd2024, roles: [app_rw], full_name: BigData Application, email: appexample.com, enabled: true } 之后这个用户用HTTP Basic认证调用所有/app-*索引的读写接口都没问题但删除索引这类高危操作会被ES拒绝。4.3 在Kibana里维护权限如果你觉得命令行写API麻烦Kibana的“Stack Management - Security - Roles/Users”界面也提供了可视化管理。这里有一个额外好处Kibana支持索引字段级别的权限控制比如设定“只看message、timestamp字段”的只读角色这在命令行API里配置会更复杂。创建Kibana用户时需要注意一点如果用户只负责投屏运维监控让他访问Kibana的权限需要单独配置。Kibana有自己的一层权限Kibana Spaces、Feature Privileges和ES索引权限不冲突。最简单的方式是在ES侧创建用户时挂kibana_admin角色但给普通开发更合理的往往是kibana_read_only。从合规角度我建议权限最小化能只读就不要写能指定索引就不要给全。集群权限里强烈不建议给*。如果你不了解某个privilege的具体含义宁可不给也不要先给后改。5. 踩坑与排查认证加完后最常见的五个翻车现场5.1 节点间通信失败transport握手无证书加认证最常见的第一个坑是配置完xpack.security.enabled: true启动单节点没问题但启动第二个节点时第二个节点报错日志里出现“not handshaking”或者“remote transport address is not active”。原因多半是Transport层的TLS没有正确配置或者各节点用的证书不一致。我当时的解决步骤是检查每个节点的elasticsearch.yml确认xpack.security.transport.ssl.enabled: true都开了。确认elastic-certificates.p12文件确实在每个节点的config目录下并且权限是644。用bin/elasticsearch-certutil重新生成统一证书复制到所有节点重启集群。如果不想在单机测试上折腾可以先把xpack.security.transport.ssl.enabled设为false但千万别把这习惯带进生产。没有TLS的认证就像在裸奔通道里喊暗号密码都能被中间人截获。5.2 不记得elastic密码越急越乱很多人第一次加认证都会遇到这个尴尬密码忘了Kibana连不上ES启动报一堆401管理员慌得想把安全问题关回去。正确的办法是用ES的elasticsearch-reset-password工具强制重置bin/elasticsearch-reset-password -u elastic -i交互式重置后重新用新密码验证即可。注意如果你之前已经把Kibana的kibana_system密码也忘了同样可以用这个工具重置。5.3 启用认证后快照恢复和滚动升级变得“莫名其妙”这个话题在热搜词里也出现了elasticsearch 恢复数据。加认证之后很多调用快照的脚本会挂因为备份和恢复涉及集群权限。比如一个拥有all权限的用户不一定能执行POST /_snapshot/my_backup/repo_backup/_restore需要manage_slm、monitor_snapshot或者具体仓库的权限。我的经验是在角色配置里单独加cluster: [manage_slm, monitor_snapshot]并且把仓库路径的访问权限给到运行该操作的用户。否则你会看到“no handler for type [snapshot]”或者“is not authorized”的错误日志提示并不直观很容易误判为快照仓库路径挂了。滚动升级时更要注意老版本节点不支持新版本节点的认证握手必须按官方跨版本兼容策略来。我遇到过一次从7.10升7.17老节点没配TLS新节点强制TLS结果新老节点根本组不成一个集群。5.4 ES端口暴露给外部连接工具的适配问题日常开发中很多人喜欢用DBeaver、Navicat或者一些IDE插件连ES来查询数据。加认证之后如果直接用这些工具连接会出现各种连接超时或401。原因并不全是ES的问题很多工具对HTTP Basic认证的字段要求不一样。比如DBeaver连接ES时在“JDBC URL”后面如果要走ES的SQL接口需要把用户名密码按标准方式填写或者在自定义JDBC URL上加上auth参数。更稳妥的方案是不建议把ES 9200端口直接暴露给终端用户。数据库可视化工具要连也建议通过Kibana或者一个带有访问控制的代理层。我在前面提到过ES的端口应该是“后端服务”不应该是“人人都能直连的东西”。给ES加认证只是第一步加上访问隔离才是负责任的做法。5.5 安全配置写错位置改了不生效ES的配置不像Spring Boot那么宽容elasticsearch.yml里写错一个缩进和冒号启动可能直接报错甚至静默忽略某些配置项。我见过有人把xpack.security.enabled写在了yaml文件某行的错误缩进下ES启动时认为这是一个未知的自定义配置结果安全功能压根没开。排查技巧是启动时观察日志里是否有以下一行Security is not enabled或者X-Pack Security is enabled一旦看到日志明确输出就知道生效没生效。另外修改了elasticsearch.yml后必须重启ES进程动态的设置可以用APIcluster.put_settings但安全相关配置绝大多数需要重启。6. 认证之外接入方适配和后续安全建议6.1 从HTTP Basic到HTTPS让认证在加密通道里跑前面我已经提到过HTTP Basic认证的账号密码在明文传输下是可以被截获的。如果你只开了认证没有启用HTTPS那你的密码实际上在网络上“裸奔”。ES的Security本身也支持HTTP层TLS配置起来和Transport层大同小异核心是把另外一个证书配到xpack.security.http.ssl相关项里。测试环境为了省事可以只给Kibana挂个HTTPSES和Kibana之间走内网HTTP但在内网里也要注意别的服务段网络隔离。稳妥的做法是买个正规证书或者用Lets Encrypt实在不行再考虑自签。这里我特别提醒自签证书使Java客户端连接时大概率会遇到PKIX path building failed因为JVM的cacerts里没有你这个自签证书。需要把证书手动导入Java信任库keytool -importcert -file cert.crt -keystore $JAVA_HOME/lib/security/cacerts -alias es-cert这个步骤是很多Java开发连ES需要折腾半天的坑。6.2 天然适配Spring Boot的RestClient和API Key方式跟Spring Boot集成的场景我强烈建议不要只依赖用户名密码认证。ES支持创建API Key可以给API Key设置过期时间、绑定指定角色在程序里以Authorization: ApiKey base64的方式请求。相比密码API Key更灵活可以随时吊销、不用跟着密码改配置。创建API Key的APIcurl -u elastic:your_password -X POST http://localhost:9200/_security/api_key -H Content-Type: application/json -d { name: springboot_app_key, role_descriptors: { app_rw_role: { indices: [ { names: [app-*], privileges: [read, write] } ] } } } 返回结果里会有api_key字段程序端把这两段字符串处理成Base64(id:api_key)即可。很多现代框架都支持这个头。缺点是有些内部老旧HTTP客户端只支持Basic那也只能继续用密码。6.3 给运维留一个“只读”账号认证配好后团队成员总有几个需要查看集群健康、索引状态的人。不要让他们用elastic。运维人员可以给他们建一个read_only_admin角色{ cluster: [monitor], indices: [ { names: [*], privileges: [read] } ] }这样既能查看所有索引又不能误删、误写Kibana或业务索引。如果你还需要他执行“滚动重启”之类的节点操作那再单独加manage等权限按需递增不建议默认给满。6.4 关于认证巡检别让临时账号活到过年我最后想聊一个运维习惯问题。很多团队加了认证以后就不再管了这其实不对。建议至少每三个月做一次这几个操作用elastic角色列表接口过一次所有用户找出那些已经离职或长期没有登录的账号。检查API Key列表把超过90天没有活动的key吊销。把elastic超级账号改成强密码并考虑把调用侧都换成专用账号。Elasticsearch的Security设计本身是成熟的真正出问题的往往是“只用不维护”。我自己见过太多临时加的用户和密码变成僵尸账号到时候泄漏了都不知道是谁的。认证添加不是终点权限治理才是真正让集群状态可控的开始。