Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
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.
This paste will be private.
From the Design Piracy series on my blog: