Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ript: making Linux firewall change management resilient

Ript: making Linux firewall change management resilient

Netfilter is an extremely powerful framework for manipulating packets, but does anyone enjoy using iptables? Tools for managing small rulesets have a steep learning curve, and most tools don't take availablity into account when managing large rulesets.

Enter Ript, a clean and opinionated Domain Specific Language for describing firewall rules, and a tool that implements database migrations-like functionality for applying these rules with zero downtime.

At Ript's core is an easy to use Ruby DSL for describing both simple and complex sets of iptables firewall rules, with helpers for all the common use cases: accepting, dropping, & rejecting packets, as well as for performing DNAT and SNAT.

Ript provides a method to group common sets of rules together called "partitions", which are used at rule application time to perform zero-downtime migrations.

In this talk Lindsay Holmwood takes you on a whirlwind tour of the DSL, explaining how Ript utilises iptables features to work its magic, and providing some concrete examples of how Ript can help increase the reliability of the services you deliver.

Lindsay Holmwood

January 30, 2013
Tweet

More Decks by Lindsay Holmwood

Other Decks in Technology

Transcript

  1. Hi!

  2. partition "movember" do interface :default => "vlan666" address :iemedia, :address

    => "192.168.55.70/27", :interface => "vlan99" address "www.movember.com", :address => "117.53.174.95", :interface => "vlan44" address "movember subnet", :address => "117.53.174.0/27", :interface => "vlan44" address "mo2010prod-dvmh-web-01", :address => "10.0.21.2" address "mo2010prod-dvmh-proxy-01", :address => "10.0.21.3" address "mo2010prod-dvmh-app-01", :address => "10.0.21.4" address "mo2010prod subnet", :address => "10.0.21.0/27" address "mo2010prod-dvmh-ipv-06", :address => "00:00:de:ca:fe:c0:ff:33" address "dickhead", :address => "127.0.0.1" # ...
  3. # ... reject "dickhead on www.movember.com" do from "dickhead" to

    "www.movember.com" end log "dickhead on www.movember.com" do from "dickhead" to "www.movember.com" end # dnat forward "movember.com public website" do ports 80, 443 dnat "www.movember.com" => "mo2010prod-dvmh-web-01" end # snat forward "movember" do to :anywhere snat "mo2010prod subnet" => "www.movember.com" end # nonat forward "ipv6 forward" do ports 80, 443 from :anywhere nonat "mo2010prod-dvmh-ipv-06" end end
  4. Now in use by: Whirlpool, One Big Switch, Tourism Victoria,

    Network TEN, Movember, Quicksilver, IMAX, Bookworld, ABC, SBS
  5. partition "joeblogsco" do end partition "joeblogsco" do label "www.joeblogsco.com", :address

    => "172.19.56.216" label "api.joeblogsco.com", :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" end
  6. partition "joeblogsco" do end partition "joeblogsco" do label "www.joeblogsco.com", :address

    => "172.19.56.216" label "api.joeblogsco.com", :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" end key
  7. partition "joeblogsco" do end partition "joeblogsco" do label "www.joeblogsco.com", :address

    => "172.19.56.216" label "api.joeblogsco.com", :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" end key data
  8. # joeblogsco.rb partition "joeblogsco" do label "app-01", :address => "192.168.5.230"

    end # foobar.rb partition "foobar" do label "app-01", :address => "192.168.78.3" end
  9. # joeblogsco.rb partition "joeblogsco" do label "app-01", :address => "192.168.5.230"

    end # foobar.rb partition "foobar" do label "app-01", :address => "192.168.78.3" end no conflicts
  10. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" end
  11. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end end
  12. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end end comment
  13. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end end comment arguments
  14. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end rewrite "public ssh access" do ports 22 dnat "www.joeblogsco.com" => "app-01" end end
  15. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end end
  16. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end end need an accept
  17. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end end
  18. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end accept "allow public ssh access" do protocols "tcp" ports 22 to "www.joeblogsco.com" end end
  19. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end end
  20. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end accept "allow public ssh access" do protocols "tcp" ports 22 to "www.joeblogsco.com" end end
  21. DRY

  22. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end rewrite "public ssh access" do ports 22 dnat "www.joeblogsco.com" => "app-01" end end
  23. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website + ssh access" do ports 80, 22 dnat "www.joeblogsco.com" => "app-01" end end
  24. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end rewrite "trusted ssh access" do ports 22 dnat "www.joeblogsco.com" => "app-01" end end
  25. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "api.joeblogsco.com",

    :address => "172.19.56.217" label "joeblogsco subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" label "trusted office", :address => "172.20.4.124" rewrite "public website" do ports 80 dnat "www.joeblogsco.com" => "app-01" end rewrite "trusted ssh access" do ports 22 from "trusted office" dnat "www.joeblogsco.com" => "app-01" end end
  26. rewrite "public mail" do ports 25, 993 dnat "www.joeblogsco.com" =>

    "app-01" end rewrite "trusted private services" do from "trusted office" ports 6000..8000 dnat "www.joeblogsco.com" => "app-01" end
  27. rewrite "public mail" do ports 25, 993 dnat "www.joeblogsco.com" =>

    "app-01" end rewrite "trusted private services" do from "trusted office" ports 6000..8000 dnat "www.joeblogsco.com" => "app-01" end rewrite "public website" do ports 80 => 8080 dnat "www.joeblogsco.com" => "app-01" end
  28. rewrite "public mail" do ports 25, 993 dnat "www.joeblogsco.com" =>

    "app-01" end rewrite "trusted private services" do from "trusted office" ports 6000..8000 dnat "www.joeblogsco.com" => "app-01" end rewrite "public website" do ports 80 => 8080 dnat "www.joeblogsco.com" => "app-01" end rewrite "api services" do ports 80, 8000..8900, 2222 => 22 dnat "api.joeblogsco.com" => "app-02" end
  29. rewrite "public mail" do ports 25, 993 dnat "www.joeblogsco.com" =>

    "app-01" end rewrite "trusted private services" do from "trusted office" ports 6000..8000 dnat "www.joeblogsco.com" => "app-01" end rewrite "public website" do ports 80 => 8080 dnat "www.joeblogsco.com" => "app-01" end rewrite "api services" do ports 80, 8000..8900, 2222 => 22 dnat "api.joeblogsco.com" => "app-02" end mappings must be last
  30. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "joeblogsco

    subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" rewrite "private to public" do snat "joeblogsco subnet" => "www.joeblogsco.com" end end
  31. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "joeblogsco

    subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" label "bad guy", :address => "172.19.110.247" rewrite "public website + ssh access" do ports 80, 22 dnat "www.joeblogsco.com" => "app-01" end drop "bad guy" do from "bad guy" to "www.joeblogsco.com" end end
  32. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "joeblogsco

    subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" label "bad guys", :address => "172.19.110.0/8" rewrite "public website + ssh access" do ports 80, 22 dnat "www.joeblogsco.com" => "app-01" end drop "bad guys" do protocols "udp" from "bad guys" to "www.joeblogsco.com" end end
  33. partition "joeblogsco" do label "www.joeblogsco.com", :address => "172.19.56.216" label "joeblogsco

    subnet", :address => "192.168.5.224/27" label "app-01", :address => "192.168.5.230" label "bad guys", :address => "172.19.110.0/8" rewrite "public website + ssh access", :log => true do ports 80, 22 dnat "www.joeblogsco.com" => "app-01" end drop "bad guys", :log => true do protocols "udp" from "bad guys" to "www.joeblogsco.com" end end
  34. partition "joeblogsco" do label "joeblogsco uat subnet", :address => "192.168.5.0/24"

    label "joeblogsco stage subnet", :address => "10.60.2.0/24" label "joeblogsco prod subnet", :address => "10.60.3.0/24" label "www.joeblogsco.com", :address => "172.19.56.216" rewrite "private to public" do snat [ "joeblogsco uat subnet", "joeblogsco stage subnet", "joeblogsco prod subnet" ] => "www.joeblogsco.com" end end
  35. accept "fruits of the forest" do protocols "tcp" ports 22

    from %w(apple blueberry cranberry eggplant fennel grapefruit) to %w(apple blueberry cranberry eggplant fennel grapefruit) end
  36. Migrations can manage the evolution of a schema used by

    several physical databases. It’s a solution to the common problem of adding a field to make a new feature work in your local database, but being unsure of how to push that change to other developers and to the production server. With migrations, you can describe the transformations in self-contained classes that can be checked into version control systems and execute against another database that might be one, two, or five versions behind. -- http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
  37. Migrations can manage the evolution of a schema used by

    several physical databases. It’s a solution to the common problem of adding a field to make a new feature work in your local database, but being unsure of how to push that change to other developers and to the production server. With migrations, you can describe the transformations in self-contained classes that can be checked into version control systems and execute against another database that might be one, two, or five versions behind. -- http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
  38. class AddSsl < ActiveRecord::Migration def up add_column :accounts, :ssl_enabled, :boolean

    end def down remove_column :accounts, :ssl_enabled end end
  39. Sequel.migration do up do create_table(:artists) do primary_key :id String :name,

    :null => false end end down do drop_table(:artists) end end
  40. ➔ ls -1 db/migrations/ | head -n 20 001_initialize.rb 002_add_test_column.rb

    003_2012Iteration2.rb 004_2012Iteration3.rb 005_2012Iteration4.rb 006_2012Iteration5.rb 007_2012Iteration6.rb 008_2012Iteration7.rb 009_2012Iteration8.rb 010_2012Iteration8.rb 011_2012Gateways.rb 012_2012Iteration8FAQ.rb 013_2012NetworkUpdates.rb 014_2012DonationDenmark.rb
  41. bwired-a67edce accept 117.53.168.72:80 ... bwired-ac12dce accept 117.53.167.72:22 ... no match,

    returns to partition-a same destination, jumps into old chain
  42. bwired-a67edce accept 117.53.168.72:80 ... bwired-ac12dce accept 117.53.167.72:22 ... no match,

    returns to partition-a same destination, jumps into old chain
  43. bwired-a67edce accept 117.53.168.72:80 ... bwired-ac12dce accept 117.53.167.72:22 ... no match,

    returns to partition-a same destination, jumps into old chain hits old rule
  44. git

  45. http://www.flickr.com/photos/25084516@N03/4994100153 http://www.flickr.com/photos/pfenwick/2237728495 http://www.flickr.com/photos/varrqnuht/2228404970 http://www.flickr.com/photos/t3rmin4t0r/2276495257 http://www.flickr.com/photos/chrissamuel/2231908105 http://www.flickr.com/photos/nhankamer/4703022414 http://www.flickr.com/photos/nortonp/6236722793 http://www.flickr.com/photos/thomasforsyth/4313764488 http://www.flickr.com/photos/mag3737/204597831 http://www.flickr.com/photos/carleycomartin/3912655528

    http://www.flickr.com/photos/thomas_hackl/8172975389 http://www.flickr.com/photos/memestate/54408373 http://www.flickr.com/photos/ldsykora/2414497811 http://www.flickr.com/photos/usdagov/7061668841 http://www.flickr.com/photos/studiogabe/5213143779 http://www.flickr.com/photos/terrio/4303997455 http://www.flickr.com/photos/cmbellman/3219012282 Credits
  46. http://www.flickr.com/photos/sizemore/2215594186 http://www.flickr.com/photos/tsuna72/5939008153 http://www.flickr.com/photos/stevensnodgrass/3543579066 http://www.flickr.com/photos/altemark/363947977 http://www.flickr.com/photos/moff/4504997898 http://www.flickr.com/photos/charlestilford/8295523130 http://www.flickr.com/photos/nasacommons/4858567480 http://www.vagrantup.com/images/vagrant_header_background-482a12a7.png http://www.flickr.com/photos/10318341@N02/4425899887 http://www.flickr.com/photos/deadair/3361335831

    http://www.flickr.com/photos/zanehollingsworth/3260908168 http://www.flickr.com/photos/cushinglibrary/3740398710 http://www.flickr.com/photos/89964047@N07/8181225923 http://www.flickr.com/photos/minnesotahistoricalsociety/5186865305 http://www.flickr.com/photos/58558794@N07/5739801904 http://www.flickr.com/photos/steverhode/3134180338 http://www.flickr.com/photos/acediscovery/3030548744 Credits