2015-10-11 22:21:11 +00:00
# encoding: utf-8
# Usage:
# describe iptables do
# it { should have_rule('-P INPUT ACCEPT') }
# end
#
# The following serverspec sytax is not implemented:
# describe iptables do
# it { should have_rule('-P INPUT ACCEPT').with_table('mangle').with_chain('INPUT') }
# end
# Please use the new sytax:
# describe iptables(table:'mangle', chain: 'input') do
# it { should have_rule('-P INPUT ACCEPT') }
# end
#
2015-10-12 08:32:46 +00:00
# Note: Docker containers normally do not have iptables installed
2015-10-11 22:21:11 +00:00
#
# @see http://ipset.netfilter.org/iptables.man.html
# @see http://ipset.netfilter.org/iptables.man.html
# @see https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html
2016-03-08 18:06:55 +00:00
module Inspec::Resources
class IpTables < Inspec . resource ( 1 )
name 'iptables'
2018-02-19 14:26:49 +00:00
supports platform : 'linux'
2016-03-08 18:06:55 +00:00
desc 'Use the iptables InSpec audit resource to test rules that are defined in iptables, which maintains tables of IP packet filtering rules. There may be more than one table. Each table contains one (or more) chains (both built-in and custom). A chain is a list of rules that match packets. When the rule matches, the rule defines what target to assign to the packet.'
2019-03-19 14:17:32 +00:00
example << ~ EXAMPLE
2016-03-08 18:06:55 +00:00
describe iptables do
it { should have_rule ( '-P INPUT ACCEPT' ) }
end
2019-03-19 14:17:32 +00:00
EXAMPLE
2015-10-11 22:21:11 +00:00
2016-03-08 18:06:55 +00:00
def initialize ( params = { } )
@table = params [ :table ]
@chain = params [ :chain ]
2015-10-12 08:32:46 +00:00
2016-03-08 18:06:55 +00:00
# we're done if we are on linux
return if inspec . os . linux?
2015-10-12 08:32:46 +00:00
2016-03-08 18:06:55 +00:00
# ensures, all calls are aborted for non-supported os
@iptables_cache = [ ]
skip_resource 'The `iptables` resource is not supported on your OS yet.'
end
2015-10-11 22:21:11 +00:00
2016-03-08 18:06:55 +00:00
def has_rule? ( rule = nil , _table = nil , _chain = nil )
# checks if the rule is part of the ruleset
# for now, we expect an exact match
retrieve_rules . any? { | line | line . casecmp ( rule ) == 0 }
end
2015-10-11 22:21:11 +00:00
2016-03-08 18:06:55 +00:00
def retrieve_rules
return @iptables_cache if defined? ( @iptables_cache )
2015-10-11 22:21:11 +00:00
2016-03-08 18:06:55 +00:00
# construct iptables command to read all rules
2018-03-06 13:56:15 +00:00
bin = find_iptables_or_error
2016-03-08 18:06:55 +00:00
table_cmd = " -t #{ @table } " if @table
2018-03-06 13:56:15 +00:00
iptables_cmd = format ( '%s %s -S %s' , bin , table_cmd , @chain ) . strip
2016-02-09 16:27:43 +00:00
2016-03-08 18:06:55 +00:00
cmd = inspec . command ( iptables_cmd )
return [ ] if cmd . exit_status . to_i != 0
2015-10-11 22:21:11 +00:00
2016-03-08 18:06:55 +00:00
# split rules, returns array or rules
@iptables_cache = cmd . stdout . split ( " \n " ) . map ( & :strip )
end
2015-10-11 22:21:11 +00:00
2016-03-08 18:06:55 +00:00
def to_s
format ( 'Iptables %s %s' , @table && " table: #{ @table } " , @chain && " chain: #{ @chain } " ) . strip
end
2018-03-06 13:56:15 +00:00
private
def find_iptables_or_error
%w{ /usr/sbin/iptables /sbin/iptables iptables } . each do | cmd |
return cmd if inspec . command ( cmd ) . exist?
end
raise Inspec :: Exceptions :: ResourceFailed , 'Could not find `iptables`'
end
2015-10-11 22:21:11 +00:00
end
end