Giter VIP home page Giter VIP logo

puppet-ferm's Introduction

puppet-ferm

Build Status Puppet Forge Puppet Forge - downloads Puppet Forge - endorsement Puppet Forge - scores Yard Docs AGPL v3 License

Table of Contents


Overview

This module manages the ferm firewalling software. It allows you to configure the actual software, but also all related rules.

What happened to older releases?

You maybe wonder what happend to release 1.1.0 and 1.0.0. We had to take them down because they contained sensitive information.

Setup

This is very easy:

include ferm

This will install the package, but nothing more. It won't explicitly enable it or write any rules. Be careful here: The default Debian package enabled autostart for the service and only allows incoming SSH/IPSec connections.

It is also possible to install ferm from sources:

class {'ferm':
  install_method = 'vcsrepo',
}

When install_method is vcsrepo, the git binary is required, this module should handle Git installation.

When install_method is vcsrepo with vcstag >= v2.5 ferm call "legacy" xtables tools because nft based tools are incompatible.

You can easily define rules in Puppet (they don't need to be exported resources):

  @@ferm::rule{"allow_kafka_server2server-${trusted['certname']}":
    chain  => 'INPUT',
    action => 'ACCEPT',
    proto  => 'tcp',
    dport  => [9092, 9093],
    saddr  => "(${facts['networking']['ip6']}/128 ${facts['networking']['ip']}/32)",
    tag    => 'allow_kafka_server2server',
  }

You can collect them like this:

# collect all exported resources with the tag allow_vault_server2server
Ferm::Rule <<| tag == 'allow_kafka_server2server' |>>

You can also define rules in Hiera. Make sure to use alias() as interpolation function, because hiera() will always return a string.

---
subnet01: '123.123.123.0/24'
subnet02: '123.123.124.0/24'
subnet03:
 - '123.123.125.0/24'
 - '123.123.126.0/24'

subnets:
  - "%{alias('subnet01')}"
  - "%{alias('subnet02')}"
  - "%{alias('subnet03')}"
  - 123.123.127.0/24

ferm::rules:
  'allow_http_https':
    chain: 'INPUT'
    action: 'ACCEPT'
    proto: 'tcp'
    dport:
      - 80
      - 443
    saddr: "%{alias('subnets')}"

ferm::rules is a hash. configured for deep merge. Hiera will collect all defined hashes and hand them over to the class. The main class will create rules for all of them. It also collects all exported resources that are tagged with the FQDN of a box.

It's also possible to match against ipsets. This allows to easily match against a huge amount of IP addresses or network ranges. You can use this as follows:

ferm::ipset { 'INPUT':
  sets => {
   'office'   => 'ACCPET',
   'internet' => 'DROP',
  }
}

please see the references section for more examples.

Examples

disable conntrack for all non-local destinations (e.g. for hypervisors)

General best practices for firewalling recommend that you use explicit whitelisting. Usually this boils down to configuring your firewall in a stateful manner, i.e. allowing ESTABLISHED and RELATED connections in addition to some whitelisted ports (i.e. TCP/22 for SSHD, likely limited to certain source addresses). For this to work you need connection tracking, provided by the nf_conntrack kernel module and configurable via the iptables conntrack module. However, especially in virtualization environments, you do not want to track every connection being routed through the hypervisor. You only want to track connections directly addressed to the hypervisor itself, i.e. traffic ending up in the filter/INPUT chain, but not traffic that is later going through filter/FORWARD to guest systems. Unfortunately the ferm tool does not allow negating lists (i.e. @ipfilter()) and thus we cannot easily negate saddr or daddr params, which forces us to configure two rules instead of one.

Connection tracking can only be controlled in the PREROUTING chain of the raw table.

ferm::rules:
  'allow_conntrack_local':
    chain: 'PREROUTING'
    table: 'raw'
    proto: 'all'
    daddr:
      - "%{facts.ipaddress}"
      - "%{facts.ipaddress6}"
    action: 'RETURN'
  'disable_conntrack_nonlocal':
    chain: 'PREROUTING'
    table: 'raw'
    proto: 'all'
    action: 'NOTRACK'
    interface: "%{facts.networking.primary}"

The upper RETURN rule will stop evaluating further rules in the PREROUTING chain of the raw table if the traffic is addressed directly to the current node applying the catalogue. The second rule will disable connection tracking for all other traffic coming in over the primary network interface, that is not addressed directly to the current node, i.e. guest systems hosted on it.

This will prevent your conntrack table from overflowing, tracking only the relevant connections and allowing you to use a stateful ruleset.

create a custom chain, e.g. for managing custom FORWARD chain rule for OpenVPN using custom ferm DSL.

$my_rules = @(EOT)
chain OPENVPN_FORWORD_RULES {
  proto udp {
    interface tun0 {
      outerface enp4s0 {
        mod conntrack ctstate (NEW) saddr @ipfilter((10.8.0.0/24)) ACCEPT;
      }
    }
  }
}
| EOT

ferm::chain{'OPENVPN_FORWORD_RULES':
  chain   => 'OPENVPN_FORWORD_RULES',
  content => $my_rules,
}

ferm::rule { "OpenVPN - FORWORD all udp traffic from network 10.8.0.0/24 to subchain OPENVPN_FORWORD_RULES":
  chain     => 'FORWARD',
  action    => 'OPENVPN_FORWORD_RULES',
  saddr     => '10.8.0.0/24',
  proto     => 'udp',
}

Reference

All parameters are documented within the classes. We generate markdown documentation. It's available in the REFERENCE.md. It also contains many examples.

Development

This project contains tests for rspec-puppet.

Quickstart to run all linter and unit tests:

bundle install --path .vendor/ --without system_tests --without development --without release
bundle exec rake test

For more details about the development workflow and on how to contribute, please check the CONTRIBUTING.md.

Authors

puppet-ferm is maintained by Vox Pupuli, it was written by Tim 'bastelfreak' Meusel.

puppet-ferm's People

Contributors

alexjfisher avatar bastelfreak avatar dan33l avatar dhollinger avatar dhoppe avatar ekohl avatar foxxx0 avatar ghoneycutt avatar jhoblitt avatar kbite avatar kengelhardt-godaddy avatar llowder avatar rehanone avatar sandra-thieme avatar smortex avatar tboedecker-godaddy avatar themeier avatar tragiccode avatar trevor-vaughan avatar zilchms avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

puppet-ferm's Issues

idempotency issue with CentOS6 since module version 2.2.0

Affected Puppet, Ruby, OS and module versions/distributions

  • Puppet: any
  • Ruby:
  • Distribution: CentOS6
  • Module version: 2.4.0

How to reproduce (e.g Puppet code you use)

The init script added in module for CentOS6 does not provide status options.
This produce idem-potency issue.

What are you seeing

Applying with debug we can see :

Debug: Executing: '/sbin/service ferm status'
Debug: Executing: '/sbin/chkconfig ferm'
Debug: Executing: '/sbin/service ferm start'
Debug: Executing: '/sbin/chkconfig ferm'
Notice: /Stage[main]/Ferm::Service/Service[ferm]/ensure: ensure changed 'stopped' to 'running'

The command /sbin/service ferm status return 1 and show usage message.
Each run Puppet tries to start ferm.

What behaviour did you expect instead

To be idempotent

Output log

Any additional information you'd like to impart

unable to configure Debian OSes

Affected Puppet, Ruby, OS and module versions/distributions

  • Puppet:
  • Ruby:
  • Distribution: Debian
  • Module version: 2.4.0

How to reproduce (e.g Puppet code you use)

    class { 'ferm':
      manage_service    => true,
      manage_configfile => true,
      manage_initfile   => false,
      forward_policy    => 'DROP',
      output_policy     => 'DROP',
      input_policy      => 'DROP',
      rules             => {
        'allow acceptance_test' => {
          chain  => 'INPUT',
          policy => 'ACCEPT',
          proto  => tcp,
          dport  => 22,
        },
      },
      ip_versions      => ['ip'],
    }

What are you seeing

On the SUT:

root@debian9-64-1:/# iptables-save 
# Generated by iptables-save v1.6.0 on Fri Sep  6 17:30:15 2019
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
# Completed on Fri Sep  6 17:30:15 2019
# Generated by iptables-save v1.6.0 on Fri Sep  6 17:30:15 2019
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state INVALID -j DROP
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -p udp -m udp --dport 500 -j ACCEPT
-A INPUT -p esp -j ACCEPT
-A INPUT -p ah -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A FORWARD -m state --state INVALID -j DROP
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Fri Sep  6 17:30:15 2019

What behaviour did you expect instead

root@debian9-64-1:/# iptables-save 
# Generated by iptables-save v1.6.0 on Fri Sep  6 17:33:42 2019
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
# Completed on Fri Sep  6 17:33:42 2019
# Generated by iptables-save v1.6.0 on Fri Sep  6 17:33:42 2019
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state INVALID -j DROP
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m comment --comment "allow acceptance_test" -m tcp --dport 22 -j ACCEPT
-A FORWARD -m state --state INVALID -j DROP
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -m state --state INVALID -j DROP
-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Fri Sep  6 17:33:42 2019

Output log

puppet apply --verbose --detailed-exitcodes /tmp/apply_manifest.pp.D6dyW0
  Info: Loading facts
  Warning: You cannot collect exported resources without storeconfigs being set; the collection will be ignored (file: /etc/puppetlabs/code/modules/ferm/manifests/init.pp, line: 104, column: 3)
  Notice: Compiled catalog for debian9-64-1 in environment production in 0.10 seconds
  Info: Applying configuration version '1567790588'
  Notice: /Stage[main]/Ferm::Install/Package[ferm]/ensure: created
  Notice: /Stage[main]/Ferm::Config/File[/etc/ferm.d]/ensure: created
  Notice: /Stage[main]/Ferm::Config/File[/etc/ferm.d/definitions]/ensure: created
  Notice: /Stage[main]/Ferm::Config/File[/etc/ferm.d/chains]/ensure: created
  Notice: /Stage[main]/Ferm::Config/Concat[/etc/ferm.conf]/File[/etc/ferm.conf]/ensure: defined content as '{md5}4066bf8cca26e371993c01cdef8d83c3'
  Notice: /Stage[main]/Ferm::Config/Ferm::Chain[INPUT]/Concat[/etc/ferm.d/chains/INPUT.conf]/File[/etc/ferm.d/chains/INPUT.conf]/ensure: defined content as '{md5}eaac2cbbe7ff78937ffa8742a0b22f04'
  Notice: /Stage[main]/Ferm::Config/Ferm::Chain[FORWARD]/Concat[/etc/ferm.d/chains/FORWARD.conf]/File[/etc/ferm.d/chains/FORWARD.conf]/ensure: defined content as '{md5}bab850d841c85b3487631604d9b3cdf0'
  Notice: /Stage[main]/Ferm::Config/Ferm::Chain[OUTPUT]/Concat[/etc/ferm.d/chains/OUTPUT.conf]/File[/etc/ferm.d/chains/OUTPUT.conf]/ensure: defined content as '{md5}bab850d841c85b3487631604d9b3cdf0'
  Info: Class[Ferm::Config]: Scheduling refresh of Class[Ferm::Service]
  Info: Class[Ferm::Service]: Scheduling refresh of Service[ferm]
  Notice: /Stage[main]/Ferm::Service/Service[ferm]: Triggered 'refresh' from 1 event
  Info: Creating state file /opt/puppetlabs/puppet/cache/state/state.yaml
  Notice: Applied catalog in 4.72 seconds

Any additional information you'd like to impart

PR #59

Interface matching is broken.

It seems interface matching is broken in some cases

take for instance

ferm::rules:
'WG-TEMP':
   interface: 'wg99'
   chain: 'INPUT'
   policy: 'ACCEPT'
   proto: 'tcp'
   dport: '1000'

the generated output is expected to be

interface wg99 {
  mod comment comment 'WG-TEMP' proto tcp dport 1000 ACCEPT;
}

What instead is being generated

  mod comment comment 'WG-TEMP' proto tcp dport 1000 ACCEPT;
interface wg99 {
}

I thought it might have been something I'd done trying to implement outerface so I reverted back to the release version but still the same.

Please support JUMP.

As Title, it looks like you can define custom chains, but I don't see any option to configure the criteria/Jump from the default chain to the custom one.

e.g

ferm::rules:
'jump_trusted':
chain: 'INPUT'
policy: 'JUMP'
saddr: "%{alias('Trusted')}"
jumpto: 'Trusted-Hosts'
'trusted_ssh':
chain: 'Trusted-Hosts'
policy: 'ACCEPT'
proto: 'tcp'
dport: '22'

outerface?

Is outerface supported by the module?, I did try using it in the rule but it didn't seem to like it.

outerface does occasionally come in handy for forward rules where you want to match the outgoing interface either instead of or as well as the incoming one.

Make usage of conntrack optional

In situations with a lot of containers or virtual machines you might like to disable conntrack. I'd suggest making usage of conntrack optional to cover this use case.

ferm fails to apply changed/new rules on Ubuntu 16.04

After the initial start of ferm, it caches the rules to /var/cache/ferm. After deploying new rules or updating existing ones, the ferm script is restarted. It reapplies the cached rules and ignores the current ones.

DNAT/SNAT?

I might just be missing it, but how do you use the DNAT/SNAT functions as I don't see the paramater to set the DNAT/SNAT Target for the translated packet

Unrecognized keyword: @preserve with ubuntu1604

Affected Puppet, Ruby, OS and module versions/distributions

  • Puppet: Any
  • Ruby:
  • Distribution: Ubuntu1604
  • Module version:

How to reproduce (e.g Puppet code you use)

use preserve_chains_in_tables

What are you seeing

Impossible to use preserve_chains_in_tables , what logs display:

 systemd[1]: Stopping ferm firewall configuration...
 ferm[7903]:  * Stopping Firewall ferm
 ferm[7903]: Error in /etc/ferm/ferm.conf line 9:
 ferm[7903]:     ip ip6
 ferm[7903]: )
 ferm[7903]: table nat
 ferm[7903]: {
 ferm[7903]:     chain DOCKER @preserve <--
 ferm[7903]: Unrecognized keyword: @preserve
 systemd[1]: ferm.service: Control process exited, code=exited status=255
 systemd[1]: Stopped ferm firewall configuration.
 systemd[1]: ferm.service: Unit entered failed state.
 systemd[1]: ferm.service: Failed with result 'exit-code'.

What behaviour did you expect instead

Output log

Any additional information you'd like to impart

The ferm version shipped with Ubuntu1604 is 2.2 and does not know @preserve.

Including 'ferm' with default values at Debian servers overwrites firewall rules

Affected Puppet, Ruby, OS and module versions/distributions

  • Puppet: Puppet 6
  • Ruby: bundled
  • Distribution: Debian 10
  • Module version: v2.6.0

How to reproduce (e.g Puppet code you use)

Include ferm without any other parameter to a Debian 10 server

include ferm

What are you seeing

After installation of ferm these firewall rules are active instead of whatever it was before:

root@debian10:~# iptables -vnL
Chain INPUT (policy DROP 12 packets, 720 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            state INVALID
  115 20310 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
    5   300 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:500
    0     0 ACCEPT     esp  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     ah   --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            state INVALID
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED

Chain OUTPUT (policy ACCEPT 8 packets, 506 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  101  390K ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED

Bonus: when stopping and disabling ferm, it wipes the firewall rules again:

root@debian10:~# systemctl stop ferm; systemctl disable ferm
Synchronizing state of ferm.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable ferm
insserv: warning: script 'S03firewall' missing LSB tags and overrides
insserv: warning: script 'firewall' missing LSB tags and overrides
insserv: warning: script 'S03firewall' missing LSB tags and overrides
insserv: warning: current start runlevel(s) (empty) of script `ferm' overrides LSB defaults (S).
insserv: warning: current stop runlevel(s) (S) of script `ferm' overrides LSB defaults (empty).
insserv: warning: script 'firewall' missing LSB tags and overrides

root@debian10:~# iptables -vnL
Chain INPUT (policy ACCEPT 805 packets, 363K bytes)
 pkts bytes target     prot opt in     out     source               destination         
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
Chain OUTPUT (policy ACCEPT 747 packets, 110K bytes)
 pkts bytes target     prot opt in     out     source               destination  

What behaviour did you expect instead

No change to existing firewall / iptables rules

Any additional information you'd like to impart

Might be due to the Debian package of 'ferm' as 'vendor preset' is 'enabled'.

โ— ferm.service - ferm firewall configuration
   Loaded: loaded (/lib/systemd/system/ferm.service; enabled; vendor preset: enabled)
   Active: active (exited) since Wed 2020-04-08 21:23:26 CEST; 5min ago
  Process: 3461 ExecStart=/etc/init.d/ferm start (code=exited, status=0/SUCCESS)
 Main PID: 3461 (code=exited, status=0/SUCCESS)
    Tasks: 0 (limit: 4915)
   CGroup: /system.slice/ferm.service

feature: include custom ferm files?

It would be nice if it's possible to define an include which would then look for a file on the puppet master and copy it to the client allowing for writing of rules in native ferm script and including them in the rulebase at the location of the include.

This would probably be better for handling complex rulesets requiring less used functions of ferm rather than having to try and include every possible option in the module itself.

I did this in a bit of a hacky way for a fairly large existing rulebase that was originally written in ferm language. Since this was on a Gateway device I was using outerface and various NAT translations.

In that instance I turned off the management of the Ferm config file and then wrote my own includes into the existing ferm config to also include the INPUT and FORWARD rules generated by he module.

This isn't clean as It does mean I have a load of ferm files that are generated by the puppet module that are simply ignored on that particular machine

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.