A Chef Definition for Managing Iptables Rules

May 26, 2010

I wrote a Chef definition for managing Iptables rules a while back, but until now, it has only existed publicly as gist on github. I figured I’d post it here as an example of how to write your own Chef definitions.

The first thing I did was create an iptables cookbook with a default recipe that simply ensures that the iptables package is installed:

                      package "iptables" do
                        package_name "iptables"
                      end
                      

Next, I used the definitions documentation on the Opscode wiki to write the actual definition. What I’m basically doing here is accepting a few Iptables-specific parameters (table, chain, options) and dynamically building the execute resources to run the appropriate Iptables commands:

                      define :iptables_rule, :action => :create, :table => "filter", :chain => nil, :options => nil do
                      
                        include_recipe "iptables"
                      
                        if params[:table].empty?
                          raise ArgumentError, "Missing required argument: table"
                        end
                        if params[:chain].nil? or params[:chain].empty?
                          raise ArgumentError, "Missing required argument: chain"
                        end
                        if params[:options].nil? or params[:options].empty?
                          raise ArgumentError, "Missing required argument: options"
                        end
                      
                        iptables_bin = "/sbin/iptables"
                        rule_id = "Chef Rule: #{params[:name]}"
                        comment = "-m comment --comment \"#{rule_id}\""
                      
                        if params[:action] == :delete
                          execute "delete_iptables_rule-#{params[:name]}" do
                            command "#{iptables_bin} --table #{params[:table]} -D #{params[:chain]} #{params[:options]} #{comment}"
                            only_if "#{iptables_bin} --table #{params[:table]} -S #{params[:chain]} | /bin/grep \"#{rule_id}\""
                          end
                        else
                          execute "create_iptables_rule-#{params[:name]}" do
                            command "#{iptables_bin} --table #{params[:table]} -A #{params[:chain]} #{params[:options]} #{comment}"
                            not_if "#{iptables_bin} --table #{params[:table]} -S #{params[:chain]} | /bin/grep \"#{rule_id}\""
                          end
                        end
                      end
                      

So now when I want to manage an Iptables rule with chef, I can just do something like this:

                      iptables_rule "jetty_port_80" do
                        table "nat"
                        chain "PREROUTING"
                        options "--proto tcp --dport 80 --jump REDIRECT --to-port 8080"
                      end
                      
blog comments powered by Disqus