38

I need to create a test user with a password using puppet.

I've read that puppet cannot manage user passwords in a generic cross-platform way, which is a pity. I am doing this for Red Hat Enterprise Linux Server release 6.3.

I do as follows:

user { 'test_user': 
  ensure   => present,
  password => sha1('hello'),
}

puppet updates the password of the user, but Linux says login/pwd incorrect when I try to log in.

It works (I can login) if I set the password manually in Linux with sudo passwd test_user, and then look at /etc/shadow and hardcode that value in puppet. something like:

user { 'test_user': 
  ensure   => present,
  password => '$1$zi13KdCr$zJvdWm5h552P8b34AjxO11',
}

I've tried also by adding $1$ in front of the sha1('hello'), but it does not work either (note, $1$ stands for sha1).

How to modify the first example to make it work (using the plaintext password in the puppet file)?

P.S.: I am aware that I should use LDAP, or sshkeys, or something else, instead of hardcoding the user passwords in the puppet file. however, I am doing this only for running a puppet vagrant test, so it is ok to hardcode the user password.

Meraj al Maksud
  • 1,528
  • 2
  • 22
  • 36
David Portabella
  • 12,390
  • 27
  • 101
  • 182
  • I met a similar problem to yours (on CentOS 6), and ended up hardcoding the hash produced from `openssl passwd` anyway - my guess is that sha1 is the wrong algorithm, but Puppet doesn't seem to supply any other hashing algorithms. – xiankai Oct 02 '13 at 06:40
  • 2
    @xiankai Yes, as I see `passwd` uses `DES` for password encryption (see `man crypt`) – Slava Semushin Oct 07 '13 at 15:41

8 Answers8

38

Linux users have their passwords stored as hash in /etc/shadow file. Puppet passes the password supplied in the user type definition in the /etc/shadow file.

Generate your hash password using openssl command:

 #openssl passwd -1  
 #Enter your password here 
 Password: 
 Verifying - Password: 
 $1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM

The previous example generate this hash: $1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM/

Add this hash password to your class as shown (do not forget the quotes)

user { 'test_user': 
  ensure   => present,
  password => '$1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM/',
}
OtherDevOpsGene
  • 7,302
  • 2
  • 31
  • 46
Avinash Singh
  • 1,006
  • 9
  • 10
  • According to the openssl passwd --help docs, using -1 uses MD5 as a hashing algorithm. It doesn't seem to have an option for any SHA based hashes so I don't think this is a good method. – agxs Jan 11 '23 at 10:14
  • 1
    Further to this, newer versions do include SHA-512 hashes, but you need to pass -6 and not -1. – agxs Jan 31 '23 at 09:54
17

The stdlib package of puppetlabs implements a similar pw_hash function of the accepted answer.

Be sure to add the library to your configuration. If you use librarian, just add in your Puppetfile

mod 'puppetlabs-stdlib'

Then to create an user, simply :

user { 'user':
  ensure => present,
  password => pw_hash('password', 'SHA-512', 'mysalt'),
}
mperrin
  • 994
  • 1
  • 10
  • 19
  • 2
    Best method by far because OS independent. All other shown methods require a specific OS or packages in order to work, ps_hash seems to work with all *nix OS. Also it supports salts by default which other shown methods do not. @mperrin You got a typo in your example: the "myhash" should be "mysalt". – omni Aug 20 '15 at 13:46
  • 3
    how can I avoid storing the plaintext password and use `pw_hash` at the same time? – Felipe Alvarez Mar 18 '16 at 06:01
  • 1
    All my sensitive information like plain text passwords or certificates are stored in a hiera file encrypted with gpg. I use the tool developed by stackoverflow staff Blackbox to help me in the daily tasks of encrypting / decrypting / deploying and sharing with trusted collaborators. – mperrin Mar 18 '16 at 12:48
  • An alternative to GPG, which seems to be well supported out-of-the-box in current Puppet releases, is eyaml: https://github.com/voxpupuli/hiera-eyaml – pioto Dec 20 '18 at 19:59
12

The sha1 function in puppet is not directly intended for passwd entries, as you figured out. I'd say setting the hash rather than the password is good practice! You are not really supposed to be able to recover a password anyway - you can generate it once, or you can have puppet generate it every time - generating that hash once should be enough IMHO... You can generate a password on Debian/Ubuntu like this:

pwgen -s -1 | mkpasswd -m sha-512 -s

...on CentOS you can use some grub-crypt command instead of mkpasswd...

bryn
  • 3,155
  • 1
  • 16
  • 15
  • 2
    If you cannot get password authentication to work even though you are using the right hashing algorithm, your Puppet installation may not be able to modify your `/etc/shadow` because of a missing libshadow-library. I blogged about this pitfall in more detail [here](http://www.relativkreativ.at/articles/two-common-pitfalls-when-using-hashed-passwords-with-puppet). – Michael Trojanek May 27 '14 at 07:17
10

I had success (gist) with ruby's String#crypt method from within a Puppet parser function.

AFAICS it's using the crypt libc functions (see: info crypt), and takes the same arguments $n$[rounds=<m>$]salt, where n is the hashing function ($6 for SHA-512) and m is the number of key strengthening rounds (5000 by default).

Paul Schyska
  • 666
  • 8
  • 17
  • 1
    Below copied from the link: $pass='password' $salt='salt' user{ "alise": ensure => present, password => inline_template("<%= '$pass'.crypt('\$6$$salt') %>"), } – AhHatem Jul 12 '19 at 20:03
3

You can use the generate function to let Puppet create the hash for you:

$password = 'hello'

user { 'test_user':
    ensure   => 'present',
    password => generate('/bin/sh', '-c', "mkpasswd -m sha-512 ${password} | tr -d '\n'"),
}
Behrang
  • 46,888
  • 25
  • 118
  • 160
2

Puppet: user with a SHA 512 hashed password

I came up with a method that doesn't need anything to add if you have python 2.6. I tested this on puppet 3.6.2 on CentOS 6.4:

$pass="password"
$shatag="\$6\$"
$cmd="import crypt, base64, os, sys; sys.stdout.write(crypt.crypt('$pass', '$shatag' + base64.b64encode(os.urandom(16))[:8]))"
user { 'boop':
  ensure   => present,
  password => generate ("/usr/bin/python", "-c", $cmd),
}

Explanations

  1. the sha tag is here to specify to crypt the hash method we want: 6 is the type of hash for SHA-512

    • $1$ -> MD5
    • $2a$ -> Blowfish (not in mainline glibc; added in some Linux distributions)
    • $5$ -> SHA-256 (since glibc 2.7)
    • $6$ -> SHA-512 (since glibc 2.7)

thx davey and wiki_crypt

  1. sys.stdout.write is here to avoid '\n' of print

  2. base64.b64encode(os.urandom(16))[:8]):

    • os.urandom(16) create a 16 bits long binary string
    • base64.b64encode encode this string in base64
    • [:8] take the first 8 characters of this string (as base64 encoding length may vary)
  3. generate is a puppet function that create text when on the puppet master. You can't use this function like you want because it is 'protected' ê.é (last post suggest a workaround to this protection-or-whatever)

hth

Community
  • 1
  • 1
Boop
  • 1,217
  • 1
  • 15
  • 22
1

In my Vagrantfile, I did this:

$newuserid = ENV["USERNAME"]

config.vm.provision :puppet do |puppet|
    puppet.module_path    = "modules"
    puppet.manifests_path = "manifests"
    puppet.manifest_file  = "main.pp"
    puppet.facter         = {"newuserid" => $newuserid}
    puppet.options        = "--verbose"    
end

And in my main.pp file:

user { $newuserid :
  ensure  => present,
  home    => "/home/${newuserid}",
  managehome => true,
  gid => "mygid",
}

exec { 'set password':
  command => "/bin/echo \"${newuserid}:${newuserid}\" | /usr/sbin/chpasswd",
  require => User [ $newuserid ],
}
Lyle Z
  • 1,269
  • 10
  • 7
0

just generate encrypted password from grub-crypt --sha-512 and paste

Creek
  • 1