最近项目需要在几个集群的机器上部署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=/
401 Unauthorized
401 Unauthorized
Could not authenticate using provided credentials
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')
Powered by CherryPy 3.6.0
心里觉得奇怪,该不会是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起来后的代码里,没进一步深究,有空再更新。