The problem with using Docker and managing your firewall with Puppet is that you have two competing tools trying to manage the rules in the firewall. The puppetlabs-firewall module allows you purge all unmanaged firewall chains and rules, and if configured to do so, puppet will purge the rules added by Docker.

This is how you purge all unmanaged rules:

resources { 'firewall':
  purge => true,
}

A feature added in puppetlabs-firewall 1.3 provides a method for allowing Puppet to selectively purge unmanaged firewall rules within a particular chain. A firewallchain parameter named ignore accepts regular expressions that are to be matched against firewall rules within that chain that are to be ignored when purging.

When the docker service is started it add iptables rules like this:

-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT

To configure puppetlabs-firewall to ignore the docker rules when purging you can configure your firewallchain to ignore rules containing "-o docker0" and "-i docker0". It is important to note that you cannot purge all firewall resources as shown above and make use of the ignore parameter; the implications of this are that you lose the ability to purge unmanaged firewallchains and you must define a firewallchain for each chain from which you wish to have puppet purge rules.

firewallchain { 'FORWARD:filter:IPv4':
  ensure => present,
  purge  => true,
  ignore => [
    '-o docker0',
    '-i docker0',
  ],
}

For my projects I have created wrapper module around puppetlabs-firewall that creates a firewallchain for INPUT, OUTPUT, and FORWARD and configures each of them to purge all rules except for those containing docker0. I am not creating any NAT rules outside of docker so I have chosen to not manage any of the chains within the NAT table using Puppet.