Ordering dependencies and accessing state created earlier *in the same run*

39 views
Skip to first unread message

Giovanni Torres

unread,
Jan 23, 2015, 6:38:24 AM1/23/15
to puppet...@googlegroups.com
Hello All!

I was hoping you could help me with the following scenario, which is replicated in the code below:

$username = 'whatuidwillthisuserget'

user { $username:
    ensure => present,
}

$uid = generate('/usr/bin/id', '--user', $username)

notify {'showuid':
    message => "The uid for user $username is $uid"
}

User<||> -> Notify<||>

This will fail if $username does not exist. If it does, it goes OK. Now, our real scenario is the following:

We install Openstack components (cinder, nova and neutron) via their Puppet modules. These modules install the packages nova-common, cinder-common and neutron-common. These packages create the users nova, neutron and cinder, if not already in the system.

Then, we need to get the uids of these users before we apply our Linux's auditd module, so we can filter out all the sudo calls those users make (after we make sure sudo configuration is sane). Unfortunally, auditd in Ubuntu 12.04.4 does not let us use usernames, only udis. We apply these types of rules:

exit,always watch=/usr/bin/sudo perm=x auid!=108 (0x6c) uid!=108 (0x6c) auid!=106 (0x6a) uid!=106 (0x6a) auid!=107 (0x6b) uid!=107 (0x6b) key=privilege_escalation

So, we have something along these lines:

class{ 'nova': }
class {'cinder': }
class {'neutron': }
class {'auditd'}

Class['nova', 'cinder, 'neutron'] -> Class['auditd']

My question: Is there any way to make it work *in a single run*?

This works very well in multiple runs, but in a single run, *when the users do not exist* fails.

We have tried the following approaches:

o Puppet functions written in Ruby

o Facts

o A more complicated version of the generate function shown earlier, to avoid the error it causes when /usr/bin/id returns 1.

We are currently using Puppet 3.4.2 and Facter 1.7.3.

Thank you all! I hope I made myself understood!

Giovanni

jcbollinger

unread,
Jan 26, 2015, 9:31:39 AM1/26/15
to puppet...@googlegroups.com


On Friday, January 23, 2015 at 5:38:24 AM UTC-6, Giovanni Torres wrote:
Hello All!

I was hoping you could help me with the following scenario, which is replicated in the code below:

$username = 'whatuidwillthisuserget'

user { $username:
    ensure => present,
}

$uid = generate('/usr/bin/id', '--user', $username)

notify {'showuid':
    message => "The uid for user $username is $uid"
}

User<||> -> Notify<||>

This will fail if $username does not exist. If it does, it goes OK.


Well, maybe.  Like all Puppet DSL functions, 'generate()' runs during catalog building.  In a master/agent setup, therefore, the code presented determines the id assigned to the user on the master, if he exists on the master.  The overall idea makes sense only if you are not centrally managing UID numbers, in which case the existence and UID of the user on the master are not relevant.  This approach might be more appropriate in a masterless setup, though the point is, I suppose, that it's flawed anyway.

 
Now, our real scenario is the following:

We install Openstack components (cinder, nova and neutron) via their Puppet modules. These modules install the packages nova-common, cinder-common and neutron-common. These packages create the users nova, neutron and cinder, if not already in the system.

Then, we need to get the uids of these users before we apply our Linux's auditd module, so we can filter out all the sudo calls those users make (after we make sure sudo configuration is sane). Unfortunally, auditd in Ubuntu 12.04.4 does not let us use usernames, only udis. We apply these types of rules:

exit,always watch=/usr/bin/sudo perm=x auid!=108 (0x6c) uid!=108 (0x6c) auid!=106 (0x6a) uid!=106 (0x6a) auid!=107 (0x6b) uid!=107 (0x6b) key=privilege_escalation

So, we have something along these lines:

class{ 'nova': }
class {'cinder': }
class {'neutron': }
class {'auditd'}

Class['nova', 'cinder, 'neutron'] -> Class['auditd']

My question: Is there any way to make it work *in a single run*?

This works very well in multiple runs, but in a single run, *when the users do not exist* fails.

We have tried the following approaches:

o Puppet functions written in Ruby


As already stated, Puppet functions run during catalog building.  That timing is not helpful for you, and possibly that location is not helpful, either.
 


o Facts



Facts are evaluated even earlier, as a prelude to the catalog request.  You could use them on second and subsequent runs to determine the chosen UIDs, but they cannot provide information that has not yet been determined when the catalog run starts.

 
o A more complicated version of the generate function shown earlier, to avoid the error it causes when /usr/bin/id returns 1.



Again, no parser function can serve here.

I see three main alternatives:

1) Use custom facts to determine the chosen UIDs, and accept that it will take two runs for your configuration to converge.

2) Use an Exec resource around a custom script to manage [the relevant part of] your auditd configuration.

3) Pre-assign the needed UIDs.

A few additional words about (3):
o As a threshold issue, any ability to pre-assign UIDs depends on having a reserved range of UIDs on which you can draw.  It is conventional on Linux for the lowest-number UIDs (up to 99 or sometimes 499) to be reserved for system accounts, which is a reasonable characterization of the accounts in question, so perhaps you can choose UIDs there.
o Having chosen UIDs, you would use Puppet to manage the corresponding users.  Ensure that each user is managed before the corresponding package, at least when you are ensuring the package present.  In all likelihood, the packages will not create a new account if a suitably-named one already exists.
o Do test out this approach manually (i.e. that the packages are willing to use an existing account) before writing Puppet code around it, just to be sure.


John

Giovanni Torres

unread,
Jan 28, 2015, 1:47:14 AM1/28/15
to puppet...@googlegroups.com


On Monday, January 26, 2015 at 4:31:39 PM UTC+2, jcbollinger wrote:

 [snip]
 
I see three main alternatives:

1) Use custom facts to determine the chosen UIDs, and accept that it will take two runs for your configuration to converge.

2) Use an Exec resource around a custom script to manage [the relevant part of] your auditd configuration.

3) Pre-assign the needed UIDs.

A few additional words about (3):
o As a threshold issue, any ability to pre-assign UIDs depends on having a reserved range of UIDs on which you can draw.  It is conventional on Linux for the lowest-number UIDs (up to 99 or sometimes 499) to be reserved for system accounts, which is a reasonable characterization of the accounts in question, so perhaps you can choose UIDs there.
o Having chosen UIDs, you would use Puppet to manage the corresponding users.  Ensure that each user is managed before the corresponding package, at least when you are ensuring the package present.  In all likelihood, the packages will not create a new account if a suitably-named one already exists.
o Do test out this approach manually (i.e. that the packages are willing to use an existing account) before writing Puppet code around it, just to be sure.

Thank you John. It is a master-less setup, I forgot to mention. This clarifies several misunderstandings I had. 

Giovanni

Hunter Haugen

unread,
Jan 28, 2015, 8:23:00 AM1/28/15
to puppet-users
The way to think about getting commands to run during the apply phase is either by using exec resource (which basically don't have a return value so don't allow you to access the data you want) or with providers.

In your example, if you wrote a custom notify provider, then instead of using the generate() method you could have the new provider run the `id` command as part of its functionality, and that could be used in the output. The user resource would be evaluated -> the user resource provider would create the user -> the notify would be evaluated -> the notify provider would run `id` and print the id of the user.

The openstack world makes heavy use of custom types & providers for this reason, and I can highly recommend O'Reilly's "Puppet Types and Providers" book to get started.



-Hunter

--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/fb03058b-ec59-42d8-9d41-29046b91329b%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages