Search code examples
linuxsshpuppet

Using puppet for centralized users and SSH key storage


I have a working puppet configuration with Master and two and agents. The scope of this config is to have a manifest which includes all users and user SSH keys in one place as per below;

user { 'puppet28':
    ensure => present,
    comment => 'puppet28',
    shell => '/bin/bash',
    home => '/home/puppet28',
    managehome => true,
    groups => ['agent99_group'],['agent_group'],
  }
  ssh_authorized_key { 'puppet28_ssh':
  user => 'puppet28',
  type => 'ssh-rsa',
  key => "AAAAB3NzaC1yc2EAAAADAQABAbKesokhkUNfMyvmvtLo32UKQlfQgt2sg8wltlveM6w=="
  }

My intention is to do a catalogue run from each agent and the user is created on each node. As the code is at the moment, agent99_group is a group on one node and agent_group is a group on another node.

Since both groups are not on the same node, I get an error when I do a puppet run the one of the groups is not present and the user creation run fails with the following error;

Error: Could not create user puppet28: Execution of '/usr/sbin/useradd -c puppet28 -G ageome/puppet28 -s /bin/bash -m puppet28' returned 6: useradd: group 'agent_group' does not Error: /Stage[main]/User/User[puppet28]/ensure: change from 'absent' to 'present' failed:t28: Execution of '/usr/sbin/useradd -c puppet28 -G agent99_group,agent_group -d /home/put28' returned 6: useradd: group 'agent_group' does not exist

Obviously this is expected, my question is if there is a way of having the user creation code inclusive of SSH key in one place and push it to multiple nodes.

It is important the user and SSH keys are ideally typed once as when this implementation goes to production it will consist of hundreds of users over approx 40-50 containers so it isnt scalable to copy and paste user details and SSH keys in a manifest for each node.

So far i've tried doing this with Hiera and also puppet forge modules but the results have always ended up in having to copy and paste something multiple times across different manifests.

Any help or other solutions?


Solution

  • The simplest example for this would be something like this.

    # This could be a module or a profile if using roles and profiles.
    class user_management {
       
      user { bob:
        ensure         => present,
        managehome     => true,
        purge_ssh_keys => true,
      }
    
      ssh_authorized_key { '[email protected]':
        ensure => present,
        user   => 'bob',
        type   => 'ssh-rsa',
        key    => lookup(user_management::bob),
      }
    }
    

    Then in the control-repo you want to be able to look up the values centraly so;

    # data/common.yaml
    ---
    user_management::bob: 'bobs-key'
    

    Any node you apply the user_management class to will get the bob user applied along with his key. A more scalable method would be to use an array of users;

    class user_management {
      $users = ['bob', 'bill']
       
      user { $users:
        ensure         => present,
        managehome     => true,
        purge_ssh_keys => true,
      }
    
      $users.each |$user| {
        ssh_authorized_key { "${user}@example.com":
          ensure => present,
          user   => $user,
          type   => 'ssh-rsa',
          key    => lookup("sshkey::${user}"),
        }
      }
    }
    

    And

    # data/common.yaml
    ---
    user_management::bob: 'bobs-key'
    user_management::bill: 'bills-key'