Puppet: User Management and /home over NFS

I was looking for a way to automate user configuration management on 20 Linux machines that I have been administering for several months now. In my setup I want to see following:

  • add a user once, have him/her on as many machines as you define
  • share users’ home directories over the network

There are many ways to have it done. I wanted to see how this can be achieved with Puppet for several reasons, mainly, because I want to have as much config management under the same hood as possible. And I am just starting with Puppet, so comments are welcome.

To implement the user management setup I need three modules:

  • users – will define users, their passwords, ssh-keys (optional), default shells etc
  • nfs_server – will share /home directory over NFS
  • nfs_client – will mount the shared /home directory as /home

In this demo I have three machines, all running Debian Squeeze:

  • puppet.mydomain.com – is the puppet master
  • node1.mydomain.com – NFS server, will share /home over the network
  • node2.mydomain.com – NFS client, will mount /home from node1

User management module
This module will create virtual users, which will then be realized in nodes.pp (they can be realized in any puppet class)

class users {
        include users::virtual
}

class users::virtual {
        define localuser ($uid,$gid,$pass,$sshkey="") {

                user { $title:
                        ensure  =>      "present",
                        uid     =>      $uid,
                        gid     =>      $gid,
                        shell   =>      "/bin/bash",
                        home    =>      "/home/$title",
                        comment =>      $realname,
                        password =>     $pass,
                        managehome =>   true,
                }

                if ( $sshkey != "" ) {
                 ssh_authorized_key { $title:
                         ensure  =>      "present",
                         type    =>      "ssh-rsa",
                         key     =>      "$sshkey",
                         user    =>      "$title",
                         require =>      User["$title"],
                         name    =>      "$title",
                 }
                }
        }
}

class mysite::users {
include users::virtual

        @users::virtual::localuser { "armen":
                uid     =>      "1001",
                gid     =>      "users",
                pass    =>      '$6$k02Z/D7h$p4IQnbu893UgmvYCbIh9zcS5qxeuDBi4BIbwzauudKierjoZD5mWE98l13BfZ5o1OU7TrInJqbLTg/ag7dm6T/',
                sshkey  =>      "AAAAB3NzaC1yc2EAAAABIwAAAQEAtbsafzNX08oT63vnKh6LNYVpFM9U42knt+tUMvhTQaOEGVnsRH6zVQj86PLYo9HD7MCVqYAloKRN6hVvoqU++CSLO0zUYsQ4bX/+DQthtKcOwU76QLFTcXVRIIGMH++GLHGjphEhjPAJc/rPM0YswCetOm3JVGVB9x/WJFOmoT+a7r4IXaULaNTYZOPZ6fr/CvUB/w3NBvPnmLMxwPFOgBLxcQ9Tbpa5sjwi1thlXl1ZfQ8Sh++gg60odTHbAhwZOU70mA8WGOmkuETDQzunQvTK14fGDvFSHJNE5nYse8IPChbfrSMJl1PsWB+SiiGrPVQtly9BEOYi/aOokj3vfQ==",
        }

        @users::virtual::localuser { "brmen":
                uid     =>      "1002",
                gid     =>      "users",
                pass    =>      '$6$k02Z/D7h$p4IQnbu893UgmvYCbIh9zcS5qxeuDBi4BIbwzauudKierjoZD5mWE98l13BfZ5o1OU7TrInJqbLTg/ag7dm6T/',
                sshkey  =>      "AAAAB3NzaC1yc2EAAAABIwAAAQEAtbsafzNX08oT63vnKh6LNYVpFM9U42knt+tUMvhTQaOEGVnsRH6zVQj86PLYo9HD7MCVqYAloKRN6hVvoqU++CSLO0zUYsQ4bX/+DQthtKcOwU76QLFTcXVRIIGMH++GLHGjphEhjPAJc/rPM0YswCetOm3JVGVB9x/WJFOmoT+a7r4IXaULaNTYZOPZ6fr/CvUB/w3NBvPnmLMxwPFOgBLxcQ9Tbpa5sjwi1thlXl1ZfQ8Sh++gg60odTHbAhwZOU70mA8WGOmkuETDQzunQvTK14fGDvFSHJNE5nYse8IPChbfrSMJl1PsWB+SiiGrPVQtly9BEOYi/aOokj3vfQ==",
        }
}

Realizing users is described in my nodes.pp at the end of this post.

Share /home over NFS

class nfs_server {

        package { "nfs-kernel-server":
                ensure => installed,
        }

        service { [ "nfs-kernel-server"]:
                ensure => running,
                enable => true,
                require => Package["nfs-kernel-server"],
        }
}

define share_dirs($share_root) {
        file { "${share_root}":
               ensure => directory,
#                owner => "root",
#                group => "root",
#                mode => 755,
        }
}

define share_mounts($share_root, $volgroup) {
        mount { "${share_root}/$name":
                ensure => mounted,
                device => "${volgroup}/$name",
                atboot => true,
                fstype => "ext3",
                options => "defaults,nosuid",
                require => File["${share_root}/$name"],
        }
}

define nfs_share ($shares, $volgroup, $share_access = "*.$domain", $share_options = "rw,sync") {
        include nfs_server

        share_dirs { $shares: share_root => $name }                             # $shares is an array
#        share_mounts { $shares: share_root => $name, volgroup => $volgroup }    # $shares is an array

        file { "/etc/exports":
                owner => "root",
                group => "root",
                mode => 644,
                content => template("/etc/puppet/modules/nfs_server/templates/etc-exports.tpl"),
                notify => Service["nfs-kernel-server"],
        }
}

The content of the mentioned /etc/puppet/modules/nfs_server/templates/etc-exports.tpl goes like this:

<% shares.each do |share| %><%= share %>    <%= share_access %>(<%= share_options %>)
<% end %>

Mount /home over NFS
And, finally, all NFS clients are mounting the /home over the network with the following module:

class nfs_client {
    mount { "/home":
        device  => "node1:/home",
        fstype  => "nfs",
        ensure  => "mounted",
#        options => "tcp,intr,hard,rw,bg,rsize=32768,wsize=32768",
        atboot  => "true",
    }
}

Taking the modules into use
And implementing the modules in my nodes.pp:

class base {
        include users, mysite::users
        realize (
        Users::Virtual::Localuser["armen", "brmen"]
        )
}

node 'node1.mydomain.com' {
        include base, nfs_server
        nfs_share { "/home":
                shares => [ "/home"],
                volgroup => "/dev/VolGroup00",
        }
}

node 'node2.mydomain.com' {
        include base, nfs_client
}

One response to “Puppet: User Management and /home over NFS

  1. Darrel Jn May 13, 2016 at 1:53 am

    Hello. excellent job. I did not imagine this. This is a excellent story. Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: