03.elasticsearch-security_es鉴权机制

文章目录

    • 1.概述
    • 2. xpack.security.enabled的作用
      • 2.1 实验一
        • 1.生成ca文件
        • 2.elastisearch.yml中进行相关的配置,开启了node之间transport层面使用ssl
        • 3.访问测试
    • 3.创建用户信息,跳过build-in user的初始化
      • 3.1 配置file realm
      • 3.2 kibana配置
      • 3.3 使用kibana创建用户测试
    • 4.anonymous 用户的测试
      • 4.1 es设置
      • 4.2 访问测试
    • 5. role中的run as 功能
      • 5.1 配置一个更低权限的user
      • 5.1 给run_user 配置一个run as 权限
    • 6.开启http层面是ssl/tsl加密

1.概述

  es 官方有security开启的操作流程,这篇文章的主要是为了搞清楚这些流程中的每一步是否必要,有什么含义。先总结官方步骤如下

  1. 检查使用license,因为不同的license能够使用的权限验证方式也是不一样的。
  2. 检查集群,保证每一个node都进行了设置 xpack.security.enabled: true
    这个会开启security设置,也就开启了node之间使用ssl和基于用户的访问模式
  3. 想要跑在专用的jvm上(这个一般用不到)
  4. 开启node之间的transport层面的ssl/tls
  5. 启动es
  6. 为build-in user设置password
  7. 选择一种realm的管理方式,basic只能使用 file,native两种方式,其他的都是收费的
  8. 创建一些role和user来进行使用
  9. 打开audit功能呢(可选的,实际上这个是收费的,我们也用不了)

2. xpack.security.enabled的作用

  最开始的时候,我以为这个仅仅是开启设置,强制要求进行node间的encrypt通信,实验的时候才发现,xpack.security.enabled会开启集群的node之间的encrypt通信的要求,同时也会开启基于user-password的访问特性。

2.1 实验一

1.生成ca文件

bin/elasticsearch-certutil ca
生成 elastic-stack-ca.p12 文件,中间一路回车,不用设置密码

bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12
生成 elastic-certificates.p12,中间一路回车,不设置密码

mkdir config/certs
mv  elastic-stack-ca.p12   elastic-certificates.p12 config/certs/

2.elastisearch.yml中进行相关的配置,开启了node之间transport层面使用ssl

## security 相关
xpack.security.enabled: true

### 1. tcp层配置
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p12

3.访问测试

这个时候集群的启动是正常的,但是使用curl访问的时候

curl 10.76.3.145:12200 |jq '.'
{
  "status": 401,
  "error": {
    "header": {
      "WWW-Authenticate": "Basic realm=\"security\" charset=\"UTF-8\""
    },
    "reason": "failed to authenticate user [elastic]",
    "type": "security_exception",
    "root_cause": [
      {
        "header": {
          "WWW-Authenticate": "Basic realm=\"security\" charset=\"UTF-8\""
        },
        "reason": "failed to authenticate user [elastic]",
        "type": "security_exception"
      }
    ]
  }
}

发现需要用户信息,必须使用用户才能够正常的访问。
使用默认的用户信息

curl -u 'elastic:changeme'  10.76.3.145:12200 |jq '.'

访问发现也是不行的,通过文档查找知道es已经取消了这些用户的默认密码,只有手动修改激活之后才是可以正常使用的。

3.创建用户信息,跳过build-in user的初始化

  因为上面的讨论中认为xpack.security.enabled会开启集群的node之间的encrypt通信的要求,同时也会开启基于user-password的访问特性,初步思考,认为build-in user只是user中的一个很小的部分,是为了让user使用更加方便的,并不算是一个独立的功能,所以步骤6并不是必须的。

为了验证一下,这里并没有进行build-in user的初始化过程。直接在每个node上配置了file realm

3.1 配置file realm

es 目录下执行

./bin/elasticsearch-users  useradd  chencc -p chencc -r superuser

bin/elasticsearch-users list

chencc         : superuser

这个命令会在config下的 users_roles, users文件下生成了role和user信息,用户为checc, password 为chencc, role为bulid-in role superuser,这个role默认拥有所有的权限,
参照这里,这里和这里

es配置


## security 相关
xpack.security.enabled: true

### 1. tcp层配置
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p12

xpack.security.authc.realms.file.file1.order: 0

3.2 kibana配置


server.name: dev-log
server.port: 45601
server.host: 10.76.0.129
elasticsearch.hosts: ["http://10.76.0.98:12200"]
elasticsearch.username: chencc
elasticsearch.password: chencc

xpack.monitoring.kibana.collection.enabled: true
xpack.monitoring.enabled: true
xpack.monitoring.elasticsearch.hosts: ["http://10.76.0.98:12200"]
xpack.monitoring.elasticsearch.username: chencc
xpack.monitoring.elasticsearch.password: chencc

注意两个地方都要配置user,password才行。
然后使用 chencc登录kibana发现还都是好使的,哈哈哈。

curl -u 'chencc:chencc'  10.76.3.145:12200 |jq '.'
{
  "tagline": "You Know, for Search",
  "version": {
    "minimum_index_compatibility_version": "6.0.0-beta1",
    "number": "7.3.0",
    "build_flavor": "default",
    "build_type": "tar",
    "build_hash": "de777fa",
    "build_snapshot": false,
    "lucene_version": "8.1.0",
    "minimum_wire_compatibility_version": "6.8.0"
  },
  "cluster_uuid": "aT2wHdDBQDSguyDjgAzHzw",
  "cluster_name": "dev-log",
  "name": "ES02"
}

  这也是说明了并不一定绝对依赖build-in user,他是es的提供的方便,但是实际使用中肯定还是建议激活的,这些用户都对应了一些特定的场景,可以更加方便快捷的进行权限划分。但是在kibana的管理页面是看不到这个用户的存在的,应该是无法通过api修改权限的
但是我们可以将file realm定义的用户合并到native ,参考这里

To migrate file-based users to the native realm, use the migrate tool.

但是这个工具在7.2的时候已经过期了,官方建议是直接使用native realm即可

  同时,对于file-realm的使用,es官方的建议是配置一个高级别的管理员用户,在其他用户都被lock的时候用户重置其他用户。参考这里

3.3 使用kibana创建用户测试

  既然chencc可以拥有所有的权限,不妨索性创建两个用户试试,在kibana的管理页面创建了一个role为superuser的用户chen_test,但是用这个用户来登录kibana的时候,发现不行。使用curl访问的时候也报没有权限。

curl -u 'chen_super:chen_super'  10.76.3.145:12200 |jq '.'

{
  "status": 401,
  "error": {
    "header": {
      "WWW-Authenticate": "Basic realm=\"security\" charset=\"UTF-8\""
    },
    "reason": "unable to authenticate user [chen_super] for REST request [/]",
    "type": "security_exception",
    "root_cause": [
      {
        "header": {
          "WWW-Authenticate": "Basic realm=\"security\" charset=\"UTF-8\""
        },
        "reason": "unable to authenticate user [chen_super] for REST request [/]",
        "type": "security_exception"
      }
    ]
  }
}

  这个时候想到有可能额因为每个es node中显式的配置了file realm ,导致了native-realm被禁用了(kibana创建的属于native realm)。所以创建的用户没有办法使用了。参考这里

The file realm is added to the realm chain by default. 
You don’t need to explicitly configure a file realm.

and 这里

The native realm is available by default when no other realms are configured. 
If other realm settings have been configured in elasticsearch.yml, 
you must add the native realm to the realm chain.

所以所显式的打开native试试


## security 相关
xpack.security.enabled: true

### 1. tcp层配置
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p12



xpack.security.authc.realms.file.file1.order: 0
xpack.security.authc.realms.native.native1.order: 1

果然,打开native之后就可以了,无论是kibana登录还是curl访问,啊啊啊。
如何进行带有user-password的请求参考这里

curl -u 'chen_super:chen_super'  10.76.3.145:12200 |jq '.'
{
  "tagline": "You Know, for Search",
  "version": {
    "minimum_index_compatibility_version": "6.0.0-beta1",
    "number": "7.3.0",
    "build_flavor": "default",
    "build_type": "tar",
    "build_hash": "de777fa",
    "build_snapshot": false,
    "lucene_version": "8.1.0",
    "minimum_wire_compatibility_version": "6.8.0"
  },
  "cluster_uuid": "aT2wHdDBQDSguyDjgAzHzw",
  "cluster_name": "dev-log",
  "name": "ES02"
}

这里说明了即使关掉了native,使用kibana和响应的api都是还是可以创建用户的,但是不能正常使用。必须在开启了native之后这些用户才是可以使用的。

4.anonymous 用户的测试

  es还允许你配置一个匿名用户来进行访问,你可以对这个用户进行role的设置,决定了如果一个访问没有携带用户信息的话,就使用配置的匿名用户来进行鉴权,后面的测试发现,如果请求携带的用户权限不够,也会尝试使用配置的anonymous用户来代替鉴权。

4.1 es设置


## security 相关
xpack.security.enabled: true

### 1. tcp层配置
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p12

## 2. realm 配置
xpack.security.authc.realms.file.file1.order: 0
xpack.security.authc.realms.native.native1.order: 1

## 3. 匿名配置
xpack.security.authc:
  anonymous:
    username: anonymous_user
    roles: superuser,kibana_user
    authz_exception: true

4.2 访问测试


curl  10.76.3.145:12200 |jq '.'
{
  "tagline": "You Know, for Search",
  "version": {
    "minimum_index_compatibility_version": "6.0.0-beta1",
    "number": "7.3.0",
    "build_flavor": "default",
    "build_type": "tar",
    "build_hash": "de777fa",
    "build_snapshot": false,
    "lucene_version": "8.1.0",
    "minimum_wire_compatibility_version": "6.8.0"
  },
  "cluster_uuid": "aT2wHdDBQDSguyDjgAzHzw",
  "cluster_name": "dev-log",
  "name": "ES02"
}

可以看到,不带用户信息进行访问,也能够通过,但是假如你携带了用户的信息,但是这个用户不存在,或者密码错误,这还是会返回失败的哦。

5. role中的run as 功能

在es的权限中中还有一种是run as 权限,也就是允许你run as另一个用户。
这个时候,另一个用户其实也就成了一种权限,类似一个role一样。
这个功能的解释我看了半天没有看懂,最后竟然还是借助google翻译看懂的,大哭。
参考这里来解释一下

Some realms have the ability to perform authentication internally, 
but delegate the lookup and assignment of roles (that is, authorization) 
to another realm.

一些realms 有进行权限验证的能力,但是可以将role的查找和分配(即授权)委派给另一个realm.
当然并不是所有的realm都有这种能力,好像PKI的ream不支持作为run as的对象。
参考这里有进一步的说明

下面进行ran-as功能测试

5.1 配置一个更低权限的user

POST _security/user/run_user
{
  "password": "run_user"
  ,
  "roles": ["beats_system"]
}

当我使用这个user访问集群穿件索引的的时候,发现是ok的

curl -u 'apm_system:apm_system' -XPUT  \
--header "Content-Type:application/json"  10.76.3.145:12200/test05/_doc/2 -d '{"id":5}'

  理论上这个beats_system role是没有这个权限的。然后我又创建了几个基础用户,发现也是这种情况,这不科学啊,搞的我错乱。后来突然想起来,当前的es有配置anonymous用户,是不是有可能没有权限的话直接就走这个anonymous用户了呢,因为anonymous用户的权限是比较高的,关掉了nanoymous用户相关的配置,重启后果然正常了(就是上面的执行会失败)。


## 3. 匿名配置
#xpack.security.authc:
#  anonymous:
#    username: anonymous_user
#    roles: superuser,kibana_user
#    authz_exception: true

这个不知道算不算是坑,在anonymous 相关的位置没有看到说明。就这样吧,哈哈。
进行下一步

5.1 给run_user 配置一个run as 权限

POST /_security/role/run_as_test
{
  "run_as": ["chencc"]
}


POST _security/user/run_user
{
  "password": "run_user",
  "roles": ["beats_system","run_as_test"]
}


发现还是不行

curl -u 'run_user:run_user' -XPUT --header "Content-Type:application/json"  10.76.3.145:12200/test05/_doc/2 -d '{"id":5}'|jq '.'
135   263  131   263    0     8  41004   1247 --:--:-- --:--:-- --:--:-- 51000
{
  "status": 403,
  "error": {
    "reason": "action [indices:data/write/bulk[s]] is unauthorized for user [run_user]",
    "type": "security_exception",
    "root_cause": [
      {
        "reason": "action [indices:data/write/bulk[s]] is unauthorized for user [run_user]",
        "type": "security_exception"
      }
    ]
  }
}

其实是api使用有点小问题啦,需要使用一个特殊的http header
这个header是为了标识你要behalf 那个用户,或者是impersonate 哪个用户(我只是单纯的想要复习一下这两个单词)

curl -H "es-security-runas-user: chencc"  -u run_user:run_user   -XPUT --header "Content-Type:application/json"  10.76.3.145:12200/test05/_doc/2 -d '{"id":5}'  |jq '.'
{
  "_primary_term": 2,
  "_seq_no": 5,
  "_shards": {
    "failed": 0,
    "successful": 2,
    "total": 2
  },
  "result": "updated",
  "_version": 6,
  "_id": "2",
  "_type": "_doc",
  "_index": "test05"
}

好了,到此run as的功能也介绍的差不多啦。

6.开启http层面是ssl/tsl加密

  这个功能之前没有怎么用过,因为伤害比较大,需要所有的client都需要配置ssl相关的配置才能访问,比如kibana,logstash,filebeat,外部的exporter等等。这里是探索,就用一下试试吧。在已经完成了transport层面的ssl配置之后,在http层面的配置在es上相对还是很简单的。

elasticsearch.yml增加以下配置

## http请求加密
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: certs/elastic-certificates.p12
xpack.security.http.ssl.truststore.path: certs/elastic-certificates.p12
xpack.security.http.ssl.client_authentication: none

第四个配置没有看出来有啥用,就是配置了服务端是否需要客户端的证书。
这个配置完后进行重启,使用curl请求却访问不通了,看了服务器有很多报错日志


[2020-06-04T11:07:54,851][WARN ][o.e.h.AbstractHttpServerTransport] [ES01] caught exception while handling client http traffic, closing connection Netty4HttpChannel{localAddress=0.0.0.0/0.0.0.0:12200, remoteAddress=/10.76.0.98:47063}
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: Received fatal alert: unknown_ca
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:472) ~[netty-codec-4.1.36.Final.jar:4.1.36.Final]
...
...
Caused by: javax.net.ssl.SSLException: Received fatal alert: unknown_ca
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) ~[?:?]

当我时使用

curl -u 'chencc:chencc'  http://10.76.0.98:12200 |jq '.'

curl: (52) Empty reply from server

在浏览器端访问http://10.76.0.98:12200也不行了,kibana自然也是报错
搞的我一度以为es集群起不起来,挂掉了,但是当我使用 netstat -tupln,又看到了对应的端口
后面想到是不是应该用https访问,在浏览器端改成https之后,信任了私有证书之后,终于可以正常访问了。然后是curl请求,忽略证书的校验,改成https访问,success!

curl -k  -u 'chencc:chencc'  https://10.76.0.98:12200 |jq '.'
{
  "tagline": "You Know, for Search",
  "version": {
    "minimum_index_compatibility_version": "6.0.0-beta1",
    "number": "7.3.0",
    "build_flavor": "default",
    "build_type": "tar",
    "build_hash": "de777fa",
    "build_snapshot": false,
    "lucene_version": "8.1.0",
    "minimum_wire_compatibility_version": "6.8.0"
  },
  "cluster_uuid": "aT2wHdDBQDSguyDjgAzHzw",
  "cluster_name": "dev-log",
  "name": "ES01"
}

你可能感兴趣的:(elasticsearch,elasticsearch,java,运维)