Puppet and fail2ban & Email Login Notifications
I wrote a series of articles about how unsafe it is to leaving an openly accessible server.
Let’s create a manifest for the fail2ban and email login notifications I talk about and to combine them with the two factor authentication manifest from my last article.
From the last article…
Just for reference, the Vagrantfile used for every manifest in this article and the modules:
Vagrantfile
Vagrant.configure("2") do |config|
config.vm.box = 'ubuntu/trusty64'
# resolves error: ==> default: Warning: Could not retrieve fact fqdn
config.vm.hostname = "vagrant.example.com"
# http://www.terrarum.net/blog/masterless-puppet-with-vagrant.html
config.vm.provision 'shell', :inline => <<-SHELL
apt-get purge -y puppet # remove puppet3
wget https://apt.puppetlabs.com/puppet5-release-trusty.deb
dpkg -i ./puppet5-release-trusty.deb
apt-get update
apt-get install -y puppet-agent # install puppet5
SHELL
# https://github.com/mitchellh/vagrant/issues/3740#issuecomment-92106636
config.vm.provision 'puppet' do |puppet|
puppet.environment_path = 'environments'
puppet.environment = 'production'
puppet.module_path = 'modules'
end
end
After running vagrant up
, using vagrant provision
is enough to apply the new
puppet manifests.
Modules
Install modules in the modules folder of the vagrant directory. The most used module in the manifests will be the stdlib module:
$ puppet module install stdlib
$ cp -r ~/.puppet/modules /vagrant/ # puppet 3
$ cp -r /opt/puppetlabs/puppet/modules /vagrant # puppet 5
fail2ban Manifest
The fail2ban manifest can be trivial, let’s create manifests for:
- just fail2ban
- extending the bantime
- fail2ban email notifications
Just fail2ban
This manifest is easy as the instructions for getting fail2ban installed is:
$ sudo apt-get install fail2ban
The manifest can be just:
environment/productions/manifests/fail2ban.pp:
package { 'fail2ban':
ensure => 'installed',
status => 'running'
}
Extending bantime
To configure the bantime from default of 5 minutes (300 seconds) to 1 hour (86400 seconds), by adding a configuration in the jail.conf file using the file resource:
The /etc/fail2ban/jail.local content desired is:
bantime = 86400
The manifest grows with the file resource and now looks like:
environment/productions/manifests/fail2ban.pp:
package { 'fail2ban':
ensure => 'installed',
status => 'start'
}
file { 'jail.local':
ensure => 'present',
path => '/etc/fail2ban/jail.local',
content => "bantime = 86400"
}
The manifest creates the content of the jail.local file inline with the
content
option. The path
option specifies exactly where and the
filename. Creating files this way reduces additional dependencies.
fail2ban Email Notifications
Let’s increase security by having fail2ban send an email when an attacker attempts too login more than six times in five minutes. To send emails, install the sendmail package and add an additional jail.local configuration:
Including sendmail package in the manifest:
package { 'sendmail':
ensure => 'installed'
}
The jail.local configuration needed:
destemail = [email protected]
action = %(action_mw)s
The fail2ban manifest for this would be:
environment/productions/manifests/fail2ban.pp:
package { 'fail2ban':
ensure => 'installed',
status => 'start'
}
package { 'sendmail':
ensure => 'installed'
}
file { 'jail.local':
ensure => 'present',
path => '/etc/fail2ban/jail.local',
content => "destemail = [email protected]\naction = %(action_mw)s"
}
note: Use "
for the content line so \n
produces a new
line/return instead of writing \n
in the jail.local file.
Combined fail2ban Manifest
Combining everything into one fail2ban manifest:
environment/productions/manifests/fail2ban.pp:
package { 'fail2ban':
ensure => 'installed',
status => 'start'
}
package { 'sendmail':
ensure => 'installed'
}
file { 'jail.local':
ensure => 'present',
path => '/etc/fail2ban/jail.local',
content => "bantime = 86400\ndestemail = [email protected]\naction = %(action_mw)s"
}
fail2ban Puppet Module
By using a jail.local it updates those fail2ban configurations instead all fail2ban configurations, which are in jail.conf.
If one wants to configure more options, using the fail2ban puppet module would be a better method to manage and configure this.
Email Login Notifications Manifest
The next step is to send emails when a login occurs, steps required:
- install mailutils
- configure pam.d to run a script on successful login
- create a shell script for execution by pam.d
Install mailutils
The manifest will be:
package { 'mailutils':
ensure => 'installed'
}
Configure pam.d
Now this is a bit trickier to have pam.d add a line, but using the file_line
method:
file_line { 'pamd_config':
path => '/etc/pam.d/sshd',
line => 'session optional pam_exec.so /usr/local/bin/send_email.sh'
}
The path
option looks for a specific file and ensures the line
is in the
file. Provisioning the system multiple times will insert the line once.
Create Email Shell Script
The script to send an email is a bit more complicated as it has quotes and shell
variables, "
& $
, inside it. Puppet also accepts variables using $
, so
escape them using \
.
The manifest file:
file { 'send_email.sh':
ensure => 'file',
path => '/usr/local/bin/send_email.sh',
mode => 'ugo+x',
content => "#!/bin/sh
if [ \"\$PAM_TYPE\" = \"open_session\" ]
then
{
echo \"User: \$PAM_USER\"
echo \"Remote Host: \$PAM_RHOST\"
echo \"Service: \$PAM_SERVICE\"
echo \"TTY: \$PAM_TTY\"
echo \"Date: `date`\"
echo \"Server: `uname -a`\"
} | mail -s \"\$PAM_SERVICE login on `hostname -s` for account \$PAM_USER\" <[email protected]>
fi
exit 0
"
}
The mode
option configures the file to be executable by the pam.d module
(otherwise, pam.d will raise an error.)
Complete Manifest
environment/productions/manifests/email_login_notifications.pp:
package { 'mailutils':
ensure => 'installed'
}
file_line { 'pamd_config':
path => '/etc/pam.d/sshd',
line => 'session optional pam_exec.so /usr/local/bin/send_email.sh'
}
file { 'send_email.sh':
ensure => 'file',
path => '/usr/local/bin/send_email.sh',
mode => 'ugo+x',
content => "#!/bin/sh
if [ \"\$PAM_TYPE\" = \"open_session\" ]
then
{
echo \"User: \$PAM_USER\"
echo \"Remote Host: \$PAM_RHOST\"
echo \"Service: \$PAM_SERVICE\"
echo \"TTY: \$PAM_TTY\"
echo \"Date: `date`\"
echo \"Server: `uname -a`\"
} | mail -s \"\$PAM_SERVICE login on `hostname -s` for account \$PAM_USER\" <[email protected]>
fi
exit 0
"
}
Conclusion
By building up two manifests: fail2ban and email login notifications I learned
how to use puppet’s file
resource utilizing mode and content options. These
manifests have come a long way from the ones I built
earlier and these
are easier to read!