Skip to content

Commit

Permalink
Merge pull request #1407 from FlatKey/ModSec-SecRuleRemoveBy-Tag-and-Msg
Browse files Browse the repository at this point in the history
Added vhost options SecRuleRemoveByTag and SecRuleRemoveByMsg
  • Loading branch information
bmjen committed Apr 14, 2016
2 parents 9fbbf1d + 800c7ce commit 1a2e229
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 1 deletion.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2272,6 +2272,38 @@ apache::vhost { 'sample.example.net':

Specifies an array of IP addresses to exclude from [`mod_security`][] rule matching. Default: undef.

###### `modsec_disable_msgs`

Array of mod_security Msgs to remove from the virtual host. Also takes a hash allowing removal of an Msg from a specific location. Default: undef.

``` puppet
apache::vhost { 'sample.example.net':
modsec_disable_msgs => [ 'Blind SQL Injection Attack', 'Session Fixation Attack' ],
}
```

``` puppet
apache::vhost { 'sample.example.net':
modsec_disable_msgs => { '/location1' => [ 'Blind SQL Injection Attack', 'Session Fixation Attack' ] },
}
```

###### `modsec_disable_tags`

Array of mod_security Tags to remove from the virtual host. Also takes a hash allowing removal of an Tag from a specific location. Default: undef.

``` puppet
apache::vhost { 'sample.example.net':
modsec_disable_tags => [ 'WEB_ATTACK/SQL_INJECTION', 'WEB_ATTACK/XSS' ],
}
```

``` puppet
apache::vhost { 'sample.example.net':
modsec_disable_tags => { '/location1' => [ 'WEB_ATTACK/SQL_INJECTION', 'WEB_ATTACK/XSS' ] },
}
```

##### `no_proxy_uris`

Specifies URLs you do not want to proxy. This parameter is meant to be used in combination with [`proxy_dest`](#proxy_dest).
Expand Down
26 changes: 25 additions & 1 deletion manifests/vhost.pp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@
$modsec_disable_vhost = undef,
$modsec_disable_ids = undef,
$modsec_disable_ips = undef,
$modsec_disable_msgs = undef,
$modsec_disable_tags = undef,
$modsec_body_limit = undef,
$jk_mounts = undef,
$auth_kerb = false,
Expand Down Expand Up @@ -520,6 +522,26 @@
}
}

if $modsec_disable_msgs {
if is_hash($modsec_disable_msgs) {
$_modsec_disable_msgs = $modsec_disable_msgs
} elsif is_array($modsec_disable_msgs) {
$_modsec_disable_msgs = { '.*' => $modsec_disable_msgs }
} else {
fail("Apache::Vhost[${name}]: 'modsec_disable_msgs' must be either a Hash of location/Msgs or an Array of Msgs")
}
}

if $modsec_disable_tags {
if is_hash($modsec_disable_tags) {
$_modsec_disable_tags = $modsec_disable_tags
} elsif is_array($modsec_disable_tags) {
$_modsec_disable_tags = { '.*' => $modsec_disable_tags }
} else {
fail("Apache::Vhost[${name}]: 'modsec_disable_tags' must be either a Hash of location/Tags or an Array of Tags")
}
}

concat { "${priority_real}${filename}.conf":
ensure => $ensure,
path => "${::apache::vhost_dir}/${priority_real}${filename}.conf",
Expand Down Expand Up @@ -996,8 +1018,10 @@
# - $modsec_disable_vhost
# - $modsec_disable_ids
# - $modsec_disable_ips
# - $modsec_disable_msgs
# - $modsec_disable_tags
# - $modsec_body_limit
if $modsec_disable_vhost or $modsec_disable_ids or $modsec_disable_ips {
if $modsec_disable_vhost or $modsec_disable_ids or $modsec_disable_ips or $modsec_disable_msgs or $modsec_disable_tags {
concat::fragment { "${name}-security":
target => "${priority_real}${filename}.conf",
order => 320,
Expand Down
121 changes: 121 additions & 0 deletions spec/acceptance/mod_security_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,126 @@ class { 'apache::mod::security': }

end #mod_security should allow disabling by id

context "mod_security should allow disabling by msg" do
it 'succeeds in puppeting mod_security' do
pp= <<-EOS
host { 'modsec.example.com': ip => '127.0.0.1', }
class { 'apache': }
class { 'apache::mod::security': }
apache::vhost { 'modsec.example.com':
port => '80',
docroot => '/var/www/html',
}
file { '/var/www/html/index.html':
ensure => file,
content => 'Index page',
}
file { '/var/www/html/index2.html':
ensure => file,
content => 'Page 2',
}
EOS
apply_manifest(pp, :catch_failures => true)
end

describe service($service_name) do
if (fact('operatingsystem') == 'Debian' && fact('operatingsystemmajrelease') == '8')
pending 'Should be enabled - Bug 760616 on Debian 8'
else
it { should be_enabled }
end
it { is_expected.to be_running }
end

describe file("#{$mod_dir}/security.conf") do
it { is_expected.to contain "mod_security2.c" }
end

it 'should block query with SQL' do
shell '/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users', :acceptable_exit_codes => [22]
end

it 'should disable mod_security per vhost' do
pp= <<-EOS
class { 'apache': }
class { 'apache::mod::security': }
apache::vhost { 'modsec.example.com':
port => '80',
docroot => '/var/www/html',
modsec_disable_msgs => [ 'Blind SQL Injection Attack' ],
}
EOS
apply_manifest(pp, :catch_failures => true)
end

it 'should return index page' do
shell('/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users') do |r|
expect(r.stdout).to match(/Index page/)
expect(r.exit_code).to eq(0)
end
end

end #mod_security should allow disabling by msg

context "mod_security should allow disabling by tag" do
it 'succeeds in puppeting mod_security' do
pp= <<-EOS
host { 'modsec.example.com': ip => '127.0.0.1', }
class { 'apache': }
class { 'apache::mod::security': }
apache::vhost { 'modsec.example.com':
port => '80',
docroot => '/var/www/html',
}
file { '/var/www/html/index.html':
ensure => file,
content => 'Index page',
}
file { '/var/www/html/index2.html':
ensure => file,
content => 'Page 2',
}
EOS
apply_manifest(pp, :catch_failures => true)
end

describe service($service_name) do
if (fact('operatingsystem') == 'Debian' && fact('operatingsystemmajrelease') == '8')
pending 'Should be enabled - Bug 760616 on Debian 8'
else
it { should be_enabled }
end
it { is_expected.to be_running }
end

describe file("#{$mod_dir}/security.conf") do
it { is_expected.to contain "mod_security2.c" }
end

it 'should block query with SQL' do
shell '/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users', :acceptable_exit_codes => [22]
end

it 'should disable mod_security per vhost' do
pp= <<-EOS
class { 'apache': }
class { 'apache::mod::security': }
apache::vhost { 'modsec.example.com':
port => '80',
docroot => '/var/www/html',
modsec_disable_tags => [ 'WEB_ATTACK/SQL_INJECTION' ],
}
EOS
apply_manifest(pp, :catch_failures => true)
end

it 'should return index page' do
shell('/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users') do |r|
expect(r.stdout).to match(/Index page/)
expect(r.exit_code).to eq(0)
end
end

end #mod_security should allow disabling by tag

end #apache::mod::security class
18 changes: 18 additions & 0 deletions templates/vhost/_security.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@
SecRule REMOTE_ADDR "<%= ips %>" "nolog,allow,id:1234123455"
SecAction "phase:2,pass,nolog,id:1234123456"
<% end -%>
<% if @_modsec_disable_msgs.is_a?(Hash) -%>
<% @_modsec_disable_msgs.each do |location,rules| -%>
<LocationMatch <%= location %>>
<% Array(rules).each do |rule| -%>
SecRuleRemoveByMsg "<%= rule %>"
<% end -%>
</LocationMatch>
<% end -%>
<% end -%>
<% if @_modsec_disable_tags.is_a?(Hash) -%>
<% @_modsec_disable_tags.each do |location,rules| -%>
<LocationMatch <%= location %>>
<% Array(rules).each do |rule| -%>
SecRuleRemoveByTag "<%= rule %>"
<% end -%>
</LocationMatch>
<% end -%>
<% end -%>
<% if @modsec_body_limit -%>
SecRequestBodyLimit <%= @modsec_body_limit %>
<% end -%>

0 comments on commit 1a2e229

Please sign in to comment.