CFINSPEC-66 : Add Ipfilter resource

Signed-off-by: Sonu Saha <sonu.saha@progress.com>
This commit is contained in:
Sonu Saha 2022-02-24 23:46:25 +05:30 committed by Clinton Wolfe
parent 136a805c1e
commit 7c874e67df
5 changed files with 203 additions and 0 deletions

View file

@ -0,0 +1,75 @@
+++
title = "ipfilter resource"
draft = false
gh_repo = "inspec"
platform = "bsd"
platform = "solaris"
[menu]
[menu.inspec]
title = "ipfilter"
identifier = "inspec/resources/os/ipfilter.md ipfilter resource"
parent = "inspec/resources/os"
+++
Use the `ipfilter` Chef InSpec audit resource to test rules that are defined for `ipfilter`. The `ipfstat` utility is used to report on packet filter statistics and filter list. `ipfstat -io` is used to view the active filtering rule set for the input and the output side of the kernel IP processing. The rule match is done against the output rules of `ipfstat -io`.
## Availability
### Installation
This resource is distributed along with Chef InSpec itself. You can use it automatically.
## Syntax
An `ipfilter` resource block declares tests for rules in IP tables:
describe ipfilter do
it { should have_rule("RULE") }
end
where
- `have_rule('RULE')` tests the active rule for ipfilter. This must match the entire line taken from `'ipfstat -io'`.
## Examples
The following examples show how to use this Chef InSpec audit resource.
### Test if there are no restrictions on loopback interface
describe ipfilter do
it { should have_rule("pass in quick on lo0 all") }
it { should have_rule("pass out quick on lo0 all") }
end
### Test if there are no restrictions on inside LAN interface named xl0 for private network
describe ipfilter do
it { should have_rule("pass in quick on xl0 all") }
it { should have_rule("pass out quick on xl0 all") }
end
### Test if there is a rule allowing FTP traffic on the public interface named dc0
describe iptables do
it { should have_rule("pass out quick on dc0 proto tcp from any to any port = ftp flags S/FSRPAU keep state") }
end
### Test if there is a rule allowing SSH on the public interface named dc0
describe iptables do
it { should have_rule("pass out quick on dc0 proto tcp from any to any port = ssh flags S/FSRPAU keep state") }
end
Note that the rule specification must exactly match what's in the output of `'ipfstat -io'`, which will depend on how you've built your rules.
## Matchers
For a full list of available matchers, please visit our [matchers page](/inspec/matchers/).
### have_rule
The `have_rule` matcher tests the named rule against the information in the output rule of `'ipftstat -io'`:
it { should have_rule("RULE") }

View file

@ -0,0 +1,58 @@
require "inspec/resources/command"
module Inspec::Resources
class IpFilter < Inspec.resource(1)
name "ipfilter"
supports platform: "freebsd"
supports platform: "solaris"
desc "Use the ipfilter InSpec audit resource to test rules that are defined for ipfilter, which maintains the IP rule set"
example <<~EXAMPLE
describe ipfilter do
it { should have_rule("pass in quick on lo0 all") }
end
EXAMPLE
def initialize
# checks if the instance is either bsd or solaris
return if inspec.os.bsd? || inspec.os.solaris?
# ensures, all calls are aborted for non-supported os
@ipfilter_cache = []
skip_resource "The `ipfilter` resource is not supported on your OS yet."
end
def has_rule?(rule = nil)
# checks if the rule is part of the ruleset
retrieve_rules.any? { |line| line.casecmp(rule) == 0 }
end
def retrieve_rules
# this would be true if the OS family was not bsd/solaris when checked in initliaze
return @ipfilter_cache if defined?(@ipfilter_cache)
# construct ipfstat command to read all rules
bin = find_ipfstat_or_error
ipfstat_cmd = "#{bin} -io"
cmd = inspec.command(ipfstat_cmd)
# Return empty array when command is not executed successfully
# or there is no output since no rules are active
return [] if cmd.exit_status.to_i != 0 || cmd.stdout == ""
# split rules, returns array or rules
@iptables_cache = cmd.stdout.split("\n").map(&:strip)
end
def to_s
format("Ipfilter").strip
end
private
def find_ipfstat_or_error
%w{/usr/sbin/ipfstat /sbin/ipfstat ipfstat}.each do |cmd|
return cmd if inspec.command(cmd).exist?
end
raise Inspec::Exceptions::ResourceFailed, "Could not find `ipfstat`"
end
end
end

35
test/fixtures/cmd/ipfstat-io vendored Normal file
View file

@ -0,0 +1,35 @@
pass out quick on lo0 all
pass out quick on xl0 all
pass out quick on dc0 proto tcp from any to any port = http flags S/FSRPAU keep state
pass out quick on dc0 proto tcp from any to any port = https flags S/FSRPAU keep state
pass out quick on dc0 proto tcp from any to any port = pop3 flags S/FSRPAU keep state
pass out quick on dc0 proto tcp from any to any port = smtp flags S/FSRPAU keep state
pass out quick on dc0 proto tcp from any to any port = time flags S/FSRPAU keep state
pass out quick on d0c0 proto tcp from any to any port = ftp flags S/FSRPAU keep state
pass out quick on dc0 proto tcp from any to any port = ssh flags S/FSRPAU keep state
pass out quick on dc0 inet proto icmp from any to any icmp-type echo keep state
block out log first quick on dc0 all
pass in quick on lo0 all
pass in quick on xl0 all
block in quick on dc0 inet from 192.168.0.0/16 to any
block in quick on dc0 inet from 172.16.0.0/12 to any
block in quick on dc0 inet from 10.0.0.0/8 to any
block in quick on dc0 inet from 127.0.0.0/8 to any
block in quick on dc0 inet from 0.0.0.0/8 to any
block in quick on dc0 inet from 169.254.0.0/16 to any
block in quick on dc0 inet from 192.0.2.0/24 to any
block in quick on dc0 inet from 204.152.64.0/23 to any
block in quick on dc0 inet from 224.0.0.0/3 to any
block in quick on dc0 from any to any with frag
block in quick on dc0 proto tcp from any to any with short
block in quick on dc0 inet from any to any with opt lsrr
block in quick on dc0 inet from any to any with opt ssrr
block in log first quick on dc0 proto tcp from any to any flags FPU/FSRPAU
block in quick on dc0 from any to any with ipopts
block in quick on dc0 inet proto icmp from any to any icmp-type echo
block in quick on dc0 proto tcp from any to any port = auth
block in log first quick on dc0 proto tcp/udp from any to any port = netbios-ns
block in log first quick on dc0 proto tcp/udp from any to any port = netbios-dgm
block in log first quick on dc0 proto tcp/udp from any to any port = netbios-ssn
block in log first quick on dc0 proto tcp/udp from any to any port = 81
block in log first quick on dc0 all

View file

@ -372,6 +372,9 @@ class MockLoader
# ipnat
"/usr/sbin/ipnat -l" => cmd.call("ipnat-l"),
%{type "/usr/sbin/ipnat"} => empty.call,
# ipfilter
"/usr/sbin/ipfstat -io" => cmd.call("ipfstat-io"),
%{type "/usr/sbin/ipfstat"} => empty.call,
# apache_conf
"sh -c 'find /etc/apache2/ports.conf -type f -maxdepth 1'" => cmd.call("find-apache2-ports-conf"),
"sh -c 'find /etc/httpd/conf.d/*.conf -type f -maxdepth 1'" => cmd.call("find-httpd-ssl-conf"),

View file

@ -0,0 +1,32 @@
require "helper"
require "inspec/resource"
require "inspec/resources/ipfilter"
describe "Inspec::Resources::Ipfilter" do
# freebsd11
it "verify ipfilter on freebsd11" do
resource = MockLoader.new(:freebsd11).load_resource("ipfilter")
_(resource.has_rule?("pass out quick on lo0 all")).must_equal true
_(resource.has_rule?("pass in quick on lo0 all")).must_equal true
_(resource.has_rule?("block in quick on dc0 inet from 10.0.0.0/8 to any")).must_equal true
_(resource.has_rule?(nil)).must_equal false
end
# solaris11
it "verify ipfilter on solaris11" do
resource = MockLoader.new(:solaris11).load_resource("ipfilter")
_(resource.has_rule?("pass out quick on lo0 all")).must_equal true
_(resource.has_rule?("pass in quick on lo0 all")).must_equal true
_(resource.has_rule?("block in quick on dc0 inet from 10.0.0.0/8 to any")).must_equal true
_(resource.has_rule?(nil)).must_equal false
end
# undefined
it "verify ipfilter on unsupported os" do
resource = MockLoader.new(:undefined).load_resource("ipfilter")
_(resource.has_rule?("pass out quick on lo0 all")).must_equal false
_(resource.has_rule?("pass in quick on lo0 all")).must_equal false
_(resource.has_rule?("block in quick on dc0 inet from 10.0.0.0/8 to any")).must_equal false
end
end