Both the Puppet master and agent nodes configured above are functional, but not secure. Based on concepts from the Securing Your Server guide, a limited user and a firewall should be configured. This can be done on all nodes through the creation of basic Puppet modules, shown below.
- From the Puppet master, navigate to the /etc/puppet/modules directory and create your new module for adding user accounts, then cd into that directory:
1
2 | mkdir /etc/puppet/modules/accounts
cd /etc/puppet/modules/accounts
|
- Create the following directories, which are needed to have a functioning module:
1
| mkdir {examples,files,manifests,templates}
|
The examples directory allows you to test the module locally. files contains any static files that may need to be edited or added. manifests contains the actual Puppet code for the module, and templates contains any non-static files that may be needed.
- Move to the manifests directory and create your first class, called init.pp. All modules require an init.pp file to be used as the main definition file of a module.
1
| mkdir {examples,files,manifests,templates}
|
- Within the init.pp file, define a limited user to use instead of root, replacing all instances of username with your chosen username:
File: /etc/puppet/modules/accounts/manifests/init.pp
1
2
3
4
5
6
7
8
9
10
11 | class accounts {
user { 'username':
ensure => present,
home => '/home/username',
shell => '/bin/bash',
managehome => true,
gid => 'username',
}
}
|
The init.pp file initially defines the accounts class. It then calls for the user resource, where a username is defined. The ensure value is set to ensure that the user exists (is present). The home value should be set to the user’s home directory path. shell defines the shell type, in this instance the bash shell. managehome notes that the home directory should be created. Finally, gid sets the primary group for the user.
- Although the primary group is set to share the username, the group itself has not been created. Save and exit init.pp. Then, create a new file called groups.pp and add the following contents. This file will be used to create the user’s group. Again, replace username with your chosen username:
File: /etc/puppet/modules/accounts/manifests/groups.pp
1
2
3
4
5
6
7 | class accounts::groups {
group { 'username':
ensure => present,
}
}
|
Include this file by adding include groups to the init.pp file, within the accounts class:
File excerpt: /etc/puppet/modules/accounts/manifests/init.pp
1
2
3
4
5 | class accounts {
include groups
...
}
|
- This user should have privileges so that administrative tasks can be performed. Because we have agent nodes on both Debian- and Red Hat-based systems, the new user needs to be in the sudo group on Debian systems, and the wheel group on Red Hat systems. This value can be set dynamically through the use of a selector and facter, a program included in Puppet that keeps track of information, or facts, about every server. Add a selector statement to the top of the init.pp file within the accounts class brackets, defining the two options:
File excerpt: /etc/puppet/modules/accounts/manifests/init.pp
1
2
3
4
5
6
7
8
9
10
11
12 | class accounts {
$rootgroup = $osfamily ? {
'Debian' => 'sudo',
'RedHat' => 'wheel',
default => warning('This distribution is not supported by the Accounts module'),
}
user { 'username':
...
}
|
This command sequence tells Puppet that within the accounts module the variable $rootgroup should evaluate, using facter, the operating system family ($osfamily), and if the value returned is Debian, to set the $rootgroup value to sudo. If the value returned is RedHat, this same value should be set to wheel; otherwise, the default value will output a warning that the distribution selected is not supported by this module.
Note
The user definition will include the $rootgroup, and the Puppet Configuration Language executes code from top to bottom. You must define the $rootgroup before the user so that it can be accessed.
- Add the groups value to the user resource, calling to the $rootgroup variable defined in the previous step:
File excerpt: /etc/puppet/modules/accounts/manifests/init.pp
1
2
3
4
5
6
7
8 | user { 'username':
ensure => present,
home => '/home/username',
shell => '/bin/bash',
managehome => true,
gid => 'username',
groups => "$rootgroup",
}
|
The value "$rootgroup" is enclosed in double quotes (") instead of single quotes (') because it is a variable. Any value enclosed within single quotes will be added as typed in your module; anything enclosed in double quotes can accept variables.
- The final value that needs to be added is the password. Since we do not want to use plain text, it should be fed to Puppet as a SHA1 digest, which is supported by default. Set a password from the terminal:
You will be prompted to enter your password and confirm. A hashed password will be output. This should then be copied and added to the user resource:
File:/etc/puppet/modules/accounts/manifests/init.pp
1
2
3
4
5
6
7
8
9
10
11
12
13 | class accounts {
user { 'username':
ensure => present,
home => '/home/username',
shell => '/bin/bash',
managehome => true,
gid => 'username',
groups => "$rootgroup",
password => '$1$07JUIM1HJKDSWm8.NJOqsP.blweQ..3L0',
}
}
|
Caution
The hashed password must be included in single quotes (').
- After saving your changes, use the puppet parser to ensure that the code is correct:
1
| puppet parser validate init.pp
|
Any errors that need to be addressed will be logged to standard output. If nothing is returned, your code is valid.
- Before the module can be tested further, navigate to theexamples directory and create another init.pp file, this time to call to the accounts module:
File: /etc/puppet/modules/accounts/examples/init.pp
After adding this line, save and exit the file.
- While still in the examples directory, test the module without making changes:
1
| puppet apply --noop init.pp
|
Note
The --noop parameter prevents Puppet from actually running the module.
It should return:
1
2
3
4
5
6
7 | Notice: Compiled catalog for puppet.example.com in environment production in 0.26 seconds
Notice: /Stage[main]/Accounts::Groups/Group[username]/ensure: current_value absent, should be present (noop)
Notice: Class[Accounts::Groups]: Would have triggered 'refresh' from 1 events
Notice: /Stage[main]/Accounts/User[username]/ensure: current_value absent, should be present (noop)
Notice: Class[Accounts]: Would have triggered 'refresh' from 1 events
Notice: Stage[main]: Would have triggered 'refresh' from 2 events
Notice: Finished catalog run in 0.02 seconds
|
- Again from the examples directory, run puppet apply to make these changes to the Puppet master server:
- Log out as root and log in to the Puppet master as your new user. The rest of this guide will be run by this user.