为 Ansible 指定 sudo 密码

Posted

技术标签:

【中文标题】为 Ansible 指定 sudo 密码【英文标题】:Specify sudo password for Ansible 【发布时间】:2014-03-19 04:03:51 【问题描述】:

如何以非交互方式?

我正在运行这样的 Ansible 剧本:

$ ansible-playbook playbook.yml -i inventory.ini \
    --user=username --ask-sudo-pass

但我想这样运行它:

$ ansible-playbook playbook.yml -i inventory.ini \
    --user=username` **--sudo-pass=12345**

有办法吗?我想尽可能地自动化我的项目部署。

【问题讨论】:

另见:serverfault.com/questions/560106/… 在此期间,--ask-sudo-pass 已更改为更通用的--ask-become-pass 命令行选项。 【参考方案1】:

The docs 强烈建议不要在明文中设置 sudo 密码,而是在运行 ansible-playbook 时在命令行上使用 --ask-sudo-pass


2016 年更新:

Ansible 2.0(不是 100% 时)将 --ask-sudo-pass 标记为已弃用。 The docs 现在建议改用 --ask-become-pass,同时将整个剧本中的 sudo 替换为 become

【讨论】:

是的,我明白为什么推荐这样做。但是,当我们使用 Ansible 作为部署过程的一部分时,自动化此过程的更好方法是什么?在部署过程中停下来让用户输入sudo密码不是很方便。 注意 --ask-sudo-pass 可以缩写为 -K,但是,据我所知,没有办法处理在多个服务器上运行的具有不同密码的剧本(它只询问你曾经),所以我认为无密码 sudo 是要走的路。 似乎不起作用。但下一个建议(“some-host ansible_sudo_pass='foobar'”)确实 --ask-sudo-pass 在 1.9 中早先被弃用了 如果你有源链接,我很乐意更新答案。【参考方案2】:

您可以通过--extra-vars "name=value" 在命令行上传递变量。 sudo 密码变量是ansible_sudo_pass。所以你的命令看起来像:

ansible-playbook playbook.yml -i inventory.ini --user=username \
                              --extra-vars "ansible_sudo_pass=yourPassword"

2017 年更新:Ansible 2.2.1.0 现在使用 var ansible_become_pass。似乎都可以。

2021 年更新:ansible_become_pass 仍然有效,但目前我们应该使用 -e 而不是 --extra-vars

【讨论】:

从安全角度来看最好的答案,如果你在 yml 执行后添加以下内容:history -c @kiltek:在行首添加一个额外的空格(在 bash 中),这将 *not* 将该行写入@ 987654326@. 在命令行中传递密码不是一个好习惯。任何人都可以在进程列表中看到密码,同时命令正在执行... 仍然,只是不要这样做。 --ask-sudo-pass @scrutari 它在某些情况下完全有效:例如:从默认的、众所周知的初始密码更改为注入用户的公共 ssh 密钥...想想新重新映像的初始配置系统。【参考方案3】:

可能最好的方法——假设你不能使用NOPASSWD solution provided by scottod——是结合使用 Mircea Vutcovici 的解决方案和Ansible vaultArchived

例如,您可能有一个类似这样的剧本:

- hosts: all

  vars_files:
    - secret

  tasks:
    - name: Do something as sudo
      service: name=nginx state=restarted
      sudo: yes

这里我们包含一个名为 secret 的文件,其中包含我们的 sudo 密码。

我们将使用 ansible-vault 创建此文件的加密版本:

ansible-vault create secret

这将要求您输入密码,然后打开您的默认编辑器来编辑文件。你可以把你的ansible_sudo_pass放在这里。

例如:secret:

ansible_sudo_pass: mysudopassword

保存并退出,现在您有一个加密的secret 文件,当您运行 playbook 时,Ansible 能够解密该文件。注意:您可以使用ansible-vault edit secret 编辑文件(并输入您在创建文件时使用的密码)

最后的难题是为 Ansible 提供一个 --vault-password-file,它将用于解密您的 secret 文件。

创建一个名为vault.txt 的文件,并在其中输入您在创建secret 文件时使用的密码。密码应该是在文件中存储为单行的字符串。

来自 Ansible 文档:

.. 确保文件的权限不会让其他人访问您的密钥,并且不要将您的密钥添加到源代码管理中

最后:你现在可以用类似的东西来运行你的剧本了

ansible-playbook playbook.yml -u someuser -i hosts --sudo --vault-password-file=vault.txt 

以上假设如下目录布局:

.
|_ playbook.yml
|_ secret
|_ hosts
|_ vault.txt

您可以在此处阅读有关 Ansible Vault 的更多信息:https://docs.ansible.com/playbooks_vault.htmlArchived


https://docs.ansible.com/ansible/latest/user_guide/vault.html

【讨论】:

注意:从 ansible 1.9 开始,您似乎不能再使用 ansible_sudo_pass(或 ansible_become_pass)变量:“fatal: [...] => Missing become password” 我在生产中使用这个解决方案,jenkins 将保管库密码存储为一个混淆的环境变量,在运行时将其写入一个临时文件并继续调用 ansible。 或更简单的:ansible-vault create group_vars/all/ansible.yml 并在此处添加 ansible_sudo_pass: yourpassword。无需更改剧本或库存 试过了,但我得到了这个错误:fatal: [localhost]: FAILED! => "changed": false, "failed": true, "module_stderr": "sudo: a password is required\n", "module_stdout": "", "msg": "MODULE FAILURE", "parsed": false 如果您将密码以纯文本形式存储在保险库旁边,保险库有什么用?【参考方案4】:

看代码(runner/__init__.py),我想你可以在你的库存文件中设置它:

[whatever]
some-host ansible_sudo_pass='foobar'

ansible.cfg 配置文件中似乎也有一些规定,但目前尚未实施 (constants.py)。

【讨论】:

安全配置它的好方法是将其存储在host_varsgroup_vars 目录中,然后使用ansible-vault 加密文件【参考方案5】:

我认为 ansible 不会让您按照自己的意愿在标志中指定密码。 可能在配置中的某个地方可以设置此项,但这会使使用 ansible 的整体安全性降低,因此不推荐使用。

您可以做的一件事是在目标机器上创建一个用户,并授予他们对所有命令或受限命令列表的无密码 sudo 权限。

如果您运行sudo visudo 并输入如下所示的行,则用户“privilegedUser”在运行sudo service xxxx start 之类的内容时不必输入密码:

%privilegedUser ALL= NOPASSWD: /usr/bin/service

【讨论】:

@bschlueter 所以你认可不好的做法? 我认为这不是一个好主意。使用 --ask-sudo-pass 对我来说很有意义。 @simone cittadini 我完全同意,因为事实上这就是我要给出的答案。这是一个安全风险。 如果您使用无密码 sudo 部署到 staging/prod,安全风险较小,但希望使用这些答案在每次部署到本地主机时不必输入本地笔记本电脑登录密码每天全天 15 分钟。 如何使用 Ansible 添加这一行?【参考方案6】:

sudo 密码 存储为名为@9​​87654321@ 的变量。 您可以通过以下几种方式设置此变量:

每个主机,在您的库存主机文件中 (inventory/<inventoryname>/hosts)

[server]
10.0.0.0 ansible_sudo_pass=foobar

每个组,在您的库存组文件中 (inventory/<inventoryname>/groups)

[server:vars]
ansible_sudo_pass=foobar

每组,在组变量中 (group_vars/<groupname>/ansible.yml)

ansible_sudo_pass: "foobar"

每组,加密 (ansible-vault create group_vars/<groupname>/ansible.yml)

ansible_sudo_pass: "foobar"

【讨论】:

【参考方案7】:

您可以一次为一个组或所有服务器设置密码:

[all:vars]
ansible_sudo_pass=default_sudo_password_for_all_hosts

[group1:vars]
ansible_sudo_pass=default_sudo_password_for_group1

【讨论】:

【参考方案8】:

我在这个问题上扯了我的头发,现在我找到了一个我想要的解决方案:

每个主机 1 个包含 sudo 密码的加密文件

/etc/ansible/hosts:

[all:vars]
ansible_ssh_connection=ssh ansible_ssh_user=myuser ansible_ssh_private_key_file=~/.ssh/id_rsa

[some_service_group]
node-0
node-1

然后为每个主机创建一个加密的 var 文件,如下所示:

ansible-vault create /etc/ansible/host_vars/node-0

有内容

ansible_sudo_pass: "my_sudo_pass_for_host_node-0"

您如何组织保管库密码(通过 --ask-vault-pass 输入)或通过 cfg 由您决定

基于此,我怀疑您可以加密整个主机文件...

【讨论】:

使用 vault 加密对我来说最有意义,尽管我很难将它们与 ansible-playback 一起使用。我必须使用-e @vault/filename.ext 来使用我的ansible-playbook 调用的保险库。【参考方案9】:

一个更精明的方法是将您的sudo 密码存储在安全保险库中,例如LastPass 或KeePass,然后使用-e@ 将其传递给ansible-playbook,而不是对内容进行硬编码在实际文件中,您可以使用构造 -e@<(...) 在子 shell 中运行命令,并将其输出 (STDOUT) 重定向到匿名文件描述符,从而有效地将密码提供给 -e@<(..)

示例

$ ansible-playbook -i /tmp/hosts pb.yml \
   -e@<(echo "ansible_sudo_pass: $(lpass show folder1/item1 --password)")

上面做了几件事,我们分解一下。

ansible-playbook -i /tmp/hosts pb.yml - 显然是通过 ansible-playbook 运行剧本 $(lpass show folder1/item1 --password)" - 运行 LastPass CLI lpass 并检索要使用的密码 echo "ansible_sudo_pass: ...password..." - 获取字符串 'ansible_sudo_pass: ' 并将其与lpass 提供的密码组合在一起 -e@&lt;(..) - 将以上内容放在一起,并连接&lt;(...) 的子shell 作为ansible-playbook 使用的文件描述符。

进一步改进

如果您不想每次都键入,那么您可以简单地这样做。首先在您的.bashrc 中创建一个别名,如下所示:

$ cat ~/.bashrc
alias asp='echo "ansible_sudo_pass: $(lpass show folder1/item1 --password)"'

现在你可以像这样运行你的剧本了:

$ ansible-playbook -i /tmp/hosts pb.yml -e@<(asp)

参考文献

https://docs.ansible.com/ansible/2.4/ansible-playbook.html#cmdoption-ansible-playbook-e

【讨论】:

使用子shell是一个非常聪明的主意!对于那些想知道的人,1Password 的 CLI 如下所示:--extra-vars @&lt;(echo ansible_become_pass: $(op get item &lt;item name&gt; | jq --raw-output '.details.sections[0].fields[] | select(.t=="password").v')) 我喜欢这个,因为当我检查 bach 历史时,密码没有以明文形式公开。这也可能是,如果启用了系统审计,该命令将被记录为读取文件,例如/dev/fd/63 因此密码位于临时文件描述符中,因此不会被公开。【参考方案10】:

如果您愿意将密码保存在纯文本文件中,另一种选择是使用带有 --extra-vars 参数的 JSON 文件(确保从源代码管理中排除该文件):

ansible-playbook --extra-vars "@private_vars.json" playbook.yml 

Ansible has supported this option since 1.3.

【讨论】:

【参考方案11】:

您可以在 hosts 文件中为您的 playbook 编写 sudo 密码,如下所示:

[host-group-name]
host-name:port ansible_sudo_pass='*your-sudo-password*'

【讨论】:

【参考方案12】:

这里曾多次建议使用 Ansible vault,但我更喜欢 git-crypt 来加密我的剧本中的敏感文件。如果您使用 git 来保存您的 ansible playbook,那么这很容易。我在 ansible vault 中发现的问题是,我最终不可避免地会遇到我想要使用的文件的加密副本,并且必须在开始工作之前对其进行解密。 git-crypt 提供了更好的 IMO 工作流程。

https://github.com/AGWA/git-crypt

使用这个,您可以将您的密码放入您的剧本中的 var 中,并将您的剧本标记为 .gitattributes 中的加密文件,如下所示:

 my_playbook.yml filter=git-crypt diff=git-crypt

您的剧本将在 Github 上进行透明加密。然后你只需要在你用来运行ansible的主机上安装你的加密密钥,或者按照文档上的说明使用gpg进行设置。

关于转发gpg 密钥(如您的ssh-agent 转发SSH 密钥)有一个很好的问答:https://superuser.com/questions/161973/how-can-i-forward-a-gpg-key-via-ssh-agent。

【讨论】:

【参考方案13】:

我的自动化方法是使用环境变量并通过--extra-vars="ansible_become_pass=' lookup('env', 'ANSIBLE_BECOME_PASS') '" 访问它。

导出环境变量,但避免 bash/shell 历史记录(以空格或其他方法开头)。例如:

     export ANSIBLE_BECOME_PASS='<your password>'

在将额外的ansible_become_pass 变量传递给ansible-playbook 时查找环境变量,例如:

ansible-playbook playbook.yml -i inventories/dev/hosts.yml -u user --extra-vars="ansible_become_pass=' lookup('env', 'ANSIBLE_BECOME_PASS') '"

好的替代答案:

@toast38coza:simply use a vaulted value for ansible_become_pass。这是体面的。但是,对于需要共享 ansible vault 密码并使用个人帐户执行 ansible 游戏的偏执团队,他们可以使用共享 vault 密码来反转彼此的操作系统密码(身份盗用)。可以说,您需要信任自己的团队吗? @slm 的bash subshell output generated to temp file descriptor and using the @ prefix to read the ansible variable from the file desriptor。至少避免 bash 历史记录。不确定,但希望 subshel​​l 回显不会被捕获并暴露在审计日志中(例如 auditd)。

【讨论】:

这是我认为最好的解决方案。使用 bash 和 set -x 时不会显示密码。【参考方案14】:

使用 ansible 2.4.1.0 和以下应该可以工作:

[all]
17.26.131.10
17.26.131.11
17.26.131.12
17.26.131.13
17.26.131.14

[all:vars]
ansible_connection=ssh
ansible_user=per
ansible_ssh_pass=per
ansible_sudo_pass=per

只需运行 playbook 并使用此库存:

ansible-playbook -i inventory copyTest.yml

【讨论】:

【参考方案15】:

您可以使用ansible vault,它将您的密码编码到加密的保险库中。之后,您可以在剧本中使用保险库中的变量。

关于 ansible vault 的一些文档:http://docs.ansible.com/playbooks_vault.html

我们将它用作每个环境的保管库。要编辑保管库,我们的命令为:ansible-vault edit inventories/production/group_vars/all/vault

如果你想调用 Vault 变量,你必须使用带有参数的 ansible-playbook:ansible-playbook -s --vault-password-file=~/.ansible_vault.password

是的,我们将保管库密码以纯文本形式存储在本地目录中,但这并不像为每个系统存储 root 密码那样危险。根密码在保险库文件中,或者您可以像 sudoers 文件一样为您的用户/组使用它。 我建议在服务器上使用 sudoers 文件。这是组管理员的示例:%admin ALL=(ALL) NOPASSWD:ALL

【讨论】:

【参考方案16】:

您可以使用如下sshpass 实用程序,

$ sshpass -p "your pass" ansible pattern -m module -a args \
   -i inventory --ask-sudo-pass

【讨论】:

【参考方案17】:

只需使用--extra-vars "become_pass=Password" 调用您的剧本

become_pass=('ansible_become_password', 'ansible_become_pass')

【讨论】:

【参考方案18】:

五年后,我可以看到这仍然是一个非常相关的主题。在某种程度上反映了 leucos 的答案,我认为在我的情况下是最好的,仅使用 ansible 工具(没有任何集中式身份验证、令牌或其他任何东西)。这假设您在所有服务器上具有相同的用户名和相同的公钥。如果你不这样做,当然你需要更具体一些,并在主机旁边添加相应的变量:

[all:vars]
ansible_ssh_user=ansible
ansible_ssh_private_key_file=home/user/.ssh/mykey
[group]
192.168.0.50 ansible_sudo_pass=' myserver_sudo '

ansible-vault create mypasswd.yml
ansible-vault edit mypasswd.yml

添加:

myserver_sudo: mysecretpassword

然后:

ansible-playbook -i inv.ini my_role.yml --ask-vault --extra-vars '@passwd.yml'

至少这样你就不必编写更多指向密码的变量了。

【讨论】:

【参考方案19】:

只是一个附录,所以没有其他人会经历我最近的烦恼:

AFAIK,最好的解决方案是按照上述 toast38coza 的一般思路。如果将你的密码文件和你的剧本静态地绑定在一起是有意义的,那么按照他的模板使用vars_files(或include_vars)。如果您想将它们分开,您可以在命令行上提供保管库内容,如下所示:

ansible-playbook --ask-vault-pass -e@<PATH_TO_VAULT_FILE> <PLAYBOOK_FILE>

回想起来很明显,但这里有一些问题:

    那个该死的@标志。如果您忽略它,解析将静默失败,并且 ansible-playbook 将继续进行,就好像您从未指定文件一样。

    您必须使用命令行 --extra-vars/-e 或在您的 YAML 代码中显式导入保管库的内容。 --ask-vault-pass 标志本身不做任何事情(除了提示您输入一个以后可能会或可能不会使用的值)。

您可以添加您的“@”并节省一个小时。

【讨论】:

【参考方案20】:

@toast38coza 的上述解决方案对我有用;只是 sudo: yes 现在在 Ansible 中已被弃用。 请改用 becomebecome_user

tasks:
 - name: Restart apache service
   service: name=apache2 state=restarted
   become: yes
   become_user: root

【讨论】:

【参考方案21】:

关于新的更新

只需使用标志 -K 运行您的剧本,他会询问您的 sudo 密码

例如ansible-playbook yourPlaybookFile.yaml -K

来自文档

要为 sudo 指定密码,请使用 --ask-become-pass(简称 -K)运行 ansible-playbook

【讨论】:

【参考方案22】:

我们还可以在 ansible 中使用 EXPECT BLOCK 来生成 bash 并根据您的需要对其进行自定义

- name: Run expect to INSTALL TA
  shell: |
    set timeout 100
    spawn /bin/sh -i

    expect -re "$ "
    send "sudo yum remove -y xyz\n"

    expect "$ "
    send "sudo yum localinstall -y  rpm_remotehost_path_for_xyz \n"

    expect "~]$ "
    send "\n"

    exit 0
  args:
  executable: /usr/bin/expect

【讨论】:

【参考方案23】:

如果您使用pass 密码管理器,您可以使用模块passwordstore,这让这变得非常简单。

假设您将用户的 sudo 密码保存为 pass as

服务器 1/用户

那么你可以像这样使用解密后的值

 lookup('community.general.passwordstore', 'Server1/User')"

我在我的库存中使用它:

---
   servers:
     hosts:
       server1:
         ansible_become_pass: " lookup('community.general.passwordstore', 'Server1/User')"

请注意,您应该运行 gpg-agent,这样您就不会在每次运行“成为”任务时看到 pinentry 提示。

【讨论】:

【参考方案24】:

您可以在 playbook 执行期间传递它。语法是 -

ansible-playbook -i inventory my.yml \
--extra-vars 'ansible_become_pass=YOUR-PASSWORD-HERE'

但出于安全原因,这不是一个好主意。最好使用 ansible Vault

首先按如下方式更新您的库存文件:

[cluster:vars]
k_ver="linux-image-4.13.0-26-generic"
ansible_user=vivek  # ssh login user
ansible_become=yes  # use sudo 
ansible_become_method=sudo 
ansible_become_pass=' my_cluser_sudo_pass '
 
[cluster]
www1
www2
www3
db1
db2
cache1
cache2

接下来新建一个名为password.yml的加密数据文件,运行如下命令:

$ ansible-vault create passwd.yml

设置保管库的密码。提供密码后,该工具将启动您使用 $EDITOR 定义的任何编辑器。附加以下内容 my_cluser_sudo_pass: your_sudo_password_for_remote_servers 在 vi/vim 中保存并关闭文件。最后运行 playbook 如下:

$ ansible-playbook -i inventory --ask-vault-pass --extra-vars '@passwd.yml' my.yml

如何再次编辑我的加密文件

ansible-vault edit passwd.yml

如何更改我的加密文件的密码

ansible-vault rekey passwd.yml

【讨论】:

【参考方案25】:

很简单,只在变量文件中添加:

例子:

$ vim group_vars/all

并添加这些:

Ansible_connection: ssh
Ansible_ssh_user: rafael
Ansible_ssh_pass: password123
Ansible_become_pass: password123

【讨论】:

谢谢,但我认为您的意思是 ansible_become_pass 而不是 Ansible_become_pass。【参考方案26】:

这对我有用... 使用 NOPASSWD 创建文件 /etc/sudoers.d/90-init-users 文件

echo "user ALL=(ALL)       NOPASSWD:ALL" > 90-init-users

其中“用户”是您的用户 ID。

【讨论】:

以上是关于为 Ansible 指定 sudo 密码的主要内容,如果未能解决你的问题,请参考以下文章

ansible命令详解

ansible命令参数介绍

Ansible sudo 密码丢失

升级到 1.9 后,使用 sudo 复制 Ansible 文件失败

Jenkins Ansibe 插件无法通过 ssh 连接到主机:权限被拒绝(公钥、密码)

ansible become使用