For this to work, you need Volcane's extlookup function:

require 'csv'

module Puppet::Parser::Functions
newfunction(:extlookup, :type => :rvalue) do |args|
key = args[0]
default = "_ExtUNSET_"
datafile = "_ExtUNSET_"

default = args[1] if args[1]
datafile = args[2] if args[2]

extlookup_datadir = lookupvar('extlookup_datadir')
extlookup_precedence = Array.new

# precedence values can have variables embedded in them
# in the form %{fqdn}, you could for example do
#
# $extlookup_precedence = ["hosts/%{fqdn}", "common"]
#
# this will result in /path/to/extdata/hosts/your.box.com.csv
# being searched.
#
# we parse the precedence here because the best place to specify
# it would be in site.pp but site.pp is only evaluated at startup
# so $fqdn etc would have no meaning there, this way it gets evaluated
# each run and has access to the right variables for that run
lookupvar('extlookup_precedence').each do |prec|
while prec =~ /%\{(.+?)\}/
prec.gsub!(/%\{#{$1}\}/, lookupvar($1))
end

extlookup_precedence << prec
end


datafiles = Array.new

# if we got a custom data file, put it first in the array of search files
if datafile != ""
if File.exists?(extlookup_datadir + "/#{datafile}.csv")
datafiles << extlookup_datadir + "/#{datafile}.csv"
end
end

extlookup_precedence.each do |d|
datafiles << extlookup_datadir + "/#{d}.csv"
end

desired = "_ExtUNSET_"

datafiles.each do |file|
parser.watch_file(file) if File.exists?(file)

if desired == "_ExtUNSET_"
if File.exists?(file)
result = CSV.read(file).find_all do |r|
r[0] == key
end


# return just the single result if theres just one,
# else take all the fields in the csv and build an array
if result.length > 0
if result[0].length == 2
val = result[0][1].to_s

# parse %{}'s in the CSV into local variables using lookupvar()
while val =~ /%\{(.+?)\}/
val.gsub!(/%\{#{$1}\}/, lookupvar($1))
end

desired = val
elsif result[0].length > 1
length = result[0].length
cells = result[0][1,length]

# Individual cells in a CSV result are a weird data type and throws
# puppets yaml parsing, so just map it all to plain old strings
desired = cells.map do |c|
c.to_s

# parse %{}'s in the CSV into local variables using lookupvar()
while c =~ /%\{(.+?)\}/
c.gsub!(/%\{#{$1}\}/, lookupvar($1))
end

c
end
end
end
end
end
end

# don't accidently return nil's and such rather throw a parse error
if desired == "_ExtUNSET_" && default == "_ExtUNSET_"
raise Puppet::ParseError, "No match found for '#{key}' in any data file during extlookup()"
else
desired = default if desired == "_ExtUNSET_"
end

desired
end
end



This is so you can look up trustednets and nodenets based on a location/domain/hostname basis via csv files. Extremely useful and should be in mainline puppet IMO. Ask in channel for more info on this piece.

iptables piece:

class iptables {
$nodenets = extlookup("nodenets")
$trustednets = extlookup("trustednets")
$puppetserver = extlookup("puppetserver")

package { "iptables": ensure => "present" }

exec { "/sbin/iptables-restore < /etc/iptables.rules":
require => [ File["/etc/iptables.rules"], Package["iptables"] ]
}

file { "/etc/iptables.rules":
content => template("iptables/iptables.rules.$domain.erb"),
ensure => "present",
group => "root",
mode => "440",
owner => "root",
require => Class["common::location"],
}

}


template for iptables.rules (this is a really anal firewall for boxes that sit on the edge). You will need .24.8 for the has_variable? function:

*filter

# Default DROP on input, default allow on out.
-P INPUT DROP
-P OUTPUT ACCEPT
-P FORWARD DROP

# Allow localhost in, and lo iface
-A INPUT -s 127.0.0.1 -j ACCEPT
-A INPUT -i lo -j ACCEPT

# Allow established and related in
-A INPUT -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT

# Drop ICMP Info Leakage
-A INPUT -p icmp -m icmp --icmp-type 13 -j DROP

# Allow ping reply back in
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT

# Make sure NEW connections have SYN set
-A INPUT -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "IPT NEW W/O SYN: "
-A INPUT -p tcp ! --syn -m state --state NEW -j DROP

# Log and Drop christmas tree packets
-A INPUT -p tcp --tcp-flags ALL ALL -j LOG --log-prefix "IPT XMAS TREE PKT: "
-A INPUT -p tcp --tcp-flags ALL ALL -j DROP

# Log and Drop NULL packets
-A INPUT -p tcp --tcp-flags ALL NONE -j LOG --log-prefix "IPT NULL PKT: "
-A INPUT -p tcp --tcp-flags ALL NONE -j DROP

# Log and drop all other non-specific malformed tcp packets
-A INPUT -p tcp --tcp-flags ACK,FIN FIN -j LOG --log-prefix "IPT BAD TCP FLAGS: "
-A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP
-A INPUT -p tcp --tcp-flags ACK,PSH PSH -j LOG --log-prefix "IPT BAD TCP FLAGS: "
-A INPUT -p tcp --tcp-flags ACK,PSH PSH -j DROP
-A INPUT -p tcp --tcp-flags ACK,URG URG -j LOG --log-prefix "IPT BAD TCP FLAGS: "
-A INPUT -p tcp --tcp-flags ACK,URG URG -j DROP
-A INPUT -p tcp --tcp-flags FIN,RST FIN,RST -j LOG --log-prefix "IPT BAD TCP FLAGS: "
-A INPUT -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
-A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j LOG --log-prefix "IPT BAD TCP FLAGS: "
-A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
-A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j LOG --log-prefix "IPT BAD TCP FLAGS: "
-A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
-A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j LOG --log-prefix "IPT BAD TCP FLAGS: "
-A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
-A INPUT -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j LOG --log-prefix "IPT BAD TCP FLAGS: "
-A INPUT -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
-A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j LOG --log-prefix "IPT BAD TCP FLAGS: "
-A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

# Log and drop IP Fragments to prevent fragmentation attack
-A INPUT -f -j LOG --log-prefix "IPT FRAGMENTS: "
-A INPUT -f -j DROP

<% if has_variable? "open_tcp_ports" and !open_tcp_ports.empty? -%>
# These ports can be accessed via anyone
-A INPUT -p tcp -m multiport --dports <%= open_tcp_ports %> -j ACCEPT
<% end -%>
<% if has_variable? "open_udp_ports" and !open_udp_ports.empty? -%>
# These ports can be accessed via anyone
-A INPUT -p udp -m multiport --dports <%= open_udp_ports %> -j ACCEPT
<% end -%>
<% if (has_variable? "restricted_tcp_ports" and !restricted_tcp_ports.empty?) and (trustednets and ![ trustednets ].flatten.empty?) -%>
# These ports can only be accessed via trusted nets
<% [ trustednets ].flatten.each do |network| -%>
-A INPUT -s <%= network %> -p tcp -m multiport --dports <%= restricted_tcp_ports %> -j ACCEPT
<% end -%>
<% end -%>
<% if (has_variable? "restricted_udp_ports" and !restricted_udp_ports.empty?) and (trustednets and ![ trustednets ].flatten.empty?) -%>
# These ports can only be accessed via trusted nets
<% [ trustednets ].flatten.each do |network| -%>
-A INPUT -s <%= network %> -p udp -m multiport --dports <%= restricted_udp_ports %> -j ACCEPT
<% end -%>
<% end -%>
<% if (has_variable? "restricted_to_node_nets_tcp_ports" and !restricted_to_node_nets_tcp_ports.empty?) and (nodenets and ![ nodenets ].flatten.empty?) -%>
# These ports can only be accessed via local net clients
<% [ nodenets ].flatten.each do |network| -%>
-A INPUT -s <%= network %> -p tcp -m multiport --dports <%= restricted_to_node_nets_tcp_ports %> -j ACCEPT
<% end -%>
<% end -%>
<% if (has_variable? "restricted_to_node_nets_udp_ports" and !restricted_to_node_nets_udp_ports.empty?) and (nodenets and ![ nodenets ].flatten.empty?) -%>
# These ports can only be accessed via local net clients
<% [ nodenets ].flatten.each do |network| -%>
-A INPUT -s <%= network %> -p udp -m multiport --dports <%= restricted_to_node_nets_udp_ports %> -j ACCEPT
<% end -%>
<% end -%>
# Allow puppetrunner
-A INPUT -s <%= puppetserver %> -p tcp -m tcp --dport 8139 -m comment --comment "Allow for puppetrunner" -j ACCEPT

# Log and Drop invalid states
-A INPUT -m state --state INVALID -j LOG --log-prefix "IPT INVALID STATE: "
-A INPUT -m state --state INVALID -j DROP

COMMIT

Sample node def:

node 'tomcat001' {
$open_tcp_ports = "443"
$restricted_tcp_ports = "22,80,8009,8180"

include basenode_tmpl
}

basenode_tmpl is just a class that includes a bunch of stuff that should be on all nodes.