From ca994084482fb7e9ef267d663d4817eab394abb6 Mon Sep 17 00:00:00 2001 From: Nathan Ward Date: Mon, 2 Nov 2020 12:05:12 +1300 Subject: [PATCH 1/4] Add functionality to configure and run radsniff. This works on redhat family systems only. Add camptocamp/systemd to manage systemd unit file. --- README.md | 16 +++++++++++++++ files/radsniff.service | 13 ++++++++++++ manifests/radsniff.pp | 35 +++++++++++++++++++++++++++++++ metadata.json | 4 ++++ spec/classes/radsniff.rb | 43 +++++++++++++++++++++++++++++++++++++++ spec/spec_helper_local.rb | 12 +++++++++++ 6 files changed, 123 insertions(+) create mode 100644 files/radsniff.service create mode 100644 manifests/radsniff.pp create mode 100644 spec/classes/radsniff.rb diff --git a/README.md b/README.md index 79fb6287..073db6d9 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,22 @@ Whether the control socket should be read-only or read-write. Choose from `ro`, } ``` +#### `freeradius::radsniff` + +The `freeradius::radsniff` class configures and runs the [RADSNIFF](https://freeradius.org/radiusd/man/radsniff.html) service. +It requires freeradius-utils to be installed, so will fail if `utils_support` is not enabled on the `freeradius` class. + +Note: This is only supported on RedHat like systems at present. + +##### `options` +Command line options to be passed to radsniff. Quotes are escaped +```puppet + # Enable radsniff, with a filter, sending data to collectd (requires freeradius to be compiled for this) + class { 'freeradius::radsniff': + options => '-m -p1812,1813 -O unix:/var/run/collectd.sock -N freeradius -W 10 -i eth0 -f "src not 192.0.2.1"', + } +``` + ### Resources #### `freeradius::attr` diff --git a/files/radsniff.service b/files/radsniff.service new file mode 100644 index 00000000..c60f0db8 --- /dev/null +++ b/files/radsniff.service @@ -0,0 +1,13 @@ +[Unit] +Description=Capture RADIUS statistics +After=syslog.target network.target +After=radiusd.target + +[Service] +Type=forking +PIDFile=/var/run/radiusd/radsniff.pid +EnvironmentFile=/etc/sysconfig/radsniff +ExecStart=/usr/bin/radsniff -P /var/run/radiusd/radsniff.pid -d /etc/raddb $RADSNIFF_OPTIONS + +[Install] +WantedBy=multi-user.target diff --git a/manifests/radsniff.pp b/manifests/radsniff.pp new file mode 100644 index 00000000..8f5ee29d --- /dev/null +++ b/manifests/radsniff.pp @@ -0,0 +1,35 @@ +# @summary configure and run radsniff +# +# @param options commandline options passed to radsniff when it runs +class freeradius::radsniff ( + String $options = '', +) { + unless $::freeradius::utils_support { + fail('freeradius::radsniff requires freeradius have utils_support enabled') + } + + unless $facts['os']['family'] == 'RedHat' { + fail('freeradius::radsniff only supports RedHat like OSes at the moment') + } + + $escaped_cmd = $options.regsubst('"','\\\\"','G') + + file {'/etc/sysconfig/radsniff': + content => @("SYSCONFIG"), + RADSNIFF_OPTIONS="${escaped_cmd}" + | SYSCONFIG + owner => 'root', + group => 'root', + mode => '0644', + require => Package['freeradius-utils'], + } + ~> service { 'radsniff': + ensure => running, + enable => true, + } + + systemd::unit_file {'radsniff.service': + source => 'puppet:///modules/freeradius/radsniff.service', + notify => Service['radsniff'], + } +} diff --git a/metadata.json b/metadata.json index 6e39d8e3..fb050441 100644 --- a/metadata.json +++ b/metadata.json @@ -27,6 +27,10 @@ { "name": "puppetlabs/concat", "version_requirement": ">=1.0.0 <7.0.0" + }, + { + "name": "camptocamp/systemd", + "version_requirement": ">=2.0.0 <3.0.0" } ], "operatingsystem_support": [ diff --git a/spec/classes/radsniff.rb b/spec/classes/radsniff.rb new file mode 100644 index 00000000..d4666503 --- /dev/null +++ b/spec/classes/radsniff.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe 'freeradius::radsniff' do + on_supported_os.each do |os, os_facts| + context "on #{os}" do + include_context 'freeradius_with_utils' + + let(:facts) { os_facts } + + let(:params) do + { + options: 'radsniff cmd "line" options', + } + end + + case os_facts[:osfamily] + when 'RedHat' + it do + is_expected.to contain_file('/etc/sysconfig/radsniff') + .with_content(%r{RADSNIFF_OPTIONS="radsniff cmd \\"line\\" options"}) + .that_notifies('Service[radsniff]') + .that_requires('Package[freeradius-utils]') + end + + it do + is_expected.to contain_service('radsniff') + .with_ensure('running') + .with_enable(true) + end + + it do + is_expected.to contain_systemd__unit_file('radsniff.service') + .with_source('puppet:///modules/freeradius/radsniff.service') + .that_notifies('Service[radsniff]') + end + else + it do + is_expected.to compile.and_raise_error(%r{radsniff only supports RedHat}) + end + end + end + end +end diff --git a/spec/spec_helper_local.rb b/spec/spec_helper_local.rb index bac495b4..1377bcfa 100644 --- a/spec/spec_helper_local.rb +++ b/spec/spec_helper_local.rb @@ -53,6 +53,18 @@ end end +# Same as above but enable utils +shared_context 'freeradius_with_utils' do + let(:pre_condition) do + [ + redhat_params_class, + 'class { freeradius: + utils_support => true, + }', + ] + end +end + # Some common dependencies for things based on names for redhat systems shared_context 'redhat_common_dependencies' do let(:pre_condition) do From b2714c80f6c312ef8e0e67095daa487cb096fce2 Mon Sep 17 00:00:00 2001 From: Nathan Ward Date: Thu, 12 Nov 2020 16:44:00 +1300 Subject: [PATCH 2/4] Allow anyone to read the dictionary --- manifests/init.pp | 2 +- spec/classes/freeradius_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/init.pp b/manifests/init.pp index 3a9f41c9..0fe113da 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -240,7 +240,7 @@ concat { "${freeradius::fr_basepath}/dictionary": owner => 'root', group => $freeradius::fr_group, - mode => '0640', + mode => '0644', require => [Package[$freeradius::fr_package], Group[$freeradius::fr_group]], } concat::fragment { 'dictionary_header': diff --git a/spec/classes/freeradius_spec.rb b/spec/classes/freeradius_spec.rb index 138bdfb5..e97136e3 100644 --- a/spec/classes/freeradius_spec.rb +++ b/spec/classes/freeradius_spec.rb @@ -151,7 +151,7 @@ is_expected.to contain_concat('/etc/raddb/dictionary') .with( 'group' => 'radiusd', - 'mode' => '0640', + 'mode' => '0644', 'owner' => 'root', ) .that_requires('Package[freeradius]') From 12dab8c2012c5896f8f22f51250bb05f440434b2 Mon Sep 17 00:00:00 2001 From: Nathan Ward Date: Fri, 14 May 2021 21:59:35 +1200 Subject: [PATCH 3/4] Add radsniff support for Debian-like OSes and specifying envfile and pidfile to support any OS --- files/radsniff.service | 13 ------- manifests/params.pp | 10 ++++++ manifests/radsniff.pp | 30 +++++++++++++--- spec/classes/radsniff.rb | 62 +++++++++++++++++++++++++++++++--- templates/radsniff.service.erb | 13 +++++++ 5 files changed, 106 insertions(+), 22 deletions(-) delete mode 100644 files/radsniff.service create mode 100644 templates/radsniff.service.erb diff --git a/files/radsniff.service b/files/radsniff.service deleted file mode 100644 index c60f0db8..00000000 --- a/files/radsniff.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Capture RADIUS statistics -After=syslog.target network.target -After=radiusd.target - -[Service] -Type=forking -PIDFile=/var/run/radiusd/radsniff.pid -EnvironmentFile=/etc/sysconfig/radsniff -ExecStart=/usr/bin/radsniff -P /var/run/radiusd/radsniff.pid -d /etc/raddb $RADSNIFF_OPTIONS - -[Install] -WantedBy=multi-user.target diff --git a/manifests/params.pp b/manifests/params.pp index 46e47b80..b3f6912d 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -172,4 +172,14 @@ } $radacctdir = "\${logdir}/radacct" + + # Default radsniff environment file location + $fr_radsniff_envfile = $::osfamily ? { + 'RedHat' => '/etc/sysconfig/radsniff', + 'Debian' => '/etc/defaults/radsniff', + default => undef, + } + + # Default radsniff pid file location + $fr_radsniff_pidfile = "/var/run/${fr_service}/radsniff.pid" } diff --git a/manifests/radsniff.pp b/manifests/radsniff.pp index 8f5ee29d..21837064 100644 --- a/manifests/radsniff.pp +++ b/manifests/radsniff.pp @@ -1,20 +1,42 @@ # @summary configure and run radsniff # +# @param envfile path to the environment file, used by the systemd unit # @param options commandline options passed to radsniff when it runs +# @param class freeradius::radsniff ( + Optional[String] $envfile = undef, String $options = '', -) { + Optional[String] $pidfile = undef, +) inherits freeradius::params { unless $::freeradius::utils_support { fail('freeradius::radsniff requires freeradius have utils_support enabled') } - unless $facts['os']['family'] == 'RedHat' { - fail('freeradius::radsniff only supports RedHat like OSes at the moment') + # Calculate the envfile to use - specified, then calculated, then error if none + if $envfile { + $final_envfile = $envfile + } else { + if $freeradius::fr_radsniff_envfile { + $final_envfile = $freeradius::fr_radsniff_envfile + } else { + fail('freeradius::radsniff requires envfile to be explicitly set on this OS') + } + } + + # Calculate the pidfile to use - specified, then calculated, then error if none + if $pidfile { + $final_pidfile = $pidfile + } else { + if $freeradius::fr_radsniff_pidfile { + $final_pidfile = $freeradius::fr_radsniff_pidfile + } else { + fail('freeradius::radsniff requires pidfile to be explicitly set on this OS') + } } $escaped_cmd = $options.regsubst('"','\\\\"','G') - file {'/etc/sysconfig/radsniff': + file { $envfile: content => @("SYSCONFIG"), RADSNIFF_OPTIONS="${escaped_cmd}" | SYSCONFIG diff --git a/spec/classes/radsniff.rb b/spec/classes/radsniff.rb index d4666503..bff7f05e 100644 --- a/spec/classes/radsniff.rb +++ b/spec/classes/radsniff.rb @@ -13,6 +13,14 @@ } end + if os_facts[:osfamily] =~ %r{^RedHat|Debian$} + it do + is_expected.to contain_service('radsniff') + .with_ensure('running') + .with_enable(true) + end + end + case os_facts[:osfamily] when 'RedHat' it do @@ -23,19 +31,63 @@ end it do - is_expected.to contain_service('radsniff') - .with_ensure('running') - .with_enable(true) + is_expected.to contain_systemd__unit_file('radsniff.service') + .with_content(%r{^Pidfile=/var/run/radiusd/radsniff.pid$}) + .with_content(%r{^EnvironmentFile=/etc/sysconfig/radsniff$}) + .with_content(%r{^ExecStart=/usr/bin/radsniff -P /var/run/radiusd/radsniff.pid -d /etc/raddb $RADSNIFF_OPTIONS$}) + .that_notifies('Service[radsniff]') + end + when 'Debian' + it do + is_expected.to contain_file('/etc/defaults/radsniff') + .with_content(%r{RADSNIFF_OPTIONS="radsniff cmd \\"line\\" options"}) + .that_notifies('Service[radsniff]') + .that_requires('Package[freeradius-utils]') end it do is_expected.to contain_systemd__unit_file('radsniff.service') - .with_source('puppet:///modules/freeradius/radsniff.service') + .with_content(%r{^Pidfile=/var/run/freeradius/radsniff.pid$}) + .with_content(%r{^EnvironmentFile=/etc/defaults/radsniff$}) + .with_content(%r{^ExecStart=/usr/bin/radsniff -P /var/run/freeradius/radsniff.pid -d /etc/freeradius $RADSNIFF_OPTIONS$}) .that_notifies('Service[radsniff]') end else it do - is_expected.to compile.and_raise_error(%r{radsniff only supports RedHat}) + is_expected.to compile.and_raise_error(%r{freeradius::radsniff requires envfile to be explicitly set on this OS}) + is_expected.to compile.and_raise_error(%r{freeradius::radsniff requires pidfile to be explicitly set on this OS}) + end + end + + context 'with envfile and pidfile set' do + let(:params) do + super().merge( + envfile: '/test/env/file', + pidfile: '/a/pid/file', + ) + end + + if os_facts[:osfamily] !~ %r{^RedHat|Debian$} + it do + is_expected.to contain_service('radsniff') + .with_ensure('running') + .with_enable(true) + end + end + + it do + is_expected.to contain_file('/test/env/file') + .with_content(%r{RADSNIFF_OPTIONS="radsniff cmd \\"line\\" options"}) + .that_notifies('Service[radsniff]') + .that_requires('Package[freeradius-utils]') + end + + it do + is_expected.to contain_systemd__unit_file('radsniff.service') + .with_content(%r{^Pidfile=/a/pid/file$}) + .with_content(%r{^EnvironmentFile=/test/env/file$}) + .with_content(%r{^ExecStart=/usr/bin/radsniff -P /a/pid/file -d /etc/freeradius $RADSNIFF_OPTIONS$}) + .that_notifies('Service[radsniff]') end end end diff --git a/templates/radsniff.service.erb b/templates/radsniff.service.erb new file mode 100644 index 00000000..93fe7dfd --- /dev/null +++ b/templates/radsniff.service.erb @@ -0,0 +1,13 @@ +[Unit] +Description=Capture RADIUS statistics +After=syslog.target network.target +After=radiusd.target + +[Service] +Type=forking +Pidfile=<%=scope['::freeradius::radsniff::final_pidfile']%> +EnvironmentFile=<%=scope['::freeradius::radsniff::final_envpath']%> +ExecStart=/usr/bin/radsniff -P <%=scope['::freeradius::radsniff::pidpath']%> -d <%=scope['::freeradius::radsniff::fr_basepath']%> $RADSNIFF_OPTIONS + +[Install] +WantedBy=multi-user.target From b3642d7d4274b92948608f730ee0ac1a3cb87567 Mon Sep 17 00:00:00 2001 From: Nathan Ward Date: Fri, 14 May 2021 23:39:00 +1200 Subject: [PATCH 4/4] Fix up radsniff tests so they actually run, and fix up all the silly mistakes I had made.. --- .fixtures.yml | 1 + manifests/radsniff.pp | 14 +++---- .../classes/{radsniff.rb => radsniff_spec.rb} | 38 ++++++++++++++++--- spec/spec_helper_local.rb | 10 +++-- templates/radsniff.service.erb | 4 +- 5 files changed, 49 insertions(+), 18 deletions(-) rename spec/classes/{radsniff.rb => radsniff_spec.rb} (67%) diff --git a/.fixtures.yml b/.fixtures.yml index 86570f89..02c2eb77 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -5,3 +5,4 @@ fixtures: logrotate: "puppet/logrotate" rsyslog: "saz/rsyslog" stdlib: "puppetlabs/stdlib" + systemd: "camptocamp/systemd" diff --git a/manifests/radsniff.pp b/manifests/radsniff.pp index 21837064..52c1c3b1 100644 --- a/manifests/radsniff.pp +++ b/manifests/radsniff.pp @@ -16,8 +16,8 @@ if $envfile { $final_envfile = $envfile } else { - if $freeradius::fr_radsniff_envfile { - $final_envfile = $freeradius::fr_radsniff_envfile + if $freeradius::radsniff::fr_radsniff_envfile { + $final_envfile = $freeradius::radsniff::fr_radsniff_envfile } else { fail('freeradius::radsniff requires envfile to be explicitly set on this OS') } @@ -27,8 +27,8 @@ if $pidfile { $final_pidfile = $pidfile } else { - if $freeradius::fr_radsniff_pidfile { - $final_pidfile = $freeradius::fr_radsniff_pidfile + if $freeradius::radsniff::fr_radsniff_pidfile { + $final_pidfile = $freeradius::radsniff::fr_radsniff_pidfile } else { fail('freeradius::radsniff requires pidfile to be explicitly set on this OS') } @@ -36,7 +36,7 @@ $escaped_cmd = $options.regsubst('"','\\\\"','G') - file { $envfile: + file { $final_envfile: content => @("SYSCONFIG"), RADSNIFF_OPTIONS="${escaped_cmd}" | SYSCONFIG @@ -51,7 +51,7 @@ } systemd::unit_file {'radsniff.service': - source => 'puppet:///modules/freeradius/radsniff.service', - notify => Service['radsniff'], + content => template('freeradius/radsniff.service.erb'), + notify => Service['radsniff'], } } diff --git a/spec/classes/radsniff.rb b/spec/classes/radsniff_spec.rb similarity index 67% rename from spec/classes/radsniff.rb rename to spec/classes/radsniff_spec.rb index bff7f05e..5687907b 100644 --- a/spec/classes/radsniff.rb +++ b/spec/classes/radsniff_spec.rb @@ -2,9 +2,9 @@ describe 'freeradius::radsniff' do on_supported_os.each do |os, os_facts| - context "on #{os}" do - include_context 'freeradius_with_utils' + include_context 'freeradius_with_utils' + context "on #{os}" do let(:facts) { os_facts } let(:params) do @@ -13,6 +13,34 @@ } end + let(:pre_condition) do + precondition = case os_facts[:osfamily] + when 'RedHat' + 'class freeradius::params { + $fr_basepath = "/etc/raddb" + $fr_radsniff_pidfile = "/var/run/radiusd/radsniff.pid" + $fr_radsniff_envfile = "/etc/sysconfig/radsniff" + } + include freeradius::params' + when 'Debian' + 'class freeradius::params { + $fr_basepath = "/etc/freeradius" + $fr_radsniff_pidfile = "/var/run/freeradius/radsniff.pid" + $fr_radsniff_envfile = "/etc/defaults/radsniff" + } + include freeradius::params' + else + 'class freeradius::params { + $fr_basepath = "/etc/raddb" + $fr_radsniff_pidfile = "/var/run/radiusd/radsniff.pid" + $fr_radsniff_envfile = undef + } + include freeradius::params' + end + + super().push(precondition) + end + if os_facts[:osfamily] =~ %r{^RedHat|Debian$} it do is_expected.to contain_service('radsniff') @@ -34,7 +62,7 @@ is_expected.to contain_systemd__unit_file('radsniff.service') .with_content(%r{^Pidfile=/var/run/radiusd/radsniff.pid$}) .with_content(%r{^EnvironmentFile=/etc/sysconfig/radsniff$}) - .with_content(%r{^ExecStart=/usr/bin/radsniff -P /var/run/radiusd/radsniff.pid -d /etc/raddb $RADSNIFF_OPTIONS$}) + .with_content(%r{^ExecStart=/usr/bin/radsniff -P /var/run/radiusd/radsniff.pid -d /etc/raddb \$RADSNIFF_OPTIONS$}) .that_notifies('Service[radsniff]') end when 'Debian' @@ -49,7 +77,7 @@ is_expected.to contain_systemd__unit_file('radsniff.service') .with_content(%r{^Pidfile=/var/run/freeradius/radsniff.pid$}) .with_content(%r{^EnvironmentFile=/etc/defaults/radsniff$}) - .with_content(%r{^ExecStart=/usr/bin/radsniff -P /var/run/freeradius/radsniff.pid -d /etc/freeradius $RADSNIFF_OPTIONS$}) + .with_content(%r{^ExecStart=/usr/bin/radsniff -P /var/run/freeradius/radsniff.pid -d /etc/freeradius \$RADSNIFF_OPTIONS$}) .that_notifies('Service[radsniff]') end else @@ -86,7 +114,7 @@ is_expected.to contain_systemd__unit_file('radsniff.service') .with_content(%r{^Pidfile=/a/pid/file$}) .with_content(%r{^EnvironmentFile=/test/env/file$}) - .with_content(%r{^ExecStart=/usr/bin/radsniff -P /a/pid/file -d /etc/freeradius $RADSNIFF_OPTIONS$}) + .with_content(%r{^ExecStart=/usr/bin/radsniff -P /a/pid/file -d .* \$RADSNIFF_OPTIONS$}) .that_notifies('Service[radsniff]') end end diff --git a/spec/spec_helper_local.rb b/spec/spec_helper_local.rb index 1377bcfa..f66ce653 100644 --- a/spec/spec_helper_local.rb +++ b/spec/spec_helper_local.rb @@ -57,10 +57,12 @@ shared_context 'freeradius_with_utils' do let(:pre_condition) do [ - redhat_params_class, - 'class { freeradius: - utils_support => true, - }', + 'class freeradius { + $utils_support = true + } + include freeradius + + package { "freeradius-utils": }', ] end end diff --git a/templates/radsniff.service.erb b/templates/radsniff.service.erb index 93fe7dfd..baf50dc8 100644 --- a/templates/radsniff.service.erb +++ b/templates/radsniff.service.erb @@ -6,8 +6,8 @@ After=radiusd.target [Service] Type=forking Pidfile=<%=scope['::freeradius::radsniff::final_pidfile']%> -EnvironmentFile=<%=scope['::freeradius::radsniff::final_envpath']%> -ExecStart=/usr/bin/radsniff -P <%=scope['::freeradius::radsniff::pidpath']%> -d <%=scope['::freeradius::radsniff::fr_basepath']%> $RADSNIFF_OPTIONS +EnvironmentFile=<%=scope['::freeradius::radsniff::final_envfile']%> +ExecStart=/usr/bin/radsniff -P <%=scope['::freeradius::radsniff::final_pidfile']%> -d <%=scope['::freeradius::radsniff::fr_basepath']%> $RADSNIFF_OPTIONS [Install] WantedBy=multi-user.target