使用Ansible创建新的用户名和密码


103

我有一个麻烦的任务,它在ubuntu 12.04上创建了一个新用户;

- name: Add deployment user
    action: user name=deployer password=mypassword

它可以按预期完成,但是当我以该用户身份登录并尝试使用我设置的密码sudo时,它总是表示不正确。我究竟做错了什么?


1
您是否使用相同的密码或ssh键登录?您是否检查了影子文件以确保其内容符合预期?同样,您password不应该以纯文本形式,而是被充斥。
Mxx

我的密码是纯文本,不能这样使用吗?我不知道该如何加密,或者真的需要加密。
raphael_turtle 2013年

Answers:


101

如果您阅读了user模块的 Ansible手册,它将把您定向至Ansible-examples github存储库,以获取有关如何使用passwordparameter的详细信息。

在那里,您将看到密码必须经过哈希处理。

- 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


25
谢谢你的提示。我只想指出,上面链接的用户模块文档建议使用openssl passwd -salt <salt> -1 <plaintext>来生成密码哈希,而不是上面的Python单行代码。从我的Python获取正确的输出时遇到了一些麻烦,这可能是由于我自己的能力不足以及openssl命令效果更好。
布伦丹·伍德

6
如何将盐与操作系统同步?
2016年

5
@Breedly:没有必要-盐总是作为密码的一部分存储($ 1 $ thesalt $ thepasswordhash),这意味着它可以在操作系统之间使用相同的哈希函数进行移植
Benjamin Dale

3
使用此python命令生成哈希对我不起作用。但是我在/etc/shadow使用手动设置密码后发现了哈希passwd <user>
dokaspar

172

我可能为时已晚,但是最近我发现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过滤器对传递的密码进行加密。

我在我的博客中添加了与此相关的以下教程


6
为避免该项目始终“更改”,您可以将密码“ salt”作为第二个参数添加到password_hash。
Michael Wyraz

11
按照@MichaelWyraz的建议:添加第二个“盐”参数可以避免“更改”。您可以通过变量设置此值,例如password={{upassword|password_hash('sha512', upassword_salt)}}。这样一来,您就可以像预期那样将salt放入变量库中,同时upassword将它们都排除在task.yml外。
user85461 '02

我还将应用@bbaassssiiee的状态检查并将update_password: on_create用户模块添加到此答案中,以防止已创建用户的密码过期。
madhead '16

感谢您的出色榜样,这使我步入正轨。不过,我必须做更多的事情才能使其在具有2.8.2版本的ansible的Mac上运行。首先,在Mac上无法使用crypt,因此需要使用来安装passlib库pip install passlib。为了能够使用内联保管库加密的字符串,我必须重新格式化以下内容:password: {{ upassword | string | password_hash('sha512') }}。这避免了错误消息secret must be unicode or bytes, not ansible.parsing.yaml.objects.AnsibleVaultEncryptedUnicode
Michael Aicher

尽管使用此方法设置了密码:“ {{my_password |字符串| password_hash('sha512')}}”,我仍然会得到-[警告]:输入的密码似乎没有被散列。必须加密'password'参数,此模块才能正常工作。
openCivilisation

46

我想提出另一种解决方案:

- 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_passworduser模块中具有可解决此问题的属性。将其与已注册的变量混合使用,还可以仅在实际更新用户时使他的密码失效。

请注意,如果您手动更改用户的外壳(假设您不喜欢邪恶管理员在其游戏中强制使用的外壳),则用户将被更新,因此其密码将过期。

还要注意如何在剧中轻松使用纯文本初始密码。无需在其他地方对其进行编码并粘贴哈希,则可以使用Jinja2过滤器。但是,如果有人在您初次登录之前碰巧登录,则可能是安全漏洞。


3
我无法获得其他解决方案为我服务。但是您的答案很简单而且很有效。如果可以的话,我想给你5个投票。
leesei '16

我不希望这样对我的密码进行硬编码:(是否可以将其从ansible-vault中取出并注入到这里?像嵌套一样"{{ '{{vaulted_password}}' | password_hash('sha512') }}"似乎不起作用...
dokaspar

您是否尝试过{{ vaulted_password | password_hash('sha512') }}vaulted_passwordVault价值的关键在哪里?
madhead '18 -4-12

update_password: on_create似乎没有工作(有一个关于它的开放的bug 2017),因此密码会改变任何时候有一个用户的状态变化。
Diti

11

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

只有一个解决方案对我有效,并带有Vault密码。非常感谢。
丹尼斯·萨文科

至少最近的基于Debian的发行版似乎不支持passwd二进制文件中的长GNU选项“ --stdin”。
XXL

10

这样尝试

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"

2
我喜欢这种解决方案,因为它允许在脚本运行时输入密码。引导脚本的好解决方案,该脚本不应每次都运行。对于Ubuntu,我使用了“ sha512_crypt”。
Gunnar

6

此答案中角色的目的是为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"

3

这是简单的方法:

---
- 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

shell:将始终导致要报告更改。
bbaassssiiee 2015年

真正的选项:@datasmid您可以添加NO_LOG docs.ansible.com/ansible/...
菲尔Pafford

3

这就是它为我工作的方式

- 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

3

为了完整起见,我将使用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

但请确保:

  1. 该命令用单引号引起来,而不是双引号,否则您的密码将永远无法使用
  2. 您运行它,--sudo否则最终会出现类似(useradd: cannot lock /etc/passwd; try again later)的错误

谢谢队友,我特别在寻找adhoc版本,并且遇到了与您提到的相同的报价问题
alexakarpov,


2

结合上面的一些解决方案,我创建了一个剧本,可根据存储在加密的本地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)。


2

如何创建用于将passwordvar 传递给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"

UPD:使用SHA-512的地穴,请参见此处此处

蟒蛇

$ 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/

1
这不是生成md5哈希密码吗?那不安全吗?
标记

2

您可以使用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希望那里的哈希值。
texnic

2

为用户生成随机密码

首先需要定义用户变量,然后再下面

任务:

- 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 }}'

1

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.'

1

两种解决方案都不能直接在我的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


1

我创建了一个ansible-playbook,可让您创建一个允许密码验证的linux帐户。

请参阅CreateLinuxAccountWithAnsible

哈希密码是使用mkpasswd命令生成的。我提供了mkpasswd在不同操作系统上安装的方法。

这是使用我的脚本所需的步骤:

  1. 用所需的用户名和密码替换<your_user_name><your_password>在内部run.sh

  2. 更改连接信息,inventory以便ansible可以连接到计算机以创建用户。

  3. 运行./run.sh以执行脚本。


1
该文件不再位于GitHub上。
Janus

0

如果您想通过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
}

0

我知道我参加晚会很晚,但是我正在使用另一种解决方案。对于--stdinpasswd二进制文件中没有的发行版,可能会很方便。

- 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进行加密。


0

我的解决方案是使用查找并自动生成密码。

---
- 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') }}"

0

尝试了许多实用程序,包括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"

-1

好吧,我完全迟到了:)我需要玩一个有趣的游戏,用随机密码创建多个本地用户。我想出了这一点,从顶部使用了一些示例,并进行了一些更改。

使用密码创建用户

---
# 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.