Newbie: Confused about where to start managing users...

329 views
Skip to first unread message

Peter Valdemar Mørch

unread,
Feb 8, 2012, 5:03:28 AM2/8/12
to puppet...@googlegroups.com
Hi,

Being a newbie, I'm trying to wrap my head around puppet. Here are my
first stumbling blocks:

We have an output from a database which is essentially a list of users
that we want to manage in the uid 2001-2999 range:

* No other users may be present in that range (puppet should delete them)
* Users outside that range must not be touched
* The user names change, but their uids will remain constant

So say that we start with no users in the 2001-2999 range and we have
this list of users in the range

peter (uid = 2001)
henrik (uid = 2002)
fred (uid = 2003)
barney (uid = 2004)

Creating/adding them is trivial based on http://docs.puppetlabs.com/learning/.

But now say that the new desired configuration driven by the databases is:

martin (uid = 2002)
barney (uid = 2003)
fred (uid = 2004)
sally (uid = 2005)

How do I achieve this:
* Get puppet to discover that peter (uid = 2001) must be deleted
* Get puppet to rename henrik->martin (trivial rename)
* Get puppet to rename fred->barney and barney->fred (complicated
rename) A third temporary username will be necessary, I guess, so that
it really becomes fred->tmp, barney->fred, tmp->barney, because
otherwise an attempt will be made to have non-unique users
temporarily. This necessary temporary user name doesn't swing well
with the declarative nature of puppet, I'm guessing.

I know exactly how to achieve these things in a shell script, but I
want to use puppet. I realize I'm going to have to have the database
output converted into either facts or manifests. I guess that
pre-processing could also identify users to be deleted, and even users
to be renamed. But the two-step rename I don't know how to even model
given the declarative nature of puppet.

Is it possible to write "myuser" so that all the above is done with just:

myuser { 2002:
name => 'martin',
}
myuser { 2003:
name => 'barney',
}
myuser { 2004:
name => 'fred',
}
myuser { 2005:
name => 'sally',
}

First step for a newbie is to ask the right questions. Am I even
asking the right questions? Does this make sense to anyone? Should I
just do this in a shell/perl script instead? What is it about this
task, that makes it unsuited for puppet?

Thanks for reading this far,
Peter

Dan White

unread,
Feb 8, 2012, 9:12:21 AM2/8/12
to puppet...@googlegroups.com
First trick with users across multiple machines is to have the same userid for the same login.

“Sometimes I think the surest sign that intelligent life exists elsewhere in the universe is that none of it has tried to contact us.”
Bill Waterson (Calvin & Hobbes)

> --
> 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.
> To unsubscribe from this group, send email to puppet-users...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
>

Peter Valdemar Mørch

unread,
Feb 8, 2012, 9:37:11 AM2/8/12
to puppet...@googlegroups.com
On Wed, Feb 8, 2012 at 3:12 PM, Dan White <yg...@comcast.net> wrote:
> First trick with users across multiple machines is to have the same userid for the same login.

I'm not sure I understand. I read this as a suggestion to make it
impossible to rename a user. "First trick is to change the
requirements" ;-) Did I understand that correctly? Of course, that'll
remove the problem of renaming users, I get that. That moves the
problem from puppet to user interface validation and we get a nasty
limitation in the UI (currently for no other reason than this). I was
hoping for another solution.

And it still leaves the challenge of removing "old"/"stale" users in the range.

Peter

jcbollinger

unread,
Feb 8, 2012, 10:23:21 AM2/8/12
to Puppet Users


On Feb 8, 4:03 am, Peter Valdemar Mørch <pmo...@gmail.com> wrote:
> Hi,
>
> Being a newbie, I'm trying to wrap my head around puppet. Here are my
> first stumbling blocks:
>
> We have an output from a database which is essentially a list of users
> that we want to manage in the uid 2001-2999 range:
>
> * No other users may be present in that range (puppet should delete them)
> * Users outside that range must not be touched


Neither below nor above? Would it be sufficient if only the UIDs
_below_ 2001 were protected?


> * The user names change, but their uids will remain constant


To give you a good answer, I need to understand this a bit better, and
I'm having trouble with that statement. On Unix-like systems the user
name is the primary identifier, and UIDs are only secondary. It is
even possible for two or more users to have the same UID. What, then,
does it mean for a user name to change while the UID remains
constant? I'm looking for the big picture here, not just the /etc/
passwd view of the world.


> So say that we start with no users in the 2001-2999 range and we have
> this list of users in the range
>
> peter (uid = 2001)
> henrik (uid = 2002)
> fred (uid = 2003)
> barney (uid = 2004)
>
> Creating/adding them is trivial based onhttp://docs.puppetlabs.com/learning/.
>
> But now say that the new desired configuration driven by the databases is:
>
> martin (uid = 2002)
> barney (uid = 2003)
> fred (uid = 2004)
> sally (uid = 2005)
>
> How do I achieve this:
> * Get puppet to discover that peter (uid = 2001) must be deleted
> * Get puppet to rename henrik->martin (trivial rename)
> * Get puppet to rename fred->barney and barney->fred (complicated
> rename) A third temporary username will be necessary, I guess, so that
> it really becomes fred->tmp, barney->fred, tmp->barney, because
> otherwise an attempt will be made to have non-unique users
> temporarily. This necessary temporary user name doesn't swing well
> with the declarative nature of puppet, I'm guessing.


You are astute. If there needs to be a renaming cycle then there is
no way to describe it in Puppet DSL. You could create a custom
extension of the underlying User provider that can perform such
cycles, but probably you don't need to do that.


> I know exactly how to achieve these things in a shell script, but I
> want to use puppet. I realize I'm going to have to have the database
> output converted into either facts or manifests. I guess that
> pre-processing could also identify users to be deleted, and even users
> to be renamed. But the two-step rename I don't know how to even model
> given the declarative nature of puppet.


I would recommend converting to manifests, or at least resource
declarations. You will find that far easier to work with.


> Is it possible to write "myuser" so that all the above is done with just:
>
> myuser { 2002:
>     name => 'martin',}
>
> myuser { 2003:
>     name => 'barney',}
>
> myuser { 2004:
>     name => 'fred',}
>
> myuser { 2005:
>     name => 'sally',
>
> }
>
> First step for a newbie is to ask the right questions. Am I even
> asking the right questions? Does this make sense to anyone? Should I
> just do this in a shell/perl script instead? What is it about this
> task, that makes it unsuited for puppet?


For just the tasks you have already mentioned, you don't need to write
a 'myuser' definition. Indeed, I don't think such a defined type
would be useful for getting around the issues you have identified.
Puppet's built-in resource types already have features that provide
much of what you describe, however.

Puppet supports purging unmanaged resources, and it has a special
provision for protecting 'system' user accounts from such a purge.
The principal caveat is that Puppet defines 'system' accounts as those
having UIDs less than or equal to a configurable upper bound. Out of
the box, it cannot limit a user purge to a range of UIDs that is
bounded above. If it would be sufficient to bound the purge range
only below, then you could do this:

resources { "user":
purge => true,
unless_system_user => 2000
}

Purging is the only activity Puppet supports for (otherwise) unmanaged
resources. If you do need to avoid purging accounts having UIDs
greater than 2999, however, then it probably wouldn't be too hard to
hack that into your Puppet. Or you could submit a feature request.
Or, a feature request accompanied by code and appropriate test cases
if you want the best chance of getting it quickly into the official
Puppet codebase.

If only a small number of accounts have UIDs above 2999, then you
could make the out-of-the-box purging support work for you by simply
putting those accounts under management. (Indeed, you could do the
same for some or all of the accounts with UIDs below 2001, too.) That
would be more consistent with the Puppet paradigm anyway.

Puppet probably can handle your complex renaming cases by transiently
leveraging the ability (available on many, but not all, client OSs)
for one UID to be assigned to multiple users:

user { 'martin':
uid => 2002,
allowdupe => true,
}

user { 'barney':
uid => 2003,
allowdupe => true,
}

user { 'fred':
uid => 2004,
allowdupe => true,
}

user { 'sally':
uid => 2005,
allowdupe => true,
}


So far, none of this touches on user home directories. Puppet's User
resource does have the ability to manage home directories on most OSs
(unless you are relying on LDAP for your user DB), but it's not clear
to me what management, if any, you might want there. This is where my
confusion over what you mean about renaming accounts comes most to
bear.


John

Dan White

unread,
Feb 8, 2012, 10:33:57 AM2/8/12
to puppet...@googlegroups.com
http://www.puppetcookbook.com/posts/remove-all-unmanaged-host-entries.html

Like this, but with users instead of hosts

“Sometimes I think the surest sign that intelligent life exists elsewhere in the universe is that none of it has tried to contact us.”
Bill Waterson (Calvin & Hobbes)

Dan White

unread,
Feb 8, 2012, 10:43:00 AM2/8/12
to puppet...@googlegroups.com
About renaming a user:

In practice, I try to avoid this because there are too many things a username touches for me to be comfortable that I have caught it all.

Easier to delete the old user and then create a new one.

The complication happens if there are files that need to be preserved.

“Sometimes I think the surest sign that intelligent life exists elsewhere in the universe is that none of it has tried to contact us.”
Bill Waterson (Calvin & Hobbes)

----- Peter Valdemar Mørch <pmo...@gmail.com> wrote:

Peter Valdemar Mørch

unread,
Feb 8, 2012, 12:02:52 PM2/8/12
to puppet...@googlegroups.com
On Wed, Feb 8, 2012 at 4:23 PM, jcbollinger <John.Bo...@stjude.org> wrote:
> To give you a good answer, I need to understand this a bit better, and
> I'm having trouble with that statement.  On Unix-like systems the user
> name is the primary identifier, and UIDs are only secondary.  It is
> even possible for two or more users to have the same UID.  What, then,
> does it mean for a user name to change while the UID remains
> constant?  I'm looking for the big picture here, not just the /etc/
> passwd view of the world.

The big picture:

We create an appliance (debian-in-a-pizza-box). In this appliance, one
can create users. There is a "users" database table. In that, the user
ID is unique, but the UI allows the user to modify user names (along
with e.g. password).

A new feature request is that it should be possible for such
configured users to log in vial SSH to the appliance, because it may
have network access to other networks than the user has from his
browser/workstation and use the appliance as a "jump host". So now the
task is to create local users based on the contents of our "users"
database table. The UI for his table also allows configuration of a
password (details about sha512 removed here) and SSH key. They must
have their own home dirs so they can use the appliance as a TFTP
server (details removed).

In order to get a little separation for these "CLI users", we create a
debootstrap/chroot for these users. So sshd_config's ChrootDirectory
is set up appropriately for these users, and for each user, we create
/jail/home/<username>, /jail/home/<username>/.ssh/authorized_keys,
/home/<username> and /home/<username>/.ssh/authorized_keys that is a
soft link to /jail/home/<username>/.ssh/authorized_keys (I want the
user to be able to add to configure his own authorized keys via CLI
too, and sshd reads .ssh/authorized_keys from the "outer" root, not
the jail, even for ChrootDirectory users, for some reason I don't
understand.)

As users come and go and get renamed, I expect /home, /jail/home,
/etc/passwd and /jail/etc/passwd to follow suit. I'm thinking that
doing the setup inside the jail can be done with installing puppet
inside the jail too and running puppet once again inside the jail with
setup from outside the jail. Exact same complication in the jail as
outside. Solve it for one and its solved for the other.

> If it would be sufficient to bound the purge range
> only below, then you could do this:
>
> resources { "user":
>    purge => true,
>    unless_system_user => 2000
> }

Cool! Yes, that is fine. We just want the possibility of creating real
non-system and non-chroot users too.

> Puppet probably can handle your complex renaming cases by transiently
> leveraging the ability (available on many, but not all, client OSs)
> for one UID to be assigned to multiple users:

...


> So far, none of this touches on user home directories.  Puppet's User
> resource does have the ability to manage home directories on most OSs
> (unless you are relying on LDAP for your user DB), but it's not clear
> to me what management, if any, you might want there.  This is where my
> confusion over what you mean about renaming accounts comes most to
> bear.

The most important is the user "foo" has home dir "/home/foo" and
correct uid. Ideal would be that if a user is renamed from a to b,
that /home/a is renamed to /home/b. We can live with "sudo rm -r
/home/a; sudo mkdir /home/b; chown b: /home/b; #setup /home/b" too
(don't expect user renames to be frequent). Regardless of whether one
does a "mv" or "rm && mkdir" the complex ( "fred->barney" +
"barney->fred" ) rename will be a two-step process, I'm affraid. How
likely is it? Not very. But there is no good way to fail gracefully,
or alert the user by rejecting the second rename in the UI either.

Doing this:

resources { "user":
purge => true,
unless_system_user => 2000
}

user { 'barney':


uid => 2003,
allowdupe => true,
}

user { 'fred':
uid => 2004,
allowdupe => true,
}

etc.

Is it a valid assumption that this would end with exactly the correct
users created in /etc/passwd? If so, then I guess it wouldn't be hard
to code:

exec { 'handleHomedirs':
# Prefer ruby in this crowd.. ;-)
command => '/opt/product/bin/handleHomedirs.rb',
require => [ User['barney'],..., Resources['user'] ]
}

Is adding "Resources['user']" to exec's require the way to ensure that
the exec gets executed after the purge of stale users?

I'm trying to get my feet wet with puppet with this feature, trying
find out what "the puppet way" is. Perhaps I didn't start with the
easiest of projects.... The handleHomedirs.rb strikes me as quite
non-puppet-esque... But perhaps this is an acceptable compromise :-)
We could just use puppet for so many things, and I decided to start
somewhere.

Thanks for your response, and sorry to burden you with so much detail....

Peter

jcbollinger

unread,
Feb 9, 2012, 12:07:23 PM2/9/12
to Puppet Users


On Feb 8, 11:02 am, Peter Valdemar Mørch <pmo...@gmail.com> wrote:
Ok. The most important thing I take from that, as it applies to your
questions, is that as far as Linux is concerned, "changing a user
name" typically means removing a user and creating a new one with the
same UID as the old but a different user name.
Your special case of swapping two or more user names in a cycle (as it
appears to your DB) manifests on the Linux side as swapping the
corresponding UIDs.

That all reflects a clash between your DB's model of the user world
and the Linux's: in database terms, it is the user name, not the UID,
that is the PK of the Linux user database. UIDs aren't even required
to be unique. It would be convenient if your DB's entity model better
matched the underlying Linux model, but I don't imagine it's feasible
to make that so. That shouldn't prevent you from using Puppet to
achieve your aim, but it will make it trickier.


> > If it would be sufficient to bound the purge range
> > only below, then you could do this:
>
> > resources { "user":
> >    purge => true,
> >    unless_system_user => 2000
> > }
>
> Cool! Yes, that is fine. We just want the possibility of creating real
> non-system and non-chroot users too.
>
>
>
> > Puppet probably can handle your complex renaming cases by transiently
> > leveraging the ability (available on many, but not all, client OSs)
> > for one UID to be assigned to multiple users:
> ...
> > So far, none of this touches on user home directories.  Puppet's User
> > resource does have the ability to manage home directories on most OSs
> > (unless you are relying on LDAP for your user DB), but it's not clear
> > to me what management, if any, you might want there.  This is where my
> > confusion over what you mean about renaming accounts comes most to
> > bear.
>
> The most important is the user "foo" has home dir "/home/foo" and
> correct uid. Ideal would be that if a user is renamed from a to b,
> that /home/a is renamed to /home/b.


I suspected you might say that.

Anyway, the bottom line is that you're not going to see that directory
renaming behavior without putting a fair amount of code into it
yourself, and I'm not immediately certain what that code would need to
be or where you would plug it in. You could get a similar effect,
however, by naming home directories by UID instead of by user name.
Puppet could even manage symlinks for you to allow users to reference
their homes by username:

user { 'alice':
uid => 2001,
allowdupe => true,
home => '/home/2001',
}

file { '/home/alice':
ensure => 'link',
target => '/home/2001',
}


> We can live with "sudo rm -r
> /home/a; sudo mkdir /home/b; chown b: /home/b; #setup /home/b" too
> (don't expect user renames to be frequent). Regardless of whether one
> does a "mv" or "rm && mkdir" the complex ( "fred->barney" +
> "barney->fred" ) rename will be a two-step process, I'm affraid. How
> likely is it? Not very. But there is no good way to fail gracefully,
> or alert the user by rejecting the second rename in the UI either.


In that case, is it ever ok to *not* remove the home directory in a
renaming situation? For example, if user "fred" is renamed to
"barney", is it really ok to just rename the home directory and keep
all its contents, even though it's also ok to create a fresh homedir?
If so, then why is there any problem in the cyclic renaming case?
Shouldn't it be ok if the home directory stays with the user name
instead of with the UID?


> Doing this:
>
> resources { "user":
>   purge => true,
>   unless_system_user => 2000
>
> }
>
> user { 'barney':
>   uid => 2003,
>   allowdupe => true,
>
> }
>
> user { 'fred':
>   uid => 2004,
>   allowdupe => true,
>
> }
>
> etc.
>
> Is it a valid assumption that this would end with exactly the correct
> users created in /etc/passwd?


It precisely describes the user configuration you want to achieve, and
the 'allowdupe' should enable it to work. Supposing that users 'fred'
and 'barney' are initially present with swapped UIDs, you should
transiently have a situation where the two have the same UID (might be
either one), and end with each having the correct UID.

What you're trying to do is unusual, however, so you should test. If
it doesn't work then that would constitute a Puppet bug.


> If so, then I guess it wouldn't be hard
> to code:
>
> exec { 'handleHomedirs':
>    # Prefer ruby in this crowd.. ;-)
>    command => '/opt/product/bin/handleHomedirs.rb',
>    require => [ User['barney'],..., Resources['user'] ]
>
> }
>
> Is adding "Resources['user']" to exec's require the way to ensure that
> the exec gets executed after the purge of stale users?


It should be, but that's beyond my personal experience.


> I'm trying to get my feet wet with puppet with this feature, trying
> find out what "the puppet way" is.


You seem to have a keen eye, and you're wise to set out to learn the
Puppet way. You're already far ahead of some Puppet newbies.


> Perhaps I didn't start with the
> easiest of projects.... The handleHomedirs.rb strikes me as quite
> non-puppet-esque... But perhaps this is an acceptable compromise :-)


I concur that you didn't start with the easiest of projects. User
management is not usually an especially hard task in itself, but
you're running up against core incompatibilities between Puppet's data
model and your existing DB's. Anyway, you probably need some kind of
homedir helper script in any event, because Puppet's built-in idea of
homedir management is to create homedirs as needed, but never to
delete homedirs.


> We could just use puppet for so many things, and I decided to start
> somewhere.


That's the only way to do it.


John

Peter Valdemar Mørch

unread,
Feb 12, 2012, 2:41:50 PM2/12/12
to puppet...@googlegroups.com
On Thu, Feb 9, 2012 at 6:07 PM, jcbollinger <John.Bo...@stjude.org> wrote:
> It precisely describes the user configuration you want to achieve, and
> the 'allowdupe' should enable it to work. Supposing that users 'fred'
> and 'barney' are initially present with swapped UIDs, you should
> transiently have a situation where the two have the same UID (might be
> either one), and end with each having the correct UID.
>
> What you're trying to do is unusual, however, so you should test. If
> it doesn't work then that would constitute a Puppet bug.

Sorry for my late reply. I've had the flue. I'm happy to report it
works exactly like you describe. Thanks for all your help and
guidance, John.

Peter

Reply all
Reply to author
Forward
0 new messages