我有一个麻烦的任务,它在ubuntu 12.04上创建了一个新用户;
- name: Add deployment user
action: user name=deployer password=mypassword
它可以按预期完成,但是当我以该用户身份登录并尝试使用我设置的密码sudo时,它总是表示不正确。我究竟做错了什么?
我有一个麻烦的任务,它在ubuntu 12.04上创建了一个新用户;
- name: Add deployment user
action: user name=deployer password=mypassword
它可以按预期完成,但是当我以该用户身份登录并尝试使用我设置的密码sudo时,它总是表示不正确。我究竟做错了什么?
Answers:
如果您阅读了user
模块的 Ansible手册,它将把您定向至Ansible-examples github存储库,以获取有关如何使用password
parameter的详细信息。
在那里,您将看到密码必须经过哈希处理。
- hosts: all
user: root
vars:
# created with:
# python -c 'import crypt; print crypt.crypt("This is my Password", "$1$SomeSalt$")'
password: $1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.
tasks:
- user: name=tset password={{password}}
如果您的剧本或ansible命令行将密码原样保留为纯文本格式,则意味着您的影子文件中记录的密码哈希错误。这意味着当您尝试使用密码进行身份验证时,其哈希值将永远不匹配。
此外,有关密码参数的一些细微差别以及如何正确使用它,请参阅Ansible FAQ。
openssl passwd -salt <salt> -1 <plaintext>
来生成密码哈希,而不是上面的Python单行代码。从我的Python获取正确的输出时遇到了一些麻烦,这可能是由于我自己的能力不足以及openssl命令效果更好。
/etc/shadow
使用手动设置密码后发现了哈希passwd <user>
。
我可能为时已晚,但是最近我发现jinja2过滤器具有处理加密密码生成的功能。在我中,main.yml
我生成的加密密码为:
- name: Creating user "{{ uusername }}" with admin access
user:
name: {{ uusername }}
password: {{ upassword | password_hash('sha512') }}
groups: admin append=yes
when: assigned_role == "yes"
- name: Creating users "{{ uusername }}" without admin access
user:
name: {{ uusername }}
password: {{ upassword | password_hash('sha512') }}
when: assigned_role == "no"
- name: Expiring password for user "{{ uusername }}"
shell: chage -d 0 "{{ uusername }}"
“ uusername”和“ upassword”被传递--extra-vars
给剧本,请注意,我在这里使用jinja2过滤器对传递的密码进行加密。
我在我的博客中添加了与此相关的以下教程
password={{upassword|password_hash('sha512', upassword_salt)}}
。这样一来,您就可以像预期那样将salt放入变量库中,同时upassword
将它们都排除在task.yml外。
update_password: on_create
用户模块添加到此答案中,以防止已创建用户的密码过期。
pip install passlib
。为了能够使用内联保管库加密的字符串,我必须重新格式化以下内容:password: {{ upassword | string | password_hash('sha512') }}
。这避免了错误消息secret must be unicode or bytes, not ansible.parsing.yaml.objects.AnsibleVaultEncryptedUnicode
我想提出另一种解决方案:
- name: Create madhead user
user:
name: madhead
password: "{{ 'password' | password_hash('sha512') }}"
shell: /bin/zsh
update_password: on_create
register: madhead
- name: Force madhead to change password
shell: chage -d 0 madhead
when: madhead.changed
为什么更好?就像这里已经提到的,Ansible剧本应该是幂等的。您不应将它们视为命令式风格的一系列动作,而应将其视为所需状态,声明式风格。因此,您应该能够多次运行它,并获得相同的结果,相同的服务器状态。
听起来不错,但有一些细微差别。其中之一是管理用户。“期望状态”是指每次您运行创建用户的剧本时,他都会被更新为与该状态完全匹配。“更新”是指他的密码也将被更改。但是很可能不是您所需要的。通常,您只需要创建用户,设置一次密码和使其密码过期一次,再进行一次播放就不会更新其密码。
幸运的是,Ansible update_password
在user
模块中具有可解决此问题的属性。将其与已注册的变量混合使用,还可以仅在实际更新用户时使他的密码失效。
请注意,如果您手动更改用户的外壳(假设您不喜欢邪恶管理员在其游戏中强制使用的外壳),则用户将被更新,因此其密码将过期。
还要注意如何在剧中轻松使用纯文本初始密码。无需在其他地方对其进行编码并粘贴哈希,则可以使用Jinja2过滤器。但是,如果有人在您初次登录之前碰巧登录,则可能是安全漏洞。
"{{ '{{vaulted_password}}' | password_hash('sha512') }}"
似乎不起作用...
{{ vaulted_password | password_hash('sha512') }}
,vaulted_password
Vault价值的关键在哪里?
update_password: on_create
似乎没有工作(有一个关于它的开放的bug 2017),因此密码会改变任何时候有一个用户的状态变化。
Ansible的“用户”模块以幂等方式管理用户。在下面的剧本中,第一个任务为用户声明state = present。请注意,第一个操作中的“ register:newuser ”帮助第二个操作确定用户是新用户(newuser.changed == True)还是现有用户(newuser.changed==False
),仅生成一次密码。
Ansible剧本具有:
tasks:
- name: create deployment user
user:
name: deployer
createhome: yes
state: present
register: newuser
- name: generate random password for user only on creation
shell: /usr/bin/openssl rand -base64 32 | passwd --stdin deployer
when: newuser.changed
这样尝试
vars_prompt:
- name: "user_password"
prompt: "Enter a password for the user"
private: yes
encrypt: "md5_crypt" #need to have python-passlib installed in local machine before we can use it
confirm: yes
salt_size: 7
- name: "add new user" user: name="{{user_name}}" comment="{{description_user}}" password="{{user_password}}" home="{{home_dir}}" shell="/bin/bash"
此答案中角色的目的是为new_user_name生成随机密码,并立即使密码过期。需要new_user_name来更改他/她的首次登录密码。
create_user.yml:
---
# create_user playbook
- hosts: your_host_group
become: True
user: ansible
roles:
- create_user
角色/ create_user /任务/main.yml:
---
# Generate random password for new_user_name and the new_user_name
# is required to change his/her password on first logon.
- name: Generate password for new user
shell: makepasswd --chars=20
register: user_password
- name: Generate encrypted password
shell: mkpasswd --method=SHA-512 {{ user_password.stdout }}
register: encrypted_user_password
- name: Create user account
user: name={{ new_user_name }}
password={{ encrypted_user_password.stdout }}
state=present
append=yes
shell="/bin/bash"
update_password=always
when: new_user_name is defined and new_user_name in uids
register: user_created
- name: Force user to change password
shell: chage -d 0 {{ new_user_name }}
when: user_created.changed
- name: User created
debug: msg="Password for {{ new_user_name }} is {{ user_password.stdout }}"
when: user_created.changed
当您要创建新用户时:
ansible-playbook -i hosts.ini create_user.yml --extra-vars "new_user_name=kelvin"
这是简单的方法:
---
- name: Create user
user: name=user shell=/bin/bash home=/srv/user groups=admin,sudo generate_ssh_key=yes ssh_key_bits=2048
- name: Set password to user
shell: echo user:plain_text_password | sudo chpasswd
no_log: True
这就是它为我工作的方式
- hosts: main
vars:
# created with:
# python -c "from passlib.hash import sha512_crypt; print sha512_crypt.encrypt('<password>')"
# above command requires the PassLib library: sudo pip install passlib
- password: '$6$rounds=100000$H/83rErWaObIruDw$DEX.DgAuZuuF.wOyCjGHnVqIetVt3qRDnTUvLJHBFKdYr29uVYbfXJeHg.IacaEQ08WaHo9xCsJQgfgZjqGZI0'
tasks:
- user: name=spree password={{password}} groups=sudo,www-data shell=/bin/bash append=yes
sudo: yes
为了完整起见,我将使用ansable发布ad-hoc命令,因为那里也有一个问题。
首先,尝试使用大多数Linux系统上可用的mkpasswd实用程序生成加密的密码:
mkpasswd --method=SHA-512
然后尝试使用ansible ad-hock命令:
ansible all -m user -a 'name=testuser shell=/bin/bash \
comment="Test User" password=$6$XXXX' -k -u admin --sudo
但请确保:
--sudo
否则最终会出现类似(useradd: cannot lock /etc/passwd; try again later
)的错误结合上面的一些解决方案,我创建了一个剧本,可根据存储在加密的本地ansible Vault文件中的纯文本密码自动生成正确的密码哈希:
---
- hosts: [your hosts]
tasks:
- include_vars: [path to your encrypted vault file]
- local_action: "command openssl passwd -salt '{{password_salt}}' -1 '{{password}}'"
register: password_hash
- user: >
name=[your username]
state=present
password="{{password_hash.stdout}}"
使用“ --ask-vault-pass”选项运行此命令以解密保管库文件(有关如何管理加密保管库的信息,请参阅ansible-vault)。
如何创建用于将password
var 传递给Ansible user
任务的加密密码(来自@Brendan Wood的评论):
openssl passwd -salt 'some_plain_salt' -1 'some_plain_pass'
结果将如下所示:
$1$some_pla$lmVKJwdV3Baf.o.F0OOy71
user
任务示例:
- name: Create user
user: name="my_user" password="$1$some_pla$lmVKJwdV3Baf.o.F0OOy71"
$ python -c "import crypt, getpass, pwd; print crypt.crypt('password', '\$6\$saltsalt\$')"
$6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/
$ perl -e 'print crypt("password","\$6\$saltsalt\$") . "\n"'
$6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/
$ ruby -e 'puts "password".crypt("$6$saltsalt$")'
$6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/
您可以使用ansible-vault在剧本中使用秘密密钥。在yml中定义您的密码。
例如 通过:秘密或
user:
pass: secret
name: fake
使用加密您的机密文件:
ansible-vault encrypt /path/to/credential.yml
Ansible会询问密码以对其进行加密。(我将解释如何使用该通行证)
然后,您可以在所需的位置使用变量。没有库密钥,没有人可以阅读它们。
保管箱金钥用法:
通过在运行剧本时传递参数。
--ask-vault-pass: secret
或者您可以将其保存到password.txt之类的文件中并隐藏在某处。(对CI用户有用)
--vault-password-file=/path/to/file.txt
在您的情况下:包括vars yml并使用您的变量。
- include_vars: /path/credential.yml
- name: Add deployment user
action: user name={{user.name}} password={{user.pass}}
password={{user.pass}}
它将扩展到包括实际的密码,而ansible希望那里的哈希值。
为用户生成随机密码
首先需要定义用户变量,然后再下面
任务:
- name: Generate Passwords
become: no
local_action: command pwgen -N 1 8
with_items: '{{ users }}'
register: user_passwords
- name: Update User Passwords
user:
name: '{{ item.item }}'
password: "{{ item.stdout | password_hash('sha512')}}"
update_password: on_create
with_items: '{{ user_passwords.results }}'
- name: Save Passwords Locally
become: no
local_action: copy content={{ item.stdout }} dest=./{{ item.item }}.txt
with_items: '{{ user_passwords.results }}'
Mxx的答案是正确的,但是crypt.crypt()
当涉及到不同的操作系统时(与系统上使用的glibc哈希算法有关),python 方法并不安全。
例如,如果您是从MacOS生成哈希值并在Linux上运行剧本,则它将无法正常工作。在这种情况下,您可以使用passlib(pip install passlib
在本地安装)。
from passlib.hash import md5_crypt
python -c 'import crypt; print md5_crypt.encrypt("This is my Password,salt="SomeSalt")'
'$1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.'
两种解决方案都不能直接在我的Mac上控制Ubuntu。因此,出于他人的考虑,结合Mxx和JoelB答案,这是当前的Python 3解决方案:
pip3 install passlib
python3 -c 'from passlib.hash import md5_crypt; \
print(md5_crypt.encrypt("This is my Password", salt="SomeSalt"))'
结果将为$1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.
,如Mxx的回答。
更好的是,使用SHA512代替MD5:
python3 -c 'from passlib.hash import sha512_crypt; \
print(sha512_crypt.encrypt("This is my Password", salt="SomeSalt"))'
结果:
$ 6 $ rounds = 656000 $ SomeSalt $ oYpmnpZahIsvn5FK8g4bDFEAmGpEN114Fe6Ko4HvinzFaz5Rq2UXQxoJZ9ZQyQoi9zaBo3gBH / FEAov3FHv48
我创建了一个ansible-playbook,可让您创建一个允许密码验证的linux帐户。
请参阅CreateLinuxAccountWithAnsible。
哈希密码是使用mkpasswd
命令生成的。我提供了mkpasswd
在不同操作系统上安装的方法。
这是使用我的脚本所需的步骤:
用所需的用户名和密码替换<your_user_name>
并<your_password>
在内部run.sh
。
更改连接信息,inventory
以便ansible可以连接到计算机以创建用户。
运行./run.sh
以执行脚本。
如果您想通过Ansible ad-hoc命令完成此操作,则可以执行以下操作:
$ password='SomethingSecret!'
$ ansible 192.168.1.10 -i some_inventory -b -m user -a "name=joe_user \
update_password=always password=\"{{ \"$password\" | password_hash('sha512') }}\""
以上命令的输出:
192.168.1.10 | SUCCESS => {
"append": false,
"changed": true,
"comment": "Joe User",
"group": 999,
"home": "/home/joe_user",
"move_home": false,
"name": "joe_user",
"password": "NOT_LOGGING_PASSWORD",
"shell": "/bin/bash",
"state": "present",
"uid": 999
}
我知道我参加晚会很晚,但是我正在使用另一种解决方案。对于--stdin
passwd二进制文件中没有的发行版,可能会很方便。
- hosts: localhost
become: True
tasks:
- name: Change user password
shell: "yes '{{ item.pass }}' | passwd {{ item.user }}"
loop:
- { pass: 123123, user: foo }
- { pass: asdf, user: bar }
loop_control:
label: "{{ item.user }}"
标签中loop_control
负责印刷只有用户名。整个剧本或仅用户变量(可以使用vars_files:
)应使用ansible-vault进行加密。
我的解决方案是使用查找并自动生成密码。
---
- hosts: 'all'
remote_user: root
gather_facts: no
vars:
deploy_user: deploy
deploy_password: "{{ lookup('password', '/tmp/password chars=ascii_letters') }}"
tasks:
- name: Create deploy user
user:
name: "{{ deploy_user }}"
password: "{{ deploy_password | password_hash('sha512') }}"
尝试了许多实用程序,包括mkpasswd,Python等。但是在读取其他工具生成的HASH值时,似乎与Ansible存在兼容性问题。因此,最终它通过ansible#值本身起作用。
ansible all -i localhost,-m debug -a“ msg = {{'yourpasswd'| password_hash('sha512','mysecretsalt')}}”
剧本-
- name: User creation
user:
name: username
uid: UID
group: grpname
shell: /bin/bash
comment: "test user"
password: "$6$mysecretsalt$1SMjoVXjYf.3sJR3a1WUxlDCmdJwC613.SUD4DOf40ASDFASJHASDFCDDDWERWEYbs8G00NHmOg29E0"
好吧,我完全迟到了:)我需要玩一个有趣的游戏,用随机密码创建多个本地用户。我想出了这一点,从顶部使用了一些示例,并进行了一些更改。
使用密码创建用户
---
# create_user playbook
- hosts: all
become: True
user: root
vars:
#Create following user
users:
- test24
- test25
#with group
group: wheel
roles:
- create-user-with-password
/ roles /使用密码创建用户/任务/main.yml
- name: Generate password for new user
local_action: shell pwgen -s -N 1 20
register: user_password
with_items: "{{ users }}"
run_once: true
- name: Generate encrypted password
local_action: shell python -c 'import crypt; print(crypt.crypt( "{{ item.stdout }}", crypt.mksalt(crypt.METHOD_SHA512)))'
register: encrypted_user_password
with_items: "{{ user_password.results }}"
run_once: true
- name: Create new user with group
user:
name: "{{ item }}"
groups: "{{ group }}"
shell: /bin/bash
append: yes
createhome: yes
comment: 'Created with ansible'
with_items:
- "{{ users }}"
register: user_created
- name: Update user Passwords
user:
name: '{{ item.0 }}'
password: '{{ item.1.stdout }}'
with_together:
- "{{ users }}"
- "{{ encrypted_user_password.results }}"
when: user_created.changed
- name: Force user to change the password at first login
shell: chage -d 0 "{{ item }}"
with_items:
- "{{ users }}"
when: user_created.changed
- name: Save Passwords Locally
become: no
local_action: copy content={{ item.stdout }} dest=./{{ item.item }}.txt
with_items: "{{ user_password.results }}"
when: user_created.changed
password
不应该以纯文本形式,而是被充斥。