Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Home directories in our environment are hashed using the first two letters of a username. For example, the home directory for user lars is /home/l/a/lars.

I would like to use puppet to enforce mode 0700 permissions on the user home directories, but I'm not sure how to target the home directories. Essentially I would like to do this:

chmod 700 /home/*/*/*

In the absence of hashing this would be easy (using for example recurse and recurselimit), but the hashing has left me looking for a solution.

UPDATE: I am not looking to enumerate our users in puppet (because home directories are created as part of our account management process).

While thinking about this I've also become more muddled. Even if our home directories weren't hashed, how would I get puppet to apply permissions to the contents of a directory without affecting the top directory itself? I was thinking of something like this:

file { '/home:
  ensure => directory,
  mode => 0700,
  recurse => true,
  recurselimit => 1,
  }

But this would apply the mode to both /home and its immediate contents. Mode 700 on /home/lars is fine. Mode 700 on /home is a big problem. Is this even possible?

share|improve this question
2  
So, basically you want to enforce permissions with puppet on directories that puppet doesn't manage? Is there any way you could make the data available to puppet? Maybe use [External Nodes] (docs.puppetlabs.com/guides/external_nodes.html) to pass an array of all the usernames or a hash appropriate to pass to the create_resources function? Might have to cave in and write a simple shell script and call it with exec in puppet ... –  freiheit Sep 11 '11 at 6:58
    
I want Puppet to manage the permissions on directories that already exist, yes. That's a pretty common case, actually; you'll find that Puppet is often used to ensure file permissions and ownership on files that were not created by Puppet. –  larsks Sep 11 '11 at 10:59
    
Yes, managing permissions (or other things) on files/directories that don't come from puppet is very common (I do stuff like that all the time), but managing permissions on files/directories puppet doesn't specifically know about is a whole different thing. –  freiheit Sep 11 '11 at 18:51

3 Answers 3

up vote 2 down vote accepted

It seems you've faced one of limitations of puppet. I'd just write a shell script that would do it.

Another possible solution might be to write a plugin for puppet which would allow you to use new datatype (say, file_wildcard) or something like that. That should be possible to write one on ruby, but I've never done that.

share|improve this answer
    
I will probably end up doing this with a simple shell script. –  larsks Sep 11 '11 at 11:00

Puppet doesn't understand wildcards in file type. If you use something like this:

file { "/home/*":
            ensure  => directory,
            owner   => $username,
            group   => $username,
            mode    => 700,
            require => [ User[$username], Group[$username] ]
    }

it will create /home/\* folder.

So, you must create the directory structure which you want as belows:

define add_user ( $fullname, $uid ) {

    $username = $title
    $firstletter = regsubst($username, '(.).*', '\1')
    $secondletter = regsubst($username, '.(.).*', '\1')

    user { $username:
            comment => "$fullname",
            home    => "/home/$firstletter/$secondletter/$username",
            shell   => "/bin/bash",
            uid     => $uid,
            require => [ File["/home/$firstletter"], File["/home/$firstletter/$secondletter"] ]
    }

    group { $username:
            gid     => $uid,
            require => User[$username]
    }

    file { "/home/$firstletter":
            ensure  => directory,
            owner   => root,
            group   => root,
            mode    => 755
    }
    file { "/home/$firstletter/$secondletter":
            ensure  => directory,
            owner   => root,
            group   => root,
            mode    => 755,
            require => File["/home/$firstletter"]
    }
    file { "/home/$firstletter/$secondletter/$username":
            ensure  => directory,
            owner   => $username,
            group   => $username,
            mode    => 700,
            require => [ File["/home/$firstletter/$secondletter"], User[$username], Group[$username] ]
    }

    file { "/home/$firstletter/$secondletter/$username/.ssh":
            ensure  => directory,
            owner   => $username,
            group   => $username,
            mode    => 700,
            require => File["/home/$firstletter/$secondletter/$username"]
    }

    # now make sure that the ssh key authorized files is around
    file { "/home/$firstletter/$secondletter/$username/.ssh/authorized_keys":
            ensure  => present,
            owner   => $username,
            group   => $username,
            mode    => 600,
            require => File["/home/$firstletter/$secondletter/$username"]
    }
}

and call it with:

node 'test_node' {
    add_user { lars:
        fullname    => "Larry Page",
        uid         => 510
    }
}
share|improve this answer
    
The problem with this solution is that it presumes I want to enumerate all of our users in puppet, which is absolutely not the case. Account creation and user management is handled through other processes. What I could do, I guess, is create 26 * 26 entries for file { '/home/a/a': }, file { '/home/a/b'}, and so forth. It's not pretty; there must be some way to generate this without create 676 file entries. –  larsks Sep 11 '11 at 0:41
    
OK. Your original post is not clear. "Create 26 * 26 entries" is not a good idea even when you do it with a shell script. Can you leave user creation process to Puppet handle? –  quanta Sep 11 '11 at 5:27
    
You can create 26*26 entries by calling defined resource types with an array. Something like: define hashhome2 ($secondletter) { file { "/home/${title}/${secondletter}": ensure => directory,require => File["/home/${title}"]} } define hashhome () { file { "/home/${title}": ensure => directory } hashhome2 { ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t'‌​,'u','v','w','x','y','z']: secondletter => $title}} hashhome {['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t‌​','u','v','w','x','y','z']:} –  freiheit Sep 11 '11 at 6:49

You need to either declare the File resource(s) you want Puppet to manage (Puppet is a declarative language...) to puppet or your looking at using the exec type to execute the chmod code snippet you gave.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.