Question

The documentation refers us to the github example, but this is a bit sparse and mysterious.

It says this:

# created with:
# crypt.crypt('This is my Password', '$1$SomeSalt')
password: $1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.

but crypt.crypt doesn't emit what the example shows. It also uses MD5.

I tried this:

# python
import crypt
crypt.crypt('This is my Password', '$6$somereallyniceandbigrandomsalt$')
>> '$69LxCegsnIwI'

but the password field of user should get something like this:

password: $6$somereallyniceandbigrandomsalt$UqddPX3r4kH3UL5jq5/ZI.

which includes three $ delimiters separating the 6 (which signifies that its a SHA-512 hash), the salt, and the crypted password.

Note that the python crypt docs don't mention anything about the $N format.

Questions:

  1. Is the salt, as supplied to crypt.crypt, supposed to end with a trailing $ or is it in $N$SALT format?

  2. Python docs refer to DES, but how is SHA-512 or MD5 being called and where is the documention for this?

  3. Am I really supposed to take the output of crypt.crypt and cut off the first $6 and make $N$SALT$CRYPTED? Is this what ansible needs?

Was it helpful?

Solution

The python example shown in the documentation depends on what version of crypt is running on the OS you are using.

I generated the crypt on OS X and the server I was targetting is ubuntu.

Due to differences in which implementation of crypt is offered by the OS, the result is different and incompatible.

Use this instead:

http://pythonhosted.org/passlib/

Passlib is a password hashing library for Python 2 & 3, which provides cross-platform implementations of over 30 password hashing algorithms, as well as a framework for managing existing password hashes. It’s designed to be useful for a wide range of tasks, from verifying a hash found in /etc/shadow, to providing full-strength password hashing for multi-user application.

>>> # import the hash algorithm
>>> from passlib.hash import sha512_crypt

>>> # generate new salt, and hash a password
>>> hash = sha512_crypt.encrypt("password")
>>> hash

'$6$rounds=656000$BthPsosdEpqOM7Qd$l/ln9nyEfxM67ea8Bvb79JoW50pGjf6iM87taIvfSmpjasE4/wBG1.60pFS6W992T7Q1q2wikMbxYUvMHD1tT1'

OTHER TIPS

This has been updated in the Ansible docs. There are two preferred ways:

How do I generate crypted passwords for the user module?

The mkpasswd utility that is available on most Linux systems is a great option:

mkpasswd --method=SHA-512 If this utility is not installed on your system (e.g. you are using OS X) then you can still easily generate these passwords using Python. First, ensure that the Passlib password hashing library is installed.

pip install passlib

Once the library is ready, SHA512 password values can then be generated as follows:

python -c "from passlib.hash import sha512_crypt; import getpass; print sha512_crypt.encrypt(getpass.getpass())"

This worked for me (using python 2.7.4):

python
>>> import crypt
>>> crypt.crypt('thisismypassword', '$6$Som3S@lt$')
'$6$Som3S@lt$XGoe9ONI00NaTkYn46CLDr8TSkvkovahinFqy95vrSe5Hzx2999C9mgF76ODFRnXMJHUCWFHLdkYd3c7AB9WV.'

I have a vars.yml that looks like this:

---
password: $6$Som3S@lt$XGoe9ONI00NaTkYn46CLDr8TSkvkovahinFqy95vrSe5Hzx2999C9mgF76ODFRnXMJHUCWFHLdkYd3c7AB9WV.

and a playbook.yml like this:

---
- hosts: vagrant
  vars_files:
    - vars.yml
  user: vagrant

  tasks:
  - name: create artefactual user
    user: name=artefactual state=present password={{password}} shell=/bin/bash

I run my playbook using vagrant, vagrant up , and then from another console I can ssh to the newly created vm using the artefactual user created by ansible, with the password thisismypassword.

I just copied the output of crypt.crypt into the ansible variable called password and used that. The output of crypt that you show in your question looks too short, I am not sure why you got that, perhaps a different version of python?

You can use the jinja2 filters that have the capability to handle the generation of encrypted passwords. Here is a working example to create the linux user with the provided password:

- name: Creating Linux User
  user:
    name: "{{ myuser }}" 
    password: "{{ mypassword | password_hash('sha512') }}"

Hope this will help you and others.

I took @felix's answer and made it into a script that I could include in a docker project that I am working on. I know that a lot of developers use macOS/OSX and that there is no mkpasswd on that platform, so I'm saving them the Googling.

I have added the following options:

  • PROCESS_TIME (boolean)
    • Enables 2nd line of output with number of rounds and CPU time
  • ROUNDS (integer)
    • Overrides the default_rounds value which is tuned to take ~300ms on an "average" system. You want a minimum of 100ms, but should be as great as you can afford.
#!/usr/bin/env python3

# Because OSX doesn't have mkpasswd...

# Based on https://stackoverflow.com/a/17992126/117471
# python3 -c "from passlib.hash import sha512_crypt; print(sha512_crypt.encrypt(input()))" <<< bruno  # NOQA

# Usage:
#
# $ ./mkpasswd.py
# Password:
# $6$rounds=656000$pfFmQISGcjWHOCxW$rBptiSK.tqSPnUiq6KiSHzz6LvvW/x1SjkkWFwxWB9Dt75NLNBs0N3OyGV4K5ejjBs/u.o3jtigvUKbmmwVQP.
#
# $ PROCESS_TIME=1 ./mkpasswd.py
# Password:
# $6$rounds=656000$e0OGrad82DBrUo9T$ldqtOdN54gmXI6nb0D.Y5mm5ih.LIQm/Ep/bkNL76.3hE65FqXA9wyZ.M5YOrv6dSvwhPAktXGJ6LJT0Fgd4x.
# 656000 rounds in 1.008705 seconds of cpu time
#
# $ ROUNDS=1280000 PROCESS_TIME=1 ./mkpasswd.py <<< bruno
# $6$rounds=1280000$QO5FSyw5rQpiY6PI$0zRMJ4RzCbH61XxIdpsUm/79.VZ13Mm9TBN9GvJwt1LI1U5FVzakrLya5VJsXlTou3p5ZeWmo29bIUjubRuc31
# 1280000 rounds in 1.9206560000000001 seconds of cpu time

import os
import sys
import time
from getpass import getpass
from passlib.hash import sha512_crypt

rounds = os.environ.get('ROUNDS')
if not rounds:
    rounds = sha512_crypt.default_rounds

passwd = input() if not sys.stdin.isatty() else getpass()

proc = sha512_crypt.using(rounds=rounds)
start = time.process_time()
out = proc.encrypt(passwd)
end = time.process_time()

print(out)

if os.environ.get('PROCESS_TIME'):
    print('{} rounds in {} seconds of cpu time'.format(rounds, end-start))

I have been using the following shell command to set the password.

- name: "Set user password: someuser"
  command: 'echo "somepassword"| passwd --stdin "someuser"'
  sudo: yes

try like this

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"

This needs pwgen installed on target host:

- name: generate linux user password
  local_action: shell /usr/bin/pwgen 16 1
  register: generated_linux_user_password

Use hosts: localhost, set_fact and hostvars, if you need the 'variable' be globally available (facts are readonly after creation):

{{hostvars['localhost']["new_fact"]}}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top