这个问题涉及最佳实践。我正在使用Fabric运行部署脚本。我的部署用户“deploy”需要sudo权限来重启服务。因此,我在脚本中使用Fabric的sudo函数来运行这些命令。这样做可以正常工作,但在脚本执行期间会提示输入密码。我不想在部署过程中输入密码。这里有什么最佳实践?我唯一能想到的解决方案是更改sudo权限,使其不需要为我的部署用户运行的命令输入密码。但我觉得这不太对劲。
最佳解决方案是在您的服务器上创建一个仅用于部署的用户(例如,deploy
)。然后,在您的fabfile中设置env.user=deploy
。接下来,在您的服务器上,您可以通过sudoers文件逐个命令地授予该用户必要的权限:
重要提示:修改sudoers文件时,请始终使用sudo visudo
。
Cmnd_Alias RELOAD_SITE = /bin/bash -l -c supervisorctl*, /usr/bin/supervisorctl*
deploy ALL = NOPASSWD: RELOAD_SITE
Cmnd_Alias
指令,然后为每个指令授予NOPASSWD
访问权限。有关详细信息,请参见man sudoers
。/etc/sudoers.d/deploy
中,并通过在结尾处添加includedir /etc/suoders.d
来从/etc/sudoers
中包含该文件。最好的方法是使用子任务。您可以在fabfile中提示输入密码,从而不会暴露任何密码,也不会对远程系统上的sudo进行鲁莽的配置更改。
import getpass
from fabric.api import env, parallel, run, task
from fabric.decorators import roles
from fabric.tasks import execute
env.roledefs = {'my_role': ['host1', 'host2']}
@task
# @parallel -- uncomment if you need parallel execution, it'll work!
@roles('my_role')
def deploy(*args, **kwargs):
print 'deploy args:', args, kwargs
print 'password:', env.password
run('echo hello')
@task
def prompt(task_name, *args, **kwargs):
env.password = getpass.getpass('sudo password: ')
execute(task_name, *args, role='my_role', **kwargs)
prompt
任务仍然只运行一次,而deploy
任务会针对角色中的每个主机并行运行。$ fab prompt:deploy,some_arg,another_arg,key=value
fabric.api import env
# [...]
env.password = 'yourpassword'
看起来sudo
并不是那么糟糕的选择。您可以指定用户可以运行哪些命令以及命令可能采用的参数(man sudoers
)。如果问题只是需要输入密码,则一种选项涉及使用pexpect
模块自动登录,也许使用加密存储的密码:
import pexpect, sys
pwd = getEncryptedPassword()
cmd = "yourcommand"
sCmd = pexpect.spawn('sudo {0}'.format(cmd))
sCmd.logfile_read = sys.stdout
sCmd.expect('Password:')
sCmd.sendline(pwd)
sCmd.expect(pexpect.EOF)
from fabric import task
import keyring
@task
def restart_apache(connection):
# set the password with keyring.set_password('some-host', 'some-user', 'passwd')
connection.config.sudo.password = keyring.get_password(connection.host, 'some-user')
connection.sudo('service apache2 restart')
您也可以使用GPG或任何其他命令行密码工具。例如:
connection.config.sudo.password = connection.local('gpg --quiet -d /path/to/secret.gpg', hide=True).strip()
secret.gpg
文件可以通过echo \"mypassword\" | gpg -e > secret.gpg
命令生成。使用hide
参数可避免在控制台中回显密码。
为保留--prompt-for-sudo-password
的支持,请添加条件语句:
if not connection.config.sudo.password:
connection.config.sudo.password = keyring.get_password(connection.host, 'some-user')
您也可以为多台机器使用密码:
from fabric import env
env.hosts = ['user1@host1:port1', 'user2@host2.port2']
env.passwords = {'user1@host1:port1': 'password1', 'user2@host2.port2': 'password2'}
run('echo "{0} ALL=(ALL) ALL" >> /etc/sudoers'.format(env.user))