SUSE安裝SaltStack後的pam認證問題
最近專案需要在幾個叢集的機器上部署SaltStack,作業系統有SUSE11 SP3和SP4兩個版本的。之前同事在centos的虛擬機器上測試一路順風順水,沒想到上SUSE遇到一堆坑。
坑1:在SaltStack的官網上可以找到兩個SUSE用的源,從Document- Installation - SUSE下找到的源是opensuse的(http://download.opensuse.org/repositories/systemsmanagement:/saltstack/SLE_11_SP4/systemsmanagement:saltstack.repo),版本為2016.3.3;而從Downloads- SUSE - SLES11下找到的源是saltstack的(http://repo.saltstack.com/opensuse/SLE_11_SP4/systemsmanagement:saltstack.repo),版本為2015.8.12。版本不一致讓人疑惑,但坑不在這裡,真正的坑是,不管用哪個源裝都會少一些依賴,比如python-requests等幾個rpm包,要找到匹配的版本還是花了一番功夫的,我找到的4個包如下,地址就不放了。這還不算大坑。
python-requests-2.4.1-30.1.x86_64.rpm
python-ordereddict-1.1-0.7.31.x86_64.rpm
ca-certificates-1-9.1.noarch.rpm
libffi43-4.3.4_20091019-0.37.28.x86_64.rpm
除了salt,salt-master,salt-minion外,我還裝了salt-api,因為需要一個restful的API供外部呼叫。裝完以後,還需要配置外部認證供salt-api使用(https://docs.saltstack.com/en/latest/topics/eauth/index.html),再新建一個作業系統帳號供api使用(我建的帳號為saltapi),無難度。全部配完,起salt-master和salt-api服務,顯示OK,但是呼叫的時候來坑了。
坑2:首先嚐試用curl方式呼叫
curl -si localhost:8088/login -H"Accept:application/json" -H"Content-type:application/json" -d'{"username":"saltapi","password":"mypassword","eauth":"pam"}'
返回了一個401錯誤:
HTTP/1.1 401 Unauthorized Content-Length: 1614 Access-Control-Expose-Headers: GET, POST Vary: Accept-Encoding Server: CherryPy/3.6.0 Allow: GET, HEAD, POST Access-Control-Allow-Credentials: true Date: Sat, 15 Oct 2016 11:14:43 GMT Access-Control-Allow-Origin: * Content-Type: text/html;charset=utf-8 Set-Cookie: session_id=9f4c49f186ad3026386a43372d7b2e538d216397; expires=Sat, 15 Oct 2016 21:14:43 GMT; Path=/ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta> <title>401 Unauthorized</title> <style type="text/css"> #powered_by { margin-top: 20px; border-top: 2px solid black; font-style: italic; } #traceback { color: red; } </style> </head> <body> <h2>401 Unauthorized</h2> <p>Could not authenticate using provided credentials</p> <pre id="traceback">Traceback (most recent call last): File "/usr/lib64/python2.6/site-packages/cherrypy/_cprequest.py", line 670, in respond response.body = self.handler() File "/usr/lib64/python2.6/site-packages/cherrypy/lib/encoding.py", line 217, in __call__ self.body = self.oldhandler(*args, **kwargs) File "/usr/lib64/python2.6/site-packages/salt/netapi/rest_cherrypy/app.py", line 534, in hypermedia_handler ret = cherrypy.serving.request._hypermedia_inner_handler(*args, **kwargs) File "/usr/lib64/python2.6/site-packages/cherrypy/_cpdispatch.py", line 61, in __call__ return self.callable(*self.args, **self.kwargs) File "/usr/lib64/python2.6/site-packages/salt/netapi/rest_cherrypy/app.py", line 1529, in POST 'Could not authenticate using provided credentials') HTTPError: (401, 'Could not authenticate using provided credentials') </pre> <div id="powered_by"> <span> Powered by <a href="http://www.cherrypy.org">CherryPy 3.6.0</a> </span> </div> </body> </html>
心裡覺得奇怪,該不會是salt-api沒裝好吧,畢竟有不少野地裡淘來的rpm啊。於是決定用salt命令在master的本機呼叫:
salt -a pam "*" test.ping
執行後會提示輸入使用者名稱和密碼,輸入saltapi帳號資訊,依然是401錯誤。這下雷了。研究了一下salt的程式碼,pam認證都要過以下檔案,編輯一下以便除錯:
vi /usr/lib64/python2.6/site-packages/salt/auth/pam.py
在179行加入:
print "retval after AUTHENTICATE:%s" % retval
然後將salt-master服務停掉,在命令列前臺起一個debug模式的salt-master,來看到底什麼情況:
service salt-master stop
salt-master -l debug
接下去就更雷了。在2015.8.12版本的機器上,執行到這裡列印“retval after AUTHENTICATE: 10”,而在2016.3.3版本的機器上列印“retvalafter AUTHENTICATE: 7”。關於這個返回值的解釋,可以看這個頁面(http://pubs.opengroup.org/onlinepubs/8329799/chap5.htm)。其中,7代表PAM_PERM_DENIED,10代表PAM_NEW_AUTHTOK_REQD。我一開始在一臺2015.8.12版本的虛擬機器上除錯,始終返回10,懷疑是PAM的token無法生成,翻遍了網上所有saltstack的文章都沒有解決方案。由於當時已經到晚上11點了,困得要死,決定先作個弊,跑過去再說。於是再修改pam.py檔案,將auth方法改為如下:
def auth(username, password, **kwargs):
‘’’
Authenticate via pam
‘’’
# return authenticate(username, password)
if username==’saltapi’ and password==’mypassword’:
return True
else:
return False
作弊成功,果然跑通,拿到了通訊的token。
第二天起來以後,覺得不甘心,繼續找原因,並且發現了2016.3.3版本下retval值為7,開始懷疑是許可權問題。起初在/etc/pam.d/下找問題,無果。偶然之下cat /etc/shadow 了一下,發現一個奇怪的帳號:
salt:*:17089:0:99999:7:::
於是恍然大悟,雖然servicesalt-master ***是用root帳號跑的,但程序未必是root起的,ps一下檢視果然,salt-master都是salt帳號起的。而linux的/etc/shadow預設是隻有root帳號能讀的,於是:
setfacl -m u:salt:r /etc/shadow
把昨天改的pam.py改回去,起salt-master服務,呼叫api拿token,成功!再深究一下,發現在/etc/salt/master下有以下一段:
# The user under which the salt master willrun. Salt will update all
# permissions to allow the specified userto run the master. The exception is
# the job cache, which must be deleted ifthis user is changed. If the
# modified files cause conflicts, setverify_env to False.
user: salt
syndic_user: salt
結論是在SUSE環境下由於某些我不清楚的原因,saltstack安裝時只是建了salt帳號,並沒能正確修改許可權,導致不能讀取/etc/shadow,引發了奇怪的401錯誤。而在centos上是正確修改了的,所以沒碰到問題。至於修改是在rpm的postscripts裡,還是在salt-master起來後的程式碼裡,沒進一步深究,有空再更新。