近些年安全事故层出不穷,经常可以听到某公司数据泄露的消息。所以为了保障用户数据的安全和避免我们被关小黑屋,对集群进行安全访问控制是很有必要的。
Elastic Stack 的安全层级如下图(官方提供的图片):
如上图,在开发环境我们可以使用 Minimal security (Elasticsearch Development) 进行部署,Minimal security 提供了基础的用户账号认证功能。
在生产环境可以使用 Basic security (Elasticsearch Production) 除了提供了 Minimal security 的用户认证功能外,集群中节点的通信还使用了 TLS,可以防止没有认证的 node 加入集群中,不过 ES 与 Kibana 间的通信并没有进行加密。
还可以使用 Basic security plus secured HTTPS traffic (Elastic Stack) 的方式进行部署,这种方式除了提供 Basic security 的功能外,Elastic Stack 中各个组件间的通信会进行加密。
所以为保证集群的安全,我们需要做以下三件事情:
- 集群访问进行身份认证。
- 节点间通信加密,通过节点间通信数据的加密,可以防止通信数据被窃取。
- 外部使用 https 访问集群,使用安全的 https 协议访问集群,而不是不安全的 http 协议。
- 对使用集群的用户进行身份认证和用户鉴权。用户使用集群的功能前需要登陆,并且根据实际情况控制用户对各个索引的访问、操作权限。
所以今天我们的内容主要有:
- 配置集群身份认证。
- 配置节点间通信加密。
- 配置使用 https 访问集群。
- 用户鉴权。
今天的内容实操性比较强,强烈建议边学边练吧。如果你对 HTTPS、CA、证书这些安全方面的知识不太了解的话,可以参考这篇文章。
一、集群身份认证
在 Elastic Stack 6.8.0 和 7.1.0 版本中核心安全功能(在 X-Pack 中提供)已经免费提供了,如果你的 ES 版本低于 6.8.0 你可以使用一些社区的安全防护产品如:search-guard。
X-Pack 套件提供的基础账号认证功能称为 Realm,其模式分为免费和收费两种:
- 免费:提供基本的账号认证服务,即账号密码登录的方式。
- 收费:提供基于LDAP、kerbors、SAML、Active Directory 等认证方式。
今天我们介绍的是免费的方式。要开启 Realm,可以在每个节点的配置文件中进行配置:
# 在每个节点的 elasticsearch.yml 中加入以下配置
xpack.security.enabled: true
或者在启动的时候以命令行参数的方式进行设置:
.bin/elasticsearch -E xxxxxx -E xpack.security.enabled=true
在重启集群之前你需要在 Kibana 中执行以下指令对 ES 进行设置:
POST /_license/start_trial?acknowledge=true
如果不执行上述设置,在重启 ES 的时候会报错:
bootstrap check failure [1] of [1]:
Transport SSL must be enabled if security is enabled on a [basic] license.
Please set [xpack.security.transport.ssl.enabled] to [true]
or disable security by setting [xpack.security.enabled] to [false]
从 trial 的字面意思来看,应该是带有测试性质的,所以当 license 为 trial 类型的时候,可以单独开启安全功能,但可以不启用传输层加密(TLS)。而 basic 类型的 license 则需要两个都开启才能使用。
ok,重启 ES 成功后,执行下面指令我们为 ES 集群加入用户账户和密码。
# 为 ES 集群设置用户账号密码
# 在集群的其中一个节点上执行即可
./bin/elasticsearch-setup-passwords interactive
在集群的其中一个节点上执行如上指令将会出现:
根据提示输入各个账号的密码即可。再次访问 ES 将会弹出认证信息,在我的测试环境,其如下图:
这里好像有个 bug,我把密码设置 “123456” 居然通过了!!!!!!!!!!!这个命令好像没有对弱密码进行限制,使用的时候注意不要用弱口令。
Ok,成功配置好登录认证的功能后,我们接着配置在 Kibana 和 Cerebro 中使用 elastic 账号接入 ES 集群。
elasticsearch.username: "elastic"
elasticsearch.password: "123456"
Kibana 的配置比较简单,在配置文件中加入上述配置项即可,然后重启 Kibana 服务。
Cerebro 同样 Cerebro 的配也需要指定访问 ES 的用户和其对应的密码,其配置文件如下:
hosts = [
{
host = "http://localhost:9211"
name = "my_app"
auth = {
username = "elastic"
password = "123456"
}
}
]
除了配置 ES 集群的账号密码外,还需要配置 Cerebro 系统本身的账号密码:
# Authentication
auth = {
type: ${?AUTH_TYPE}
settings {
......
group-search {
......
}
# Basic auth
username = "admin"
password = "123456"
}
}
需要配置 username 和 password,配置完成后,重启服务即可。
完成了 Kibana 和 Cerebro 接入 ES 集群后,下面我们来配置 ES 集群节点间使用加密通信。
二、节点间通信加密
为啥要加密节点间通信的信息呢?主要是为了防止流量被监听和非法节点加入到集群中,从而导致集群数据泄漏。
节点间通信是使用 TLS 来进行加密的,所以我们首先要要搞到一个证书,而颁发证书需要 CA 来颁发的,所以我们首先要生成一个 CA。在其中一个节点上使用下面的指令生成一个 CA:
# 生成一个 CA
./bin/elasticsearch-certutil ca
成功执行了指令后,当前目录下会生成一个 p12 后缀的证书文件,其默认的名字为:elastic-stack-ca.p12。这个 elastic-stack-ca.p12 包含了 CA 的公共证书以及用于为每个节点签署证书的私钥。需要注意的是,为了简单,在生成这个 CA 的时候我们不要输入密码,直接按 Enter 键就可以了。
有了 CA 后,我们可以使用这个 CA 生成证书和私钥:
# 生成证书和私钥
./bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12
执行如上指令,默认的情况下会生成一个 PKCS#12 格式的文件:elastic-certificates.p12,然后将这个包含私钥和公钥的文件复制到各个节点的 ES config 目录下。在我的测试环境,其路径如下:
最后在每个节点上开启 SSL、设置认证方式、设置证书路径等配置如下:
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.client_authentication: required
xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
如上配置,其中 verification_mode 有 3 种模式:
- full,其为默认值,除了验证证书的有效性外,还会检查节点的 hostname 或者 ip。
- certificate,持有有效证书的节点才能加入到集群,所以需要将生成的证书复制到所有的节点上。
- none,不需要认证就可以加入到集群中。一般在调试的时候使用,强烈建议不要在生产环境中使用。
完成了配置后,重启集群配置生效。当一个违法的节点试图加入到集群时将会被拒绝(你可以只配置两个节点,留下一个节点不配置作为非法节点),集群日志如下:
日志中非常清楚地记录了,一个非法节点使用非加密的链接加入到集群中,然后被无情地拒绝了。
三、外部使用 https 访问集群
如上图,本小节我们将配置 ES 对外提供 https 的 rest 接口,此时 Kibana 和其他客户端需要使用 https 的方式连接到 ES 集群。另外我们还配置 Kibana 对外提供 https 的访问方式,我们在浏览器需要使用 https 的方式访问 Kibana。
1、配置 ES 对外提供 https 的访问方式
要配置 ES 对外提供 https 的访问方式,只需要在配置文件中加入以下配置即可:
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: elastic-certificates.p12
xpack.security.http.ssl.truststore.path: elastic-certificates.p12
其中 elastic-certificates.p12 是我们上面生成的证书文件,在每个节点上加入以上配置,并且重启集群即可。这里并没有按照官方文档的说法去做,那个生成证书的步骤要复杂很多,感兴趣的同学可以查阅官方文档。
集群重启后 ES 只提供 https 的访问方式,此时 Kibana 和 cerebro 是无法访问 ES 集群的,下面我们来配置这两个服务使用 https 访问 ES 集群。
Kibana
由于 Kibana 不支持使用 PKCS#12 格式的证书来配置,其支持 pem 格式的证书,所以我们需要使用 elastic-certificates.p12 生成一个 pem 格式的证书:
# 在 ubuntu 执行,如果是 win 的话自己安装 openssl 工具
openssl pkcs12 -in elastic-certificates.p12 -cacerts -nokeys -out es_ca.pem
如上示例,我们生成了一个 es_ca.pem 证书,然后将这个 pem 的证书复制到 Kibana 的配置目录。最后在 kibana.yml 配置文件中加入以下配置(修改证书的路径):
elasticsearch.hosts: ["https://localhost:9211"] # 这个链接地址需要用 https 了
elasticsearch.ssl.certificateAuthorities: ["/your_path/kibana/config/es-ca.pem"]
elasticsearch.ssl.verificationMode: certificate
如上配置,elasticsearch.hosts 需要使用 https 协议了,而不是原来的 http 协议。需要注意的是证书的地址需要是绝对路径的。重启 kibana,并且执行一个简单的查询看看是否能正常访问 ES。
Cerebro
同样 cerebro 的配置也比较简单,将上面生成的 es-ca.pem 证书复制到 cerebro 的配置目录下,然后在 application.conf 配置文件中加入一下配置(修改证书的路径):
play.ws.ssl {
trustManager = {
stores = [
{ type = "PEM", path = "/your_path/cerebro/conf/es_ca.pem" }
]
}
}
play.ws.ssl.loose.acceptAnyCertificate=true
# 修改协议为 https
......
host = "https://localhost:9211"
......
然后还需要修改访问 ES 的地址,把 http 协议的访问方式改为 https 协议,然后重启 cerebro 即可。
2、配置 Kibana 对外提供 https 的访问方式
要提供 https 的访问方式,我们需要为 Kibana 生成证书,在其中一个节点的目录下执行一下指令:
# 生成 pem 证书
./bin/elasticsearch-certutil ca -pem
执行如上指令,将会生成了 elastic-stack-ca.zip 文件,解压此 zip 文件将得到 ca.crt、ca.key 两个文件:
将这两个文件复制到 Kibana 的配置目录,然后再 kibana.yml 配置文件中加入以下配置项(请修改证书的路径):
server.ssl.enabled: true
server.ssl.certificate: /your_path/kibana/config/ca.crt
server.ssl.key: /home/spoofer/ES/kibana/config/ca.key
温馨提示:如果你在 Kibana dev tools 看板上的例子比较重要,请先复制出来备份,因为使用 https 后这些内容会清空!!!
ok,现在重启 Kibana,然后发现在浏览器中用 http 的方式已经无法访问了,使用 https 的访问方式后是可以的,但由于我们用的是自己的 CA,所以浏览器会有不安全的警告。
至此,整个集群的安全配置已经完成并且生效,下面我们来看看如何做用户鉴权。
四、用户鉴权
用户鉴权是指我们指定某些用户只能访问部分索引或者对某些索引只有部分权限(如只有读权限)等,限制用户的权限可以有效地保护数据的安全。
我们可以使用 X-Pack 的 RBAC(Role-based Access Control)机制来为自定义角色分配权限、为用户指定角色,从而实现权限管理。
授权的过程是围绕着以下几个概念开展的:
- Secured Resource,指受访问控制的资源,例如某个索引。
- Privilege ,用户可以针对安全资源执行的一个或多个动作(例如 read、write 索引)的命名组。
- Permissions , 针对安全资源的一条或多条 Privileges。
- Role,Permissions 的集合。
- User,认证的用户。
- Group,用户组。
上述这些概念都很好理解,下面我们将演示在 Kibana 中创建一个Role 和 User,并且将这个新的角色分配给新的用户。
创建 Role
登录 Kibana 在左侧导航栏点击 Stack Management,然后再点击左侧的 Security 下的 Roles:
点击右上角的 Create role 按钮,我们来创建一个新的 Role:
如上图,各个选项的详细解析如下表:
选项 | 说明 |
---|---|
Role name | 新建角色的名称 |
Cluster privileges | 定义对集群的操作权限,如创建快照、取消任务等详细信息参考官方文档。 |
Run As privileges | 允许一个认证的用户代表其他用户提交请求,更多的信息请参考官方文档。 |
Index privileges | 定义索引的操作权限,可以使用通配符的方式,更多信息请参考官方文档。 |
点击 Add Kibana privileges 可以设置这个角色对 Kibana 的访问权限。
在弹出的界面中配置 Kibana 的权限即可,通过这个配置可以控制拥有这个 role 的用户可看到 Kiaban 左边菜单栏的菜单有哪些。如果不配置 Kibana privileges 这个权限的话这个角色的用户是无法登录 Kibana 的。
创建用户
点击左侧的 Security 下的 Users:
填写用户相关的信息即可创建用户,这里 Privileges 我们填写我们上面创建的 role:read_user。
然后我们回到 Dev Tools 创建 users 索引,并且写入几条数据:
# 创建 users mapping
PUT users
{
"mappings": {
"properties": {
"user_id": { "type": "keyword" },
"name": { "type": "keyword" }
}
}
}
# 写入数据
POST /users/_doc
{
"user_id": "1",
"name": "fork"
}
# 查询数据
POST users/_search
{
"query": { "match_all": {} }
}
Ok, 点击 Kibana 右上角的按钮,log out 当前用户,然后使用我们新创建的用户进行登录,在 Dev Tools 中执行查询发现是可以操作的,但是写入数据的时候会报 http 403 的错误:
五、总结
今天为你介绍了 ES 集群安全的配置。
为了不让 ES 裸奔在网络中,我们使用了 X-Pack 中提供的基础账号认证功能来设置账号和密码,此时 ES 提供的功能必须登录后才能使用。
为了不让非法节点接入到集群中,我们为集群节点通信配置了加密通信的方式。而外部访问 ES 我们也配置了 https 的访问方式。虽然是这样,但我还是建议你不要暴露 ES 到公网中去。
同样 Kibana 我们也介绍了如何配置外部使用 https 的方式进行访问。
最后还介绍如何在 Kibana 中创建一个 Role 和 User,并且为这个 Role 和 User 分配对应的权限。
本章的内容实操性比较强,建议多动手多折腾~