03.elasticsearch-security_es鑑權機制

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"
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章