elasticsearch's basic auth plugin "Jetty"
Elasticsearch本身是沒有安全性的功能, 我們得透過plugin來安裝, 這次我選擇了elasticsearch-jetty,此外也有人用nginx反向代理來進行控制.
首先我們得先注意到Elasticsearch與Jetty Plugin的版本號對應, 在這裡可以查看, 如果版本號沒對應上就無法正常工作了.
這次範例是用1.2.1版本(Elasticsearch & Jetty Plugin), 到es的bin目錄下執行
plugin -url https://oss-es-plugins.s3.amazonaws.com/elasticsearch-jetty/elasticsearch-jetty-1.2.1.zip -install elasticsearch-jetty-1.2.1
接下來我們要取代es原來的Jetty, 請到es目錄下的config文件夾下面打開 elasticsearch.yml 檔案,接這找出http:type這個section,找不到就直接添加, 改如下(注意冒號後面有個空格)
http.type: com.sonian.elasticsearch.http.jetty.JettyHttpServerTransportModule
接下來我們用curl來測試一下,es的http server的jetty版本是否正確
$ curl -I "http://localhost:9200/" HTTP/1.1 200 OK Content-Type: text/plain;charset=UTF-8 Access-Control-Allow-Origin: * Content-Length: 0 Server: Jetty(8.1.14.v20131031)
接下來我們要開始配置jetty了, jetty配置文件會使用jetty-*.xml檔名來存放配置內容, 而且是可以配置多個檔案的, 其好處是讓我們可以做些分類. 此配置同樣在 elasticsearch.yml 檔案內
sonian.elasticsearch.http.jetty.config: jetty.xml, jetty-hash-auth.xml,jetty-restrict-all.xml
請勿盲目的複製以上代碼, 後面所出現的3個檔案名jetty.xml, jetty-hash-auth.xml,jetty-restrict-all.xml是實際存在檔案, 而且是存在es目錄下的config, 請確保你的檔案位置與名稱是否正確, 注意配置檔案名稱順序不要調換.
這個檔案的sample可以在es目錄下的\plugins\jetty-1.2.1找到, 接著把他們複製到es目錄下的config.
接下來我們要把焦點放到Jertty的xml配置檔上面, 這裡主要關心的是jetty-hash-auth.xml,jetty-restrict-all.xml這兩個檔案, 也可參考官方文檔的說明.
首先來看jetty-hash-auth.xml, 我們可以發現文件內有一串字/realm.properties,其實這是一個檔案, 我們必須在es目錄下的config下新增realm.properties檔案, 這裡面擺放的就是basic_auth的帳號密碼.
superuser: Adm1n,admin,readwrite user: Passw0rd,readwrite me: CRYPT:meyvITIbcrTAY,readwrite read: 1234,readonly guest: 1111
上面我列了一些範例, 配置格式為 username: password,role1,role2 這個配置是最基礎的密碼是明碼(有時候並不想給人直接看到).
me: CRYPT:meyvITIbcrTAY,readwrite 這個範例的密碼是被混淆過的,逗號分個開來的仍然是role, 只是密碼是CRYPT:meyvITIbcrTAY這種格式.
這裡順便也來給出如何產生密碼的方法, 執行java -cp lib/jetty-util-xxx.jar org.eclipse.jetty.util.security.Password username password, XXX是版本號.
下面範例我是用es目錄下的\plugins\jetty-1.2.1的jetty-util-8.1.14.v20131031.jar.
java -cp jetty-util-8.1.14.v20131031.jar org.eclipse.jetty.util.security.Password guest guestPwd guestPwd OBF:20771x1b206z MD5:639bae9ac6b3e1a84cebb7b403297b79 CRYPT:guest/ks90E221EY
<New class="org.eclipse.jetty.util.security.Constraint" id="DefaultSecurityConstraint"> <Set name="authenticate">true</Set> <Set name="name">BASIC</Set> <Set name="roles"> <Array type="java.lang.String"> <Item>readwrite</Item> </Array> </Set> </New> <New class="org.eclipse.jetty.util.security.Constraint" id="NoneSecurityConstraint"> <Set name="authenticate">false</Set> </New>
根據我的理解這是在創建一個實例,id類似於變量名(DefaultSecurityConstraint), 根據名稱來看這是一個約束class, 開啟authenticate, 設置驗證方式BASIC,我們可以在roles段添加一些語意性的名子(這邊是readwrite), 另一個是沒有權限控制的約束(NoneSecurityConstraint).
注意到readwrite這個字串, 這跟我們在配置realm.properties裡面的角色是對應的.
接下來這段, 有關handler的部分尚未研究, 我們先關注到Call元素的method, pathSpec, constraint.
下面的範例是指: GET http://127.0.0.1:9200, GET http://127.0.0.1:9200/_search?q=* 都可以不需要通過basic_auth驗證就可以訪問, 其他例如: GET http://127.0.0.1:9200/_plugin/marvel 則需要權限.
<Set name="handler"> <New class="com.sonian.elasticsearch.http.jetty.security.RestConstraintSecurityHandler" id="DefaultSecurityHandler"> <Set name="handler"><Ref id="OldHandler"/></Set> <Set name="loginService"> <!-- from jetty-es-auth.xml or jetty-hash-auth.xml --> <Ref id="DefaultLoginService"/> </Set> <Set name="realmName">DefaultRealm</Set> <Call name="addConstraintMapping"> <Arg> <New class="org.eclipse.jetty.security.ConstraintMapping"> <Set name="pathSpec">*</Set> <Set name="constraint"> <Ref id="DefaultSecurityConstraint"/> </Set> </New> </Arg> </Call> <Call name="addConstraintMapping"> <Arg> <New class="org.eclipse.jetty.security.ConstraintMapping"> <Set name="method">GET</Set> <Set name="pathSpec"> /,/_search </Set> <Set name="constraint"> <Ref id="NoneSecurityConstraint"/> </Set> </New> </Arg> </Call> </New> </Set>
pathSpec主要是配置可以分訪問的uri, 分別用逗號隔開. 注意這個Set Setion需要段行那怕只有一個url規則, 下面是針對rui根的配置
<Set name="pathSpec">
/
</Set>
method是指允許的http的動詞, GET, PUT, POST...是否可以設置多個尚未研究.
constraint配置之前的角色約束.
以上的配置目前都需要重新啟動es, 關於這樣的方案有待研究, 或者是我們要正確的去使用uri約束, 而不是把所有的業務相關過濾行為都放在這個配置檔案.