diff --git a/manifests/action.pp b/manifests/action.pp new file mode 100644 index 0000000..2469f92 --- /dev/null +++ b/manifests/action.pp @@ -0,0 +1,151 @@ +# Define: fail2ban::action +# +# Adds a custom fail2ban action +# Documentation: Manpages & http://www.fail2ban.org/wiki/index.php/MANUAL_0_8 +# +# Supported arguments: +# $actionname - The name you want to give the action. +# If not set, defaults to == default +# action local file is named after this value, like +# $name.local. The suffix "local" is automatically added. +# +# $enable - true / false. If false, the rule _IS NOT ADDED_ to the +# action.local file +# Defaults to true +# +# $source - Sets the content of source parameter for the new action +# It's mutually exclusive with $template. +# +# $template - Template to use when defining a new action +# It's mutually exclusive with $source. +# +# $start - command(s) executed when the jail starts. +# Can be an array +# Used only with $template +# +# $stop - command(s) executed when the jail stops. +# Can be an array +# Used only with $template +# +# $check - the command ran before any other action. +# It aims to verify if the environment is still ok. +# Used only with $template +# +# $ban - command(s) that bans the IP address after maxretry +# log lines matches within last findtime seconds. +# Used only with $template +# +# $unban - command(s) that unbans the IP address after bantime. +# Used only with $template +# +# $actionbefore - indicates an action file that is read before the +# [Definition] section. +# +# $actionafter - indicates an action file is read after the +# [Definition] section. +# +# $initvars - Variables for the INIT stanza of the action file. +# They are tuples in the format +# "var = value" +# Can be an array like +# [ "var1 = value1", "var2 = value2",.., "varN = valueN" ] +# +define fail2ban::action ( + $actionname = '', + $actionsource = '', + $actiontemplate = 'fail2ban/action.local.erb', + $actionstart = '', + $actionstop = '', + $actioncheck = '', + $actionban = '', + $actionunban = '', + $actionbefore = '', + $actionafter = '', + $actioninitvars = '', + $enable = true ) { + + include fail2ban + + $real_actionname = $actionname ? { + '' => $title, + default => $actionname, + } + + $action_file = "${fail2ban::data_dir}/action.d/${real_actionname}.local" + + $array_start = is_array($actionstart) ? { + false => $actionstart ? { + '' => ['/bin/true'], + default => [$actionstart], + }, + default => $actionstart, + } + + $array_stop = is_array($actionstop) ? { + false => $actionstop? { + '' => ['/bin/true'], + default => [$actionstop], + }, + default => $actionstop, + } + + $array_check = is_array($actioncheck) ? { + false => $actioncheck? { + '' => ['/bin/true'], + default => [$actioncheck], + }, + default => $actioncheck, + } + + $array_ban = is_array($actionban) ? { + false => $actionban? { + '' => ['/bin/true'], + default => [$actionban], + }, + default => $actionban, + } + + $array_unban = is_array($actionunban) ? { + false => $actionunban? { + '' => ['/bin/true'], + default => [$actionunban], + }, + default => $actionunban, + } + + $array_initvars = is_array($actioninitvars) ? { + false => $actioninitvars? { + '' => [], + default => [$actioninitvars], + }, + default => $actioninitvars, + } + + $ensure = bool2ensure($enable) + + $manage_file_source = $actionsource ? { + '' => undef, + default => $actionsource, + } + + $manage_file_content = $actiontemplate ? { + '' => undef, + default => template($actiontemplate), + } + + file { "${real_actionname}.local": + ensure => $fail2ban::manage_file, + path => $action_file, + mode => $fail2ban::config_file_mode, + owner => $fail2ban::config_file_owner, + group => $fail2ban::config_file_group, + require => Package[$fail2ban::package], + notify => $fail2ban::manage_service_autorestart, + source => $manage_file_source, + content => $manage_file_content, + replace => $fail2ban::manage_file_replace, + audit => $fail2ban::manage_audit, + noop => $fail2ban::bool_noops, + } + +} diff --git a/spec/defines/fail2ban_action_spec.rb b/spec/defines/fail2ban_action_spec.rb new file mode 100644 index 0000000..ec35ea1 --- /dev/null +++ b/spec/defines/fail2ban_action_spec.rb @@ -0,0 +1,91 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb') + +describe 'fail2ban::action' do + + let(:title) { 'fail2ban::action' } + let(:node) { 'rspec.example42.com' } + let(:facts) do + { + :ipaddress => '10.42.42.42', + } + end + + describe 'Test action define is called with no options' do + let(:params) do + { + :actionname => 'sample1', + } + end + let(:expected) do +"# This file is managed by Puppet. DO NOT EDIT. +# +[INCLUDES] + + +[Definition] + +actionstart = /bin/true +actionstop = /bin/true +actioncheck = /bin/true +actionban = /bin/true +actionunban = /bin/true + +[Init] +" + end + + it { should contain_file('sample1.local').with_path('/etc/fail2ban/action.d/sample1.local').with_content(expected) } + end + + describe 'Test action.local is created with all options' do + let(:params) do + { + :actionname => 'sample2', + :actionstart => 'start_action', + :actionstop => 'stop_action', + :actioncheck => 'check_action', + :actionban => ['first_ban_action','second_ban_action','complex[ban]'], + :actionunban => 'now_unban', + :actionbefore => 'add_before', + :actioninitvars => ['a = 1','b = 2', 'not c'], + } + end + let(:expected) do +"# This file is managed by Puppet. DO NOT EDIT. +# +[INCLUDES] + +before = add_before +[Definition] + +actionstart = start_action +actionstop = stop_action +actioncheck = check_action +actionban = first_ban_action +\tsecond_ban_action +\tcomplex[ban] +actionunban = now_unban + +[Init] +a = 1 +b = 2 +not c +" + end + + it { should contain_file('sample2.local').with_path('/etc/fail2ban/action.d/sample2.local').with_content(expected) } + it { should contain_file('sample2.local').without_source } + end + + describe 'Test action define is called with a source file' do + let(:params) do + { + :actionname => 'sample3', + :actionsource => 'puppet:///some/path/to/source', + } + end + + it { should contain_file('sample3.local').with_path('/etc/fail2ban/action.d/sample3.local').with_source('puppet:///some/path/to/source') } + it { should contain_file('sample3.local').without_template } + end +end diff --git a/templates/action.local.erb b/templates/action.local.erb new file mode 100644 index 0000000..ac5c6ae --- /dev/null +++ b/templates/action.local.erb @@ -0,0 +1,33 @@ +# This file is managed by Puppet. DO NOT EDIT. +# +[INCLUDES] + +<% if @actionbefore != '' -%> +before = <%= @actionbefore -%> +<% end -%> +<% if @actionafter != '' -%> +after = <%= @actionafter -%> +<% end -%> + +[Definition] + +<% if @array_start != [] -%> +actionstart = <%= @array_start.join("\n\t") %> +<% end -%> +<% if @array_stop != [] -%> +actionstop = <%= @array_stop.join("\n\t") %> +<% end -%> +<% if @array_check != [] -%> +actioncheck = <%= @array_check.join("\n\t") %> +<% end -%> +<% if @array_ban != [] -%> +actionban = <%= @array_ban.join("\n\t") %> +<% end -%> +<% if @array_unban != [] -%> +actionunban = <%= @array_unban.join("\n\t") %> +<% end -%> + +[Init] +<% if @array_initvars != [] -%> +<%= @array_initvars.join("\n") %> +<% end -%>