Merge pull request #5597 from mitre/firewalld_update

Firewalld update -- exposed more fields, updated docs, added custom matchers
This commit is contained in:
Clinton Wolfe 2022-03-10 15:40:17 -05:00 committed by GitHub
commit 63a5fd26a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 199 additions and 23 deletions

View file

@ -40,6 +40,7 @@ Use the where clause to test open interfaces, sources, and services that are in
its('interfaces') { should cmp ['enp0s3', 'eno2'] }
its('sources') { should cmp ['192.168.1.0/24', '192.168.1.2'] }
its('services') { should cmp ['ssh', 'icmp'] }
its('target') { should cmp ['default'] }
end
## Properties
@ -68,7 +69,31 @@ The `services` property is used in conjunction with the where class to display o
its('services') { should cmp ['ssh', 'icmp'] }
end
### `default_zone`
### target
The `target` property is used in conjunction with the where class to display the target action in an active zone.
describe firewalld.where { zone == 'public' } do
its('target') { should cmp ['default'] } # or ['DROP'], ['ACCEPT'], etc.
end
### ports
The `ports` property is used in conjunction with the where class to display the ports used by an active zone.
describe firewalld.where { zone == 'public' } do
its('ports') { should cmp ["80/tcp", "443/tcp"] }
end
### protocols
The `protocols` property is used in conjunction with the where class to display the protocols used by an active zone.
describe firewalld.where { zone == 'public' } do
its('protocols') { should cmp ["icmp", "ipv4"] }
end
### default_zone
The `default_zone` property displays the default active zone to be used.
@ -114,4 +139,16 @@ The `be_running` matcher tests if the firewalld service is running:
it { should have_rule_enabled('family=ipv4 source address=192.168.0.14 accept', 'public') }
It is not necessary to add the "rule" string, and you can start with the optional flags that are used in firewalld and end with the action
It is not necessary to add the "rule" string, and you can start with the optional flags that are used in firewalld and end with the action.
### `have_icmp_block_inversion_enabled`
`have_icmp_block_inversion_enabled` returns true or false if ICMP block inversion flag is set for the indicated zone.
it { should have_icmp_block_inversion_enabled }
### `have_masquerade_enabled`
`have_masquerade_enabled` returns true or false if the masquerade flag is set for the indicated zone.
it { should have_masquerade_enabled }

View file

@ -32,6 +32,17 @@ module Inspec::Resources
.register_column(:interfaces, field: "interfaces")
.register_column(:sources, field: "sources")
.register_column(:services, field: "services")
.register_column(:target, field: "target")
.register_column(:ports, field: "ports")
.register_column(:protocols, field: "protocols")
.register_column(:forward_ports, field: "forward_ports")
.register_column(:source_ports, field: "source_ports")
.register_column(:icmp_blocks, field: "icmp_blocks")
.register_column(:rich_rules, field: "rich_rules")
.register_custom_matcher(:icmp_block_inversion?) { |x| x.params[0]["icmp_block_inversion"] }
.register_custom_matcher(:has_icmp_block_inversion_enabled?) { |x| x.params[0]["icmp_block_inversion"] }
.register_custom_matcher(:masquerade?) { |x| x.params[0]["masquerade"] }
.register_custom_matcher(:has_masquerade_enabled?) { |x| x.params[0]["masquerade"] }
filter.install_filter_methods_on_resource(self, :params)
@ -64,28 +75,28 @@ module Inspec::Resources
end
def has_service_enabled_in_zone?(query_service, query_zone = default_zone)
firewalld_command("--zone=#{query_zone} --query-service=#{query_service}") == "yes"
firewalld_command("--permanent --zone=#{query_zone} --query-service=#{query_service}") == "yes"
end
def service_ports_enabled_in_zone(query_service, query_zone = default_zone)
# return: String of ports open
# example: ['22/tcp', '4722/tcp']
firewalld_command("--zone=#{query_zone} --service=#{query_service} --get-ports --permanent").split(" ")
firewalld_command("--permanent --zone=#{query_zone} --service=#{query_service} --get-ports").split(" ")
end
def service_protocols_enabled_in_zone(query_service, query_zone = default_zone)
# return: String of protocoals open
# return: String of protocols open
# example: ['icmp', 'ipv4', 'igmp']
firewalld_command("--zone=#{query_zone} --service=#{query_service} --get-protocols --permanent").split(" ")
firewalld_command("--permanent --zone=#{query_zone} --service=#{query_service} --get-protocols").split(" ")
end
def has_port_enabled_in_zone?(query_port, query_zone = default_zone)
firewalld_command("--zone=#{query_zone} --query-port=#{query_port}") == "yes"
firewalld_command("--permanent --zone=#{query_zone} --query-port=#{query_port}") == "yes"
end
def has_rule_enabled?(rule, query_zone = default_zone)
rule = "rule #{rule}" unless rule.start_with?("rule")
firewalld_command("--zone=#{query_zone} --query-rich-rule='#{rule}'") == "yes"
firewalld_command("--permanent --zone=#{query_zone} --query-rich-rule='#{rule}'") == "yes"
end
def to_s
@ -120,19 +131,82 @@ module Inspec::Resources
"interfaces" => line.split(":")[1].split(" "),
"services" => services_bound(zone),
"sources" => sources_bound(zone),
"target" => target_bound(zone),
"icmp_block_inversion" => icmp_block_inversion_bound?(zone),
"ports" => ports_bound(zone),
"protocols" => protocols_bound(zone),
"masquerade" => masquerade_bound?(zone),
"forward_ports" => forward_ports_bound(zone),
"source_ports" => source_ports_bound(zone),
"icmp_blocks" => icmp_blocks_bound(zone),
"rich_rules" => rich_rules_bound(zone),
}
end
def target_bound(query_zone)
# result: a target bound for the zone
# example: 'DROP'
firewalld_command("--permanent --zone=#{query_zone} --get-target").strip
end
def icmp_block_inversion_bound?(query_zone)
# result: true/false whether inversion of icmp blocks has been enabled for a zone
# example: true
firewalld_command("--permanent --zone=#{query_zone} --query-icmp-block-inversion") == "yes"
end
def ports_bound(query_zone)
# result: a list of ports bound for a zone
# example: ['80/tcp', '443/tcp']
firewalld_command("--permanent --zone=#{query_zone} --list-ports").split(" ")
end
def protocols_bound(query_zone)
# result: a list of protocols added for a zone
# example: ['icmp', 'ipv4', 'igmp']
firewalld_command("--permanent --zone=#{query_zone} --list-protocols").split(" ")
end
def masquerade_bound?(query_zone)
# result: true/false whether IPv4 masquerading has been enabled for a zone
# example: true
firewalld_command("--permanent --zone=#{query_zone} --query-masquerade") == "yes"
end
def forward_ports_bound(query_zone)
# result: a list of IPv4 forward ports bound to a zone
# example: ['port=80:proto=tcp:toport=88', 'port=12345:proto=tcp:toport=54321:toaddr=192.168.1.3']
firewalld_command("--permanent --zone=#{query_zone} --list-forward-ports").split("\n")
end
def source_ports_bound(query_zone)
# result: a list of source ports bound to a zone
# example: ['80/tcp', '8080/tcp']
firewalld_command("--permanent --zone=#{query_zone} --list-source-ports").split(" ")
end
def icmp_blocks_bound(query_zone)
# result: a list of internet ICMP type blocks bound to a zone
# example: ['echo-request', 'echo-reply']
firewalld_command("--permanent --zone=#{query_zone} --list-icmp-blocks").split(" ")
end
def rich_rules_bound(query_zone)
# result: a list of rich language rules bound to a zone
# example: ['rule protocol value="ah" accept', 'rule service name="ftp" log limit value="1/m" audit accept']
firewalld_command("--permanent --zone=#{query_zone} --list-rich-rules").split("\n")
end
def sources_bound(query_zone)
# result: a list containing either an ip address or ip address with a mask, or a ipset or an ipset with the ipset prefix.
# example: ['192.168.0.4', '192.168.0.0/16', '2111:DB28:ABC:12::', '2111:db89:ab3d:0112::0/64']
firewalld_command("--zone=#{query_zone} --list-sources").split(" ")
firewalld_command("--permanent --zone=#{query_zone} --list-sources").split(" ")
end
def services_bound(query_zone)
# result: a list of services bound to a zone.
# example: ['ssh', 'dhcpv6-client']
firewalld_command("--zone=#{query_zone} --list-services").split(" ")
firewalld_command("--permanent --zone=#{query_zone} --list-services").split(" ")
end
def firewalld_command(command)
@ -145,4 +219,4 @@ module Inspec::Resources
result.stdout.strip
end
end
end
end

View file

@ -0,0 +1 @@
default

View file

@ -0,0 +1,2 @@
port=80:proto=tcp:toport=88:toaddr=
port=12345:proto=tcp:toport=54321:toaddr=192.168.1.3

View file

@ -0,0 +1 @@
echo-request echo-reply

View file

@ -0,0 +1 @@
80/tcp 443/tcp

View file

@ -0,0 +1 @@
icmp ipv4

View file

@ -0,0 +1,2 @@
rule protocol value="ah" accept
rule service name="ftp" log limit value="1/m" audit accept

View file

@ -0,0 +1 @@
80/tcp 8080/tcp

View file

@ -0,0 +1 @@
no

View file

@ -0,0 +1 @@
no

View file

@ -523,16 +523,25 @@ class MockLoader
"firewall-cmd --get-default-zone" => cmd.call("firewall-cmd--get-default-zone"),
"firewall-cmd --get-active-zones" => cmd.call("firewall-cmd--get-active-zones"),
"firewall-cmd --state" => cmd.call("firewall-cmd--state"),
"firewall-cmd --zone=public --query-service=ssh" => cmd.call("firewall-cmd--service-enabled-in-zone"),
"firewall-cmd --zone=public --query-port=22/udp" => cmd.call("firewall-cmd-has-port-enabled-in-zone"),
"firewall-cmd --zone=public --query-rich-rule='rule family=ipv4 source address=192.168.0.14 accept'" => cmd.call("firewall-cmd-has-rule-enabled"),
"firewall-cmd --zone=public --service=ssh --get-ports --permanent" => cmd.call("firewall-cmd-service-ports-enabled-in-zone"),
"firewall-cmd --zone=public --service=ssh --get-protocols --permanent" => cmd.call("firewall-cmd-service-protocols-enabled-in-zone"),
"firewall-cmd --zone=public --list-services" => cmd.call("firewall-cmd-services-bound"),
"firewall-cmd --zone=default --list-services" => cmd.call("firewall-cmd-services-bound"),
"firewall-cmd --zone=public --list-sources" => cmd.call("firewall-cmd-sources-bound"),
"firewall-cmd --zone=default --list-sources" => cmd.call("firewall-cmd-sources-bound"),
"firewall-cmd --zone=public --query-rich-rule=rule family=ipv4 source address=192.168.0.14 accept" => cmd.call("firewall-cmd-has-rule-enabled"),
"firewall-cmd --permanent --zone=public --query-service=ssh" => cmd.call("firewall-cmd--service-enabled-in-zone"),
"firewall-cmd --permanent --zone=public --query-port=22/udp" => cmd.call("firewall-cmd-has-port-enabled-in-zone"),
"firewall-cmd --permanent --zone=public --query-rich-rule='rule family=ipv4 source address=192.168.0.14 accept'" => cmd.call("firewall-cmd-has-rule-enabled"),
"firewall-cmd --permanent --zone=public --service=ssh --get-ports" => cmd.call("firewall-cmd-service-ports-enabled-in-zone"),
"firewall-cmd --permanent --zone=public --service=ssh --get-protocols" => cmd.call("firewall-cmd-service-protocols-enabled-in-zone"),
"firewall-cmd --permanent --zone=public --list-services" => cmd.call("firewall-cmd-services-bound"),
"firewall-cmd --permanent --zone=default --list-services" => cmd.call("firewall-cmd-services-bound"),
"firewall-cmd --permanent --zone=public --list-sources" => cmd.call("firewall-cmd-sources-bound"),
"firewall-cmd --permanent --zone=default --list-sources" => cmd.call("firewall-cmd-sources-bound"),
"firewall-cmd --permanent --zone=public --get-target" => cmd.call("firewall-cmd-get-target"),
"firewall-cmd --permanent --zone=public --query-icmp-block-inversion" => cmd.call("firewall-cmd-query-icmp-block-inversion"),
"firewall-cmd --permanent --zone=public --list-ports" => cmd.call("firewall-cmd-list-ports"),
"firewall-cmd --permanent --zone=public --list-protocols" => cmd.call("firewall-cmd-list-protocols"),
"firewall-cmd --permanent --zone=public --query-masquerade" => cmd.call("firewall-cmd-query-masquerade"),
"firewall-cmd --permanent --zone=public --list-forward-ports" => cmd.call("firewall-cmd-list-forward-ports"),
"firewall-cmd --permanent --zone=public --list-source-ports" => cmd.call("firewall-cmd-list-source-ports"),
"firewall-cmd --permanent --zone=public --list-icmp-blocks" => cmd.call("firewall-cmd-list-icmp-blocks"),
"firewall-cmd --permanent --zone=public --list-rich-rules" => cmd.call("firewall-cmd-list-rich-rules"),
"firewall-cmd --permanent --zone=public --query-rich-rule=rule family=ipv4 source address=192.168.0.14 accept" => cmd.call("firewall-cmd-has-rule-enabled"),
"sh -c 'type \"firewall-cmd\"'" => cmd.call("firewall-cmd"),
"rpm -qia firewalld" => cmd.call("pkg-info-firewalld"),
"systemctl is-active sshd --quiet" => empty.call,

View file

@ -10,7 +10,7 @@ describe "Inspec::Resources::FirewallD" do
_(cent_resource.has_zone?("zonenotinfirewalld")).must_equal false
end
it "verity firewalld is running" do
it "verify firewalld is running" do
_(cent_resource.running?).must_equal true
end
@ -40,6 +40,51 @@ describe "Inspec::Resources::FirewallD" do
_(entries.sources).must_equal [["192.168.1.0/24", "192.168.1.2"]]
end
it "detects target in an active zone" do
entries = cent_resource.where { zone == "public" }
_(entries.target).must_equal ["default"]
end
it "detects whether ICMP block inversion is enabled in an active zone" do
entries = cent_resource.where { zone == "public" }
_(entries.icmp_block_inversion?).must_equal false
end
it "detects ports in an active zone" do
entries = cent_resource.where { zone == "public" }
_(entries.ports).must_equal [["80/tcp", "443/tcp"]]
end
it "detects protocols in an active zone" do
entries = cent_resource.where { zone == "public" }
_(entries.protocols).must_equal [%w{icmp ipv4}]
end
it "detects whether IPv4 masquerading is enabled in an active zone" do
entries = cent_resource.where { zone == "public" }
_(entries.masquerade?).must_equal false
end
it "detects IPv4 forward ports in an active zone" do
entries = cent_resource.where { zone == "public" }
_(entries.forward_ports).must_equal [["port=80:proto=tcp:toport=88:toaddr=", "port=12345:proto=tcp:toport=54321:toaddr=192.168.1.3"]]
end
it "detects source ports in an active zone" do
entries = cent_resource.where { zone == "public" }
_(entries.source_ports).must_equal [["80/tcp", "8080/tcp"]]
end
it "detects ICMP blocks in an active zone" do
entries = cent_resource.where { zone == "public" }
_(entries.icmp_blocks).must_equal [%w{echo-request echo-reply}]
end
it "detects rich rules in an active zone" do
entries = cent_resource.where { zone == "public" }
_(entries.rich_rules).must_equal [["rule protocol value=\"ah\" accept", "rule service name=\"ftp\" log limit value=\"1/m\" audit accept"]]
end
it "verify firewalld detects a whether or not a service is allowed in a zone" do
_(cent_resource.has_service_enabled_in_zone?("ssh", "public")).must_equal true
end
@ -52,7 +97,7 @@ describe "Inspec::Resources::FirewallD" do
_(cent_resource.service_protocols_enabled_in_zone("ssh", "public")).must_equal ["icmp"]
end
it "verify firewalld detects a whether or not a service is allowed in a zone" do
it "verify firewalld detects a whether or not a port is allowed in a zone" do
_(cent_resource.has_port_enabled_in_zone?("22/udp", "public")).must_equal true
end