用Ansible创build一个新的用户和密码

我有一个在Ubuntu 12.04上创build一个新用户的任务。

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

它按预期完成,但是当我以该用户身份login并尝试使用密码sudo时,我将其设置为始终表示不正确。 我究竟做错了什么?

如果你阅读Ansible的user模块手册,它会指导你到Ansible的例子github回购详情如何使用password参数 。

你会看到你的密码必须被散列。

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

如果您的剧本或命令行以纯文本forms显示密码,这意味着您的影子文件中logging的密码哈希值是错误的。 这意味着当您尝试使用您的密码进行身份validation时,它的哈希将永远不会匹配。

另外,关于密码参数的一些细微差别,以及如何正确使用密码参见Ansible FAQ 。

我可能为时太晚回复,但最近我发现jinja2filter能够处理encryption密码的生成。 在我的main.yml我生成的encryption密码为:

 - 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传递给playbook,并注意我在这里使用了jinja2filter来encryption传递的密码。

我已经在下面添加了与此相关的教程到我的博客

我想提出另一个解决scheme:

 - 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戏剧应该是幂等的。 你应该把它们看作是一种命令性风格的一系列动作,而不是一种所希望的状态,即声明式的风格。 因此,您应该可以多次运行并获得相同的结果,即相同的服务器状态。

这一切听起来不错,但有一些细微之处。 其中之一是pipe理用户。 “期望状态”意味着每次运行一个创build用户的游戏时,他都会被更新为完全匹配该状态。 “更新”我的意思是他的密码也会改变。 但很可能这不是你所需要的。 通常情况下,你需要创build用户,设置和过期密码只有一次,进一步发挥运行不应该更新他的密码。

幸运的是,Ansible在user模块中有update_password属性来解决这个问题。 混合这与注册的variables,你也可以过期,只有当用户实际更新他的密码。

请注意,如果您手动更改用户的shell(假设您不喜欢恶意pipe理员在其播放中强制使用的shell),用户将被更新,因此他的密码将会过期。

还要注意如何在游戏中使用纯文本初始密码。 不需要将它们编码到其他地方并粘贴散列,可以使用Jinja2filter 。 但是,如果有人在你最初的工作之前碰巧login,这可能是一个安全漏洞。

试试这个

 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" 

Ansible“用户”模块以幂等的方式pipe理用户。 在下面的剧本中,第一个任务为用户声明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 

这是简单的方法:

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

用户模块的任务定义应该在最新的Ansible版本中有所不同。

 tasks: - user: name=test password={{ password }} state=present 

结合上面的几个解决scheme,我创build了一个剧本,可以根据存储在encryption的本地不可用的保pipe库文件中的明文密码自动生成正确的密码哈希:

 --- - 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”选项运行此命令来解密您的电子仓库文件(有关如何pipe理encryption电子仓库的信息,请参阅anault-vault)。

您可以使用安全保险库在剧本中使用密钥。 在yml中定义你的密码。

恩。 通过:秘密或

 user: pass: secret name: fake 

encryption你的秘密文件:

ansible-vault encrypt /path/to/credential.yml

ansible会要求密码进行encryption。 (我会解释如何使用该通行证)

然后你可以在你想要的地方使用你的variables。 没有保险箱钥匙,没有人可以阅读。

保险箱密钥使用情况:

运行playbook时通过传递参数。

 --ask-vault-pass: secret 

或者你可以保存到像password.txt文件,并隐藏在某个地方。 (对CI用户有用)

 --vault-password-file=/path/to/file.txt 

在你的情况:包括vars yml和使用你的variables。

 - include_vars: /path/credential.yml - name: Add deployment user action: user name={{user.name}} password={{user.pass}} 

如何创buildencryption的密码传递给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" 

UPD:crypt使用SHA-512看这里和这里 :

python

 $ python -c "import crypt, getpass, pwd; print crypt.crypt('password', '\$6\$saltsalt\$')" $6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/ 

Perl的

 $ perl -e 'print crypt("password","\$6\$saltsalt\$") . "\n"' $6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/ 

ruby

 $ ruby -e 'puts "password".crypt("$6$saltsalt$")' $6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/ 

Mxx的答案是正确的,但是当涉及不同的操作系统时,python crypt.crypt()方法是不安全的(与系统上使用的glibc哈希algorithm有关)。

例如,如果你从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.' 

此答案中的angular色的目的是为new_user_name生成随机密码并立即过期密码。 new_user_name需要在第一次login时更改密码。

create_user.yml:

 --- # create_user playbook - hosts: your_host_group become: True user: ansible roles: - create_user 

angular色/ 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 

当你想创build一个新的用户时:

 ansible-playbook -i hosts.ini create_user.yml --extra-vars "new_user_name=kelvin" 

这两个解决scheme都不能直接在我的Mac上控制Ubuntu。 所以为了别人的缘故,结合Mxx和JoelB的答案,下面是当前的Python 3解决scheme:

 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 $轮= 656000 $ $ SomeSalt oYpmnpZahIsvn5FK8g4bDFEAmGpEN114Fe6Ko4HvinzFaz5Rq2UXQxoJZ9ZQyQoi9zaBo3gBH / FEAov3FHv48

为了完整起见,我将使用ansible发布ad-hoc命令,因为这里也有一个捕获。

首先尝试使用大多数Linux系统上可用的mkpasswd实用程序生成encryption的密码:

 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

如果您想将其作为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 }