Re: [Puppet Users] rand losing its randomness after using fqdn_rand

870 views
Skip to first unread message

R.I.Pienaar

unread,
Aug 1, 2012, 1:13:00 PM8/1/12
to puppet...@googlegroups.com


----- Original Message -----
> From: "Felipe Ortega" <orte...@gmail.com>
> To: puppet...@googlegroups.com
> Sent: Wednesday, August 1, 2012 5:28:23 AM
> Subject: [Puppet Users] rand losing its randomness after using fqdn_rand
>
>
> Hi,
>
>
> I'm a newbie puppet user, and I'm facing some weird behaviour in my
> testing environment.
> I'm using Debian packages from testing/Wheezy (version 2.7.18) via
> apache+passenger installation. Also:
>
>
> $ ruby -v
> ruby 1.8.7 (2012-02-08 patchlevel 358) [x86_64-linux]
>
>
> I developed the following custom function (with some help from
> Google) to generate the shadow password of any new user:
>
>
> module Puppet::Parser::Functions
> newfunction(:shadow_pwd, :type => :rvalue) do |args|
> passwd = args[0]
> case args[1]
> when 'md5'
> algo = '$1$'
> when 'blowfish'
> algo = '$2$'
> when 'sha256'
> algo = '$5$'
> when 'sha512'
> algo = '$6$'
> end
> o = [('a'..'z'),('A'..'Z'),('0'..'9')].map{|i| i.to_a}.flatten
> salt = (0..8).map{ o[rand(o.length)] }.join
> hash = passwd.crypt(algo + salt)
> end
> end
>
>
> it takes two arguments, the cleartext password and the algorithm to
> encrypt it.
>
>
> So, with this setup, on every run of the puppet agent, a new shadow
> password was assigned to the user. Well, in fact it was always the
> same cleartext password, but as the salt was different on every run,
> the shadow password of the user was different too, and puppet
> updated the user password accordingly.
>
>
> Here comes a new class, puppet, to manage the agent configuration on
> every node. I chose to run puppet agent via cron task, and in order
> to prevent every agent try to get the catalog at the same time, I
> use the following code snippet (picket up online):
>
>
> $first = fqdn_rand(30)
> $second = $first + 30
> cron {'puppet':
> command => '/usr/bin/puppet agent --no-daemon --onetime',
> user => 'root',
> minute => [$first,$second],
> ensure => present,
> require => Class['puppet::install'],
> }
>
>
> This works OK too, it creates a new task in the crontab file of user
> root, executing the command twice an hour, always on the same two
> minutes.
>
>
> But then I realized the shadow password of the users were not being
> updated anymore (only when I change the cleartext password). After
> some debugging, I found out that the salt was always the same!
> Further debugging led me to the definition of the fqdn_rand
> function, and the culprit seems to be this line:
>
>
> srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),args].join(':')).hex)
>
>
> which sets the seed used for the rand function.
>
>
> After all this stuff, what should I do? Is it a bug in fqdn_rand?
> Because after using it, rand loses its randomness. Or, is it my
> fault for not setting the seed in my custom function? If so, how and
> where should a set the seed so it works as before using fqdn_rand?

I'd say this is a bug in fqdn_rand, but if you wish to work around it
in your function you can also just call srand() when your function get
called

Would be great if you could file a bug about fqdn_rand

Eric Shamow

unread,
Aug 1, 2012, 1:48:26 PM8/1/12
to puppet...@googlegroups.com
Not sure that this should be considered a bug in fqdn_rand - the idea with fqdn_rand is that it should generate the same random number each time it is run in order to maintain idempotency.

The salt will be different on *different* hosts, but it will be the same on the same host.

-Eric

--

Eric Shamow
Professional Services
http://puppetlabs.com/
(c)631.871.6441
> --
> You received this message because you are subscribed to the Google Groups "Puppet Users" group.
> To post to this group, send email to puppet...@googlegroups.com (mailto:puppet...@googlegroups.com).
> To unsubscribe from this group, send email to puppet-users...@googlegroups.com (mailto:puppet-users...@googlegroups.com).
> For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.



R.I.Pienaar

unread,
Aug 1, 2012, 1:58:19 PM8/1/12
to puppet...@googlegroups.com


----- Original Message -----
> From: "Eric Shamow" <er...@puppetlabs.com>
> To: puppet...@googlegroups.com
> Sent: Wednesday, August 1, 2012 10:48:26 AM
> Subject: Re: [Puppet Users] rand losing its randomness after using fqdn_rand
>
> Not sure that this should be considered a bug in fqdn_rand - the idea
> with fqdn_rand is that it should generate the same random number
> each time it is run in order to maintain idempotency.

The bug is that it does:

* set salt to cause consistant random numbers
* get random data

I think it should do:

* set salt to cause consistant random numbers
* get random data
* reset salt to produce random data

This will retain the behaviour of fqdn_rand and not break random for everyone else

Calvin Walton

unread,
Aug 1, 2012, 2:30:52 PM8/1/12
to puppet...@googlegroups.com
On Wed, 2012-08-01 at 18:58 +0100, R.I.Pienaar wrote:
> From: "Eric Shamow" <er...@puppetlabs.com>
> > Not sure that this should be considered a bug in fqdn_rand - the idea
> > with fqdn_rand is that it should generate the same random number
> > each time it is run in order to maintain idempotency.
>
> The bug is that it does:
>
> * set salt to cause consistant random numbers
> * get random data
>
> I think it should do:
>
> * set salt to cause consistant random numbers
> * get random data
> * reset salt to produce random data

> This will retain the behaviour of fqdn_rand and not break random for everyone else

I was going to say that an even *better* solution would be to do this:

* Create a private Random object for use only by fqdn_rand
* Set the seed on the private Random object, without disturbing
the Kernel.rand implementation
* get random data from the private Random object

...but then I remembered that the Random class was introduced in Ruby
1.9, so this won't work on older versions like 1.8.7, and I had
forgotten that fqdn_rand should always return the same number on the
same machine when it is called with the same arguments.

The definition of 'srand' is actually kind of interesting:
srand(number=0) => old_seed
so the patch to fix this is actually quite trivial:

diff --git a/lib/puppet/parser/functions/fqdn_rand.rb b/lib/puppet/parser/functi
index 93ab98b..987815c 100644
--- a/lib/puppet/parser/functions/fqdn_rand.rb
+++ b/lib/puppet/parser/functions/fqdn_rand.rb
@@ -7,6 +7,7 @@ Puppet::Parser::Functions::newfunction(:fqdn_rand, :type => :rva
$random_number_seed = fqdn_rand(30,30)") do |args|
require 'digest/md5'
max = args.shift
- srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),args].join(':')).hex)
+ old_seed = srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),args].join(':')).hex)
rand(max).to_s
+ srand(old_seed)
end

--
Calvin Walton <calvin...@kepstin.ca>

David Schmitt

unread,
Aug 1, 2012, 5:11:12 PM8/1/12
to puppet...@googlegroups.com
On 2012-08-01 14:28, Felipe Ortega wrote:
> So, with this setup, on every run of the puppet agent, a new shadow
> password was assigned to the user. Well, in fact it was always the same
> cleartext password, but as the salt was different on every run, the
> shadow password of the user was different too, and puppet updated the
> user password accordingly.


Others have already answered about the puppet bug. I'd like to
additionally point out, that it's Bad Practice to generate multiple
hashes from the same cleartext as this will reduce the amount of work
needed when attacking the hash.


Best Regards, David

Felipe Ortega

unread,
Aug 2, 2012, 5:59:34 AM8/2/12
to puppet...@googlegroups.com
Hi again,

I've tried the patch submitted by Calvin Walton, and it's almost working. There are two remaining issues:

 1.- The patch needs some more lines, because it returns the "new old seed" value. So the new patch would be:

diff --git a/puppet/parser/functions/fqdn_rand.rb.orig b/puppet/parser/functions/fqdn_rand.rb
index 93ab98b..6482449 100644
--- a/puppet/parser/functions/fqdn_rand.rb.orig
+++ b/puppet/parser/functions/fqdn_rand.rb
@@ -7,6 +7,8 @@ Puppet::Parser::Functions::newfunction(:fqdn_rand, :type => :rvalue, :doc =>
       $random_number_seed = fqdn_rand(30,30)") do |args|
     require 'digest/md5'
     max = args.shift
-    srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),args].join(':')).hex)
-    rand(max).to_s
+    old_seed = srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),args].join(':')).hex)
+    exit_value = rand(max).to_s
+    srand(old_seed)
+    exit_value
 end

2.- I need to restart apache on the master server (remember I was using Passenger) to get a different salt value of the shadow password. Without the patch, I always get the same salt value, no matter if I restart the apache server or not.  
Reply all
Reply to author
Forward
0 new messages