ript 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +6 -0
  2. data/.rbenv-version +1 -0
  3. data/AUTHORS.md +16 -0
  4. data/CHANGELOG.md +93 -0
  5. data/Gemfile +4 -0
  6. data/Gemfile.lock +62 -0
  7. data/LICENCE +19 -0
  8. data/README.md +564 -0
  9. data/Rakefile +136 -0
  10. data/bin/rbenv-sudo +18 -0
  11. data/bin/ript +207 -0
  12. data/dist/init.d +48 -0
  13. data/examples/accept-multiple-from-and-to.rb +16 -0
  14. data/examples/accept-with-a-list-of-ports.rb +13 -0
  15. data/examples/accept-with-specific-port-and-interface.rb +14 -0
  16. data/examples/accept-without-specific-from.rb +11 -0
  17. data/examples/accept.rb +12 -0
  18. data/examples/basic.rb +4 -0
  19. data/examples/dash-in-partition-name.rb +2 -0
  20. data/examples/drop.rb +11 -0
  21. data/examples/duplicate-partition-names/foobar1.rb +2 -0
  22. data/examples/duplicate-partition-names/foobar2.rb +2 -0
  23. data/examples/errors-undefined-method-with-no-match.rb +12 -0
  24. data/examples/errors-undefined-method.rb +12 -0
  25. data/examples/forward-dnat-with-different-destination-port.rb +16 -0
  26. data/examples/forward-dnat-with-explicit-from-and-port-mappings.rb +11 -0
  27. data/examples/forward-dnat-with-explicit-from-and-ports.rb +11 -0
  28. data/examples/forward-dnat-with-explicit-from.rb +11 -0
  29. data/examples/forward-dnat-with-explicit-protocols.rb +15 -0
  30. data/examples/forward-dnat-with-multiple-froms.rb +13 -0
  31. data/examples/forward-dnat-with-multiple-ports.rb +10 -0
  32. data/examples/forward-dnat-with-multiple-sources.rb +15 -0
  33. data/examples/forward-dnat.rb +16 -0
  34. data/examples/forward-snat-with-explicit-from.rb +16 -0
  35. data/examples/forward-snat-with-multiple-sources.rb +13 -0
  36. data/examples/forward-snat.rb +9 -0
  37. data/examples/log-and-accept.rb +12 -0
  38. data/examples/log-and-drop.rb +11 -0
  39. data/examples/log-dnat.rb +10 -0
  40. data/examples/log-snat.rb +13 -0
  41. data/examples/log.rb +11 -0
  42. data/examples/missing-address-definition-in-destination.rb +15 -0
  43. data/examples/missing-address-definition-in-from.rb +15 -0
  44. data/examples/multiple-partitions-in-this-file.rb +14 -0
  45. data/examples/multiple-partitions/bar.rb +11 -0
  46. data/examples/multiple-partitions/foo.rb +17 -0
  47. data/examples/partition-name-exactly-20-characters.rb +2 -0
  48. data/examples/partition-name-longer-than-20-characters.rb +2 -0
  49. data/examples/postclean.rb +10 -0
  50. data/examples/preclean.rb +10 -0
  51. data/examples/raw-with-chain-deletion.rb +9 -0
  52. data/examples/raw-with-flush.rb +9 -0
  53. data/examples/raw.rb +50 -0
  54. data/examples/reject.rb +11 -0
  55. data/examples/space-in-partition-name.rb +2 -0
  56. data/features/cli.feature +115 -0
  57. data/features/dsl/errors.feature +107 -0
  58. data/features/dsl/filter.feature +187 -0
  59. data/features/dsl/logging.feature +114 -0
  60. data/features/dsl/nat.feature +271 -0
  61. data/features/dsl/raw.feature +28 -0
  62. data/features/setup.feature +58 -0
  63. data/features/step_definitions/cli_steps.rb +15 -0
  64. data/features/step_definitions/example_steps.rb +44 -0
  65. data/features/support/env.rb +25 -0
  66. data/lib/ript/bootstrap.rb +20 -0
  67. data/lib/ript/dsl.rb +14 -0
  68. data/lib/ript/dsl/primitives.rb +7 -0
  69. data/lib/ript/dsl/primitives/common.rb +78 -0
  70. data/lib/ript/dsl/primitives/filter.rb +145 -0
  71. data/lib/ript/dsl/primitives/nat.rb +206 -0
  72. data/lib/ript/dsl/primitives/raw.rb +45 -0
  73. data/lib/ript/exceptions.rb +2 -0
  74. data/lib/ript/partition.rb +162 -0
  75. data/lib/ript/patches.rb +10 -0
  76. data/lib/ript/rule.rb +70 -0
  77. data/lib/ript/version.rb +3 -0
  78. data/ript.gemspec +33 -0
  79. metadata +232 -0
@@ -0,0 +1,6 @@
1
+ tmp/
2
+ pkg/
3
+ *.swp
4
+ *~
5
+ vendor
6
+ .bundle
@@ -0,0 +1 @@
1
+ 1.9.2-p290
@@ -0,0 +1,16 @@
1
+ Ript was designed and built by:
2
+
3
+ Lindsay Holmwood (@auxesis)
4
+ Steve Fisher (@laminat0r)
5
+
6
+ Patches have been merged from:
7
+
8
+ Arthur Barton (@arthurbarton)
9
+ John Ferlito (@johnf)
10
+ Jesse Reynolds (@jessereynolds)
11
+
12
+ Inspiration given by:
13
+
14
+ Matt Moor (@mattm0)
15
+
16
+ Ript is copyright Bulletproof Networks 2011-2012, all rights reserved.
@@ -0,0 +1,93 @@
1
+ ## Changelog
2
+
3
+ # 0.8.4 - 2012/08/121
4
+ - Bug: DNAT rules from one port to another were adding a filter rule for the
5
+ source instead of destination port (@johnf)
6
+
7
+ # 0.8.3 - 2012/07/19
8
+ - Bug: Default the protocol for filter rules to TCP, so filter rules are generated correctly (@auxesis)
9
+
10
+ # 0.8.2 - 2012/07/19
11
+ - Bug: Fix a regression where we don't generate rules without an explicit from. (@auxesis)
12
+
13
+ # 0.8.1 - 2012/07/17
14
+ - Bug: Generate the iptables clean commands in Ruby, to eliminate bogus clean command generation (@auxesis)
15
+ - Chore: Refactor test internals to re-use common iptables cleaning routines (@auxesis)
16
+
17
+ # 0.8.0 - 2012/07/17
18
+ - Feature: Allow multiple froms to be specified in a DNAT rewrite (@auxesis)
19
+ - Feature: Provide a default label named "all", that represents the IPv4 zero-address 0.0.0.0/0 (@auxesis)
20
+
21
+ # 0.7.1 - 2012/07/16
22
+ - Bug: Ensure the list of chains to clean up is unique, so we don't delete the same chains multiple times (@auxesis)
23
+
24
+ # 0.7.0 - 2012/07/09
25
+ - Feature: Show a custom message if exceptions appear to be generated by Ript (@auxesis)
26
+ - Feature: Add support for specifying protocols in rewrites (@auxesis)
27
+ - Chore: Move example rules to examples/. Point tests at the new directory (@auxesis)
28
+
29
+ # 0.6.1 - 2012/06/06
30
+ - Feature: Make init script executable (@johnf)
31
+
32
+ # 0.6.0 - 2012/06/06
33
+ - Feature: add "rules save", outputs rules in a format suitable for iptables-restore (@johnf)
34
+ - Feature: Add an init script to dist/ that performs iptables-restore at boot (@johnf)
35
+
36
+ # 0.5.0 - 2012/05/31
37
+ - Feature: rename "customer" to "partition", to make terminology more friendly for use on standalone hosts (thanks @jessereynolds)
38
+
39
+ # 0.4.3 - 2012/05/27
40
+ - Bug: Fix clean subcommand so it ignores important chains (before-a, etc) (@johnf)
41
+
42
+ # 0.4.2 - 2012/05/24
43
+ - Bug: Use the destination address in the FORWARD chain when building the implicit accept on DNAT, so traffic actually gets accepted (@auxesis)
44
+
45
+ # 0.4.1 - 2012/05/23
46
+ - Bug: Emit --protocol when generating ACCEPT rules, so the --dport argument works (@auxesis)
47
+
48
+ # 0.4.0 - 2012/05/23
49
+ - Feature: Automatically create ACCEPT rules on the FORWARD chain, so NAT works in environments where DROP is the default policy(@auxesis)
50
+ - Feature: Reject multiple partition definitions in the same file, to maintain clean definitions(@auxesis)
51
+ - Feature: Make the DSL documentation awesome(@auxesis)
52
+
53
+ # 0.3.6 - 2012/05/03
54
+ - Bug: Tests were broken and weren't matching empty output correctly (@johnf)
55
+ - Bug: raw tables were being applied repeatedly (@johnf)
56
+
57
+ # 0.3.5 - 2012/05/03
58
+ - Bug: Bring back generate functionality (@johnf)
59
+
60
+ # 0.3.4 - 2012/05/03
61
+ - Chore: Remove timestamps from chain names (@johnf)
62
+ - Feature: Add partition-X chain (@johnf)
63
+ - Feature: Add cleanup functionality (@johnf)
64
+ - Chore: Update CLI arguments (@johnf)
65
+
66
+ # 0.3.3 - 2012/05/02
67
+ - Bug: Split SNAT/DNAT partition rule generation into separate chains, so rules apply correctly (@johnf)
68
+ - Feature: Check that ript is being run as root (@arthurbarton)
69
+
70
+ # 0.3.2 - 2012/04/25
71
+ - Feature: Add validation for duplicate partition names (@auxesis)
72
+ - Feature: Add validation for bad characters in partition names (@auxesis)
73
+ - Feature: Add validation for partition names longer than 12 characters (@auxesis)
74
+
75
+ # 0.3.1 - 2012/04/24
76
+ - Feature: Add support for specifying multiple to addresses in a single accept/drop/reject definition (@auxesis)
77
+
78
+ # 0.3.0 - 2012/04/23
79
+ - Feature: Attempt to suggest alternative method names when a user uses one that doesn't exist (@auxesis)
80
+ - Feature: Extend accept, reject, drop, log blocks in the DSL to handle interfaces, protocols, and ports (@auxesis)
81
+ - Feature: Allow ript to run against an arbitrary path or file to the relative path (@auxesis)
82
+ - Feature: Add logging support throughout the DSL (@auxesis)
83
+ - Chore: Rename 'address' to 'label' in the DSL, as that's what they are (@auxesis)
84
+ - Chore: Rename 'forward' to 'rewrite' in the DSL, to reduce terminology collisions (@auxesis)
85
+ - Chore: Add a test harness script for running ript + tests in an rbenv environment as root (@auxesis)
86
+
87
+ # 0.2.0 - 2012/04/10
88
+ - Add support for SNAT rules (@auxesis)
89
+ - Split tests into more managable files (@auxesis)
90
+
91
+ # 0.1.0 - 2012/03/26
92
+ - Add installation + development documentation. (@auxesis)
93
+ - Build a gem release. (@auxesis)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ source :rubygems
4
+ gemspec
@@ -0,0 +1,62 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ript (0.8.4)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ arr-pm (0.0.7)
10
+ cabin (> 0)
11
+ aruba (0.3.5)
12
+ childprocess (>= 0.1.7)
13
+ cucumber (>= 0.10.0)
14
+ rspec (>= 2.5.0)
15
+ backports (2.3.0)
16
+ builder (3.0.0)
17
+ cabin (0.4.4)
18
+ json
19
+ childprocess (0.1.8)
20
+ ffi (~> 1.0.6)
21
+ clamp (0.3.1)
22
+ colorize (0.5.8)
23
+ cucumber (1.1.9)
24
+ builder (>= 2.1.2)
25
+ diff-lcs (>= 1.1.2)
26
+ gherkin (~> 2.9.0)
27
+ json (>= 1.4.6)
28
+ term-ansicolor (>= 1.0.6)
29
+ diff-lcs (1.1.3)
30
+ ffi (1.0.7)
31
+ rake (>= 0.8.7)
32
+ fpm (0.4.5)
33
+ arr-pm (~> 0.0.7)
34
+ backports (= 2.3.0)
35
+ cabin (~> 0.4.3)
36
+ clamp
37
+ json
38
+ gherkin (2.9.3)
39
+ json (>= 1.4.6)
40
+ json (1.6.6)
41
+ rake (0.8.7)
42
+ rspec (2.5.0)
43
+ rspec-core (~> 2.5.0)
44
+ rspec-expectations (~> 2.5.0)
45
+ rspec-mocks (~> 2.5.0)
46
+ rspec-core (2.5.1)
47
+ rspec-expectations (2.5.0)
48
+ diff-lcs (~> 1.1.2)
49
+ rspec-mocks (2.5.0)
50
+ term-ansicolor (1.0.7)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ aruba
57
+ colorize
58
+ cucumber (>= 1.1.9)
59
+ fpm (>= 0.4.5)
60
+ rake
61
+ ript!
62
+ rspec
data/LICENCE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright 2011-2012 Bulletproof Networks. All rights reserved.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,564 @@
1
+ Ript
2
+ ====
3
+
4
+ Ript provides a clean Ruby DSL for describing firewall rules, and implements
5
+ database migrations-like functionality for applying the rules with zero downtime.
6
+
7
+ Ript works with `iptables` on Linux, and is written in Ruby.
8
+
9
+ Installing
10
+ ----------
11
+
12
+ Make sure you have Ruby 1.9.2 installed, and run:
13
+
14
+ ``` bash
15
+ gem install ript
16
+ ```
17
+
18
+ If you want the firewall rules to be reloaded at reboot, you will need to set up an
19
+ init script.
20
+
21
+ ``` bash
22
+ sudo cp "$(dirname $(dirname $(dirname $(gem which ript/dsl.rb))))"/dist/init.d /etc/init.d/ript
23
+ sudo update-rc.d ript defaults
24
+ sudo mkdir /var/lib/ript
25
+ sudo chown root.adm /var/lib/ript
26
+ sudo chmod 770 /var/lib/ript
27
+ ```
28
+
29
+ Applying rules
30
+ --------------
31
+
32
+ - Run `ript rules generate <path>` - will output all the generated rules by interpreting the file, or files in directory, `<path>`
33
+ - Run `ript rules diff <path>` - will output a diff of rules to apply based on what rules are currently loaded in memory
34
+ - Run `ript rules apply <path>` - will apply the aforementioned diff
35
+ - Run `ript rules diff <path>` - will display any rules not applied correctly
36
+ - Run `ript rules save` - will output the currently loaded rule in iptables-restore format
37
+ - Run `ript clean diff <path>` - will output iptables commands to delete unneeded rules
38
+ - Run `ript clean apply <path>` - will run the iptables commands to delete unneeded rules
39
+
40
+ There are tests for this workflow in `features/cli.feature`
41
+
42
+ Note: If you are using the supplied init script then you will need to add:
43
+ ``` bash
44
+ ript rules save > /var/lib/ript/iptables.stat
45
+ ```
46
+ to your workflow.
47
+
48
+ Developing
49
+ ----------
50
+
51
+ It is recommended to use a Ubuntu Lucid VM to develop Ript. If you develop on a machine without iptables some of the tests will fail.
52
+
53
+ It is also recommended that you use [rbenv](http://rbenv.org/).
54
+
55
+ ``` bash
56
+ rbenv install 1.9.2-p290
57
+ gem install bundler
58
+ rbenv rehash
59
+ ```
60
+
61
+ Then to setup a Ript development environment, run:
62
+
63
+ ``` bash
64
+ git clone git@github.com:bulletproofnetworks/ript.git
65
+ cd ript
66
+ bundle
67
+ rbenv rehash
68
+ ```
69
+
70
+ Then run the tests with:
71
+
72
+ ``` bash
73
+ # Run all the tests
74
+ sudo bin/rbenv-sudo rake features
75
+ # Run a specific test file
76
+ sudo bin/rbenv-sudo cucumber -r features/support/ -r features/step_definitions/ features/dsl/filter.feature
77
+ # Run a specific test in a file
78
+ sudo bin/rbenv-sudo cucumber -r features/support/ -r features/step_definitions/ features/dsl/filter.feature:13
79
+ ```
80
+
81
+ ript commands can be run like so:
82
+
83
+ ```` bash
84
+ sudo bin/rbenv-sudo bundle exec ript --help
85
+ ```
86
+
87
+ Releasing
88
+ ---------
89
+
90
+ 1. Bump the version in `lib/ript/version.rb`
91
+ 2. Add an entry to `CHANGELOG.md`
92
+ 3. Run a `bundle` to update any RubyGems dependencies.
93
+ 4. `git commit` everything.
94
+ 5. git tag the version git tag X.Y.Z
95
+ 6. Build the gem with `rake build`
96
+
97
+ This will build a `.gem` and a `.deb` in `pkg/`
98
+
99
+ Design
100
+ ------
101
+
102
+ - Applying firewall rules should cause zero downtime.
103
+ - Making a change to a partition's rules should only ever affect that partition.
104
+ - Each partition has their own set of chains where their rules live.
105
+ - Each chain is self contained, and there a pointers to that chain from a
106
+ global chain where all partition pointers live.
107
+ - The pointer rules should be kept very simple, to reduce the chain traversal
108
+ time for packets.
109
+ - Rolling forward is as simple as creating a new chain, and inserting pointers
110
+ to the new chain in the global chain.
111
+ - Rolling back is as simple as deleting the pointers to the new chain from the
112
+ global chain. The new chain could be retained, but we choose delete it.
113
+ - Decommissioning a partition should be as simple as removing the partition's
114
+ rules file.
115
+ - Deleting the rules file will cause Ript to realise the partition's chains
116
+ should be deleted.
117
+
118
+ The DSL
119
+ -------
120
+
121
+ The core of Ript is its easy to use DSL to describe iptables firewall rules.
122
+
123
+ The DSL is flexible and handles both simple and complex use cases.
124
+
125
+ ### Introduction ###
126
+
127
+ ![Book cover - http://www.flickr.com/photos/sterlic/4299631538/sizes/z/in/photostream/](http://farm5.staticflickr.com/4116/4880818306_3bd230d0d4_z.jpg)
128
+
129
+ Let's start from the beginning:
130
+
131
+ ``` ruby
132
+ # partitions/joeblogsco.rb
133
+ partition "joeblogsco" do
134
+ # Labels + rules go here
135
+ end
136
+ ```
137
+
138
+ All labels + rules in Ript are wrapped in a `partition` block, which partitions
139
+ partition rules so they can be changed on a per-partition basis. This is integral
140
+ to how Ript does zero-downtime rule migrations.
141
+
142
+ So, what are labels?
143
+
144
+ ``` ruby
145
+ # partitions/joeblogsco.rb
146
+ partition "joeblogsco" do
147
+ label "www.joeblogsco.com", :address => "172.19.56.216"
148
+ label "api.joeblogsco.com", :address => "172.19.56.217"
149
+ label "joeblogsco subnet", :address => "192.168.5.224/27"
150
+ label "app-01", :address => "192.168.5.230"
151
+ end
152
+ ```
153
+
154
+ Labels are identifiers for addresses or subnets that you want to write rules
155
+ for.
156
+
157
+ What are rules?
158
+
159
+ ``` ruby
160
+ # partitions/joeblogsco.rb
161
+ partition "joeblogsco" do
162
+ label "www.joeblogsco.com", :address => "172.19.56.216"
163
+ label "api.joeblogsco.com", :address => "172.19.56.217"
164
+ label "joeblogsco subnet", :address => "192.168.5.224/27"
165
+ label "app-01", :address => "192.168.5.230"
166
+
167
+ rewrite "public website" do
168
+ ports 80
169
+ dnat "www.joeblogsco.com" => "app-01"
170
+ end
171
+ end
172
+ ```
173
+
174
+ Rules define how traffic flows from one place to another. Rules can either
175
+ rewrite the source or destination of a packet (SNAT and DNAT), or permit/deny
176
+ the flow of traffic:
177
+
178
+
179
+ ``` ruby
180
+ # partitions/joeblogsco.rb
181
+ partition "joeblogsco" do
182
+ label "www.joeblogsco.com", :address => "172.19.56.216"
183
+ label "api.joeblogsco.com", :address => "172.19.56.217"
184
+ label "joeblogsco subnet", :address => "192.168.5.224/27"
185
+ label "app-01", :address => "192.168.5.230"
186
+ label "trusted office", :address => "172.20.4.124"
187
+
188
+ rewrite "public website" do
189
+ ports 80
190
+ dnat "www.joeblogsco.com" => "app-01"
191
+ end
192
+
193
+ rewrite "public ssh access" do
194
+ ports 22
195
+ dnat "www.joeblogsco.com" => "app-01"
196
+ end
197
+
198
+ end
199
+ ```
200
+
201
+ In the above example, we are telling Ript we want SSH traffic to
202
+ `www.joeblogsco.co` (`172.19.56.216`) which is on a public network to be sent
203
+ to `app-01` (`192.168.5.230`), which is on a private network.
204
+
205
+ Because the default policy is to drop packets that don't have an explicit
206
+ match, we also need an `accept` rule so that the traffic being rewritten is also
207
+ allowed to pass through.
208
+
209
+ Ript knows this is generally what you want to do, so it actually creates this
210
+ rule for you automatically. If we were to write it out, it would look something
211
+ like this:
212
+
213
+ ``` ruby
214
+ rewrite "public ssh access" do
215
+ ports 22
216
+ dnat "www.joeblogsco.com" => "app-01"
217
+ end
218
+
219
+ accept "allow public ssh access" do
220
+ protocols "tcp"
221
+ ports 22
222
+ to "www.joeblogsco.com"
223
+ end
224
+ ```
225
+
226
+ Ript's DSL is actually pretty smart, so we can clean up the above example a
227
+ bit:
228
+
229
+ ``` ruby
230
+ # partitions/joeblogsco.rb
231
+ partition "joeblogsco" do
232
+ label "www.joeblogsco.com", :address => "172.19.56.216"
233
+ label "api.joeblogsco.com", :address => "172.19.56.217"
234
+ label "joeblogsco subnet", :address => "192.168.5.224/27"
235
+ label "app-01", :address => "192.168.5.230"
236
+ label "trusted office", :address => "172.20.4.124"
237
+
238
+ rewrite "public website + ssh access" do
239
+ ports 80, 22
240
+ dnat "www.joeblogsco.com" => "app-01"
241
+ end
242
+
243
+ end
244
+ ```
245
+
246
+ Here we have collapsed the two rewrite rules into one. Ript does the heavy
247
+ lifting behind the scenes to generate the all the rules.
248
+
249
+ If you want to be more specific about your rewrites (for example, you only want
250
+ external SSH access from a specific jump host), it's really straight forward:
251
+
252
+ ``` ruby
253
+ # partitions/joeblogsco.rb
254
+ partition "joeblogsco" do
255
+ label "www.joeblogsco.com", :address => "172.19.56.216"
256
+ label "api.joeblogsco.com", :address => "172.19.56.217"
257
+ label "joeblogsco subnet", :address => "192.168.5.224/27"
258
+ label "app-01", :address => "192.168.5.230"
259
+ label "trusted office", :address => "172.20.4.124"
260
+
261
+ rewrite "public website" do
262
+ ports 80
263
+ dnat "www.joeblogsco.com" => "app-01"
264
+ end
265
+
266
+ rewrite "trusted ssh access" do
267
+ ports 22
268
+ from "trusted office"
269
+ dnat "www.joeblogsco.com" => "app-01"
270
+ end
271
+ end
272
+ ```
273
+
274
+ <a id="ports"></a>
275
+ You have a lot of flexibility when specifying ports, port ranges, and port mappings:
276
+
277
+ ``` ruby
278
+ # partitions/joeblogsco.rb
279
+ partition "joeblogsco" do
280
+ label "www.joeblogsco.com", :address => "172.19.56.216"
281
+ label "api.joeblogsco.com", :address => "172.19.56.217"
282
+ label "joeblogsco subnet", :address => "192.168.5.224/27"
283
+ label "app-01", :address => "192.168.5.230"
284
+ label "app-02", :address => "192.168.5.231"
285
+ label "trusted office", :address => "172.20.4.124"
286
+
287
+ rewrite "public mail" do
288
+ # Pass TCP port 25 + 993 through to app-01
289
+ ports 25, 993
290
+ dnat "www.joeblogsco.com" => "app-01"
291
+ end
292
+
293
+ rewrite "trusted private services" do
294
+ # Pass TCP port 6000 to 8000 through to app-01 from the trusted office
295
+ from "trusted office"
296
+ ports 6000..8000
297
+ dnat "www.joeblogsco.com" => "app-01"
298
+ end
299
+
300
+ rewrite "public website" do
301
+ # Map TCP port 80 traffic on the public IP to TCP port 8080 on app-01
302
+ ports 80 => 8080
303
+ dnat "www.joeblogsco.com" => "app-01"
304
+ end
305
+
306
+ rewrite "api services" do
307
+ # Pass TCP port 80 through to app-02
308
+ # Pass TCP port 8000 to 8900 through to app-02
309
+ # Map TCP port 2222 traffic on the public IP to TCP port 22 on app-02
310
+ ports 80, 8000..8900, 2222 => 22
311
+ dnat "api.joeblogsco.com" => "app-02"
312
+ end
313
+ end
314
+ ```
315
+
316
+ The above `ports` syntax works throughout all rule types.
317
+
318
+ Some notes on the DSL so far:
319
+
320
+ - A label's scope is restricted to the partition block it is defined in. This
321
+ means you can use the same labels across different partitions and there won't
322
+ be naming colissions.
323
+
324
+ - The string argument passed to `rewrite`, `accept`, and other DSL rules is
325
+ used purely for documentation (think comments). Other people maintaining your
326
+ firewall rules will love you when you describe the intention of those rule in
327
+ these comments.
328
+
329
+ It's always best to write rules as if the person who ends up maintaining your
330
+ rules is a violent psychopath who knows where you live.
331
+
332
+ - Rules will default to the TCP protocol if you don't specify one. Valid
333
+ protocols can be found in `/etc/protocols` on any Linux system. Ript accepts
334
+ both the numeric and string identifiers (`udp` and `17` are both valid), but
335
+ strongly recommends you use the string identifiers.
336
+
337
+ - Given `accept` rules are created automatically when you define a rewrite, you
338
+ may be wondering if `accept` rules are used at all?
339
+
340
+ `accept` is very useful on standalone firewalls, when opening up specific
341
+ ports to the public internet.
342
+
343
+ For firewall configurations that are doing lots of public-to-private address
344
+ translation, you're going to use `accepts` very rarely.
345
+
346
+ - Arguments to `ports` can be mixed (`ports 500..650, 80, 25, 9000..9500`),
347
+ but you must always specify port mappings last, e.g. `ports 25, 80 => 8080`
348
+ is valid, but `ports 80 => 8080, 25` is not.
349
+
350
+
351
+ ### Rule types ###
352
+
353
+ ![Ruler - http://www.flickr.com/photos/sterlic/4299631538/](http://farm3.staticflickr.com/2730/4299631538_220c9c9448_z.jpg)
354
+
355
+ The introduction examples cover the common use cases, but Ript has support for
356
+ many other types of rules.
357
+
358
+ For example, SNAT:
359
+
360
+ ``` ruby
361
+ # partitions/joeblogsco.rb
362
+ partition "joeblogsco" do
363
+ label "www.joeblogsco.com", :address => "172.19.56.216"
364
+ label "joeblogsco subnet", :address => "192.168.5.224/27"
365
+ label "app-01", :address => "192.168.5.230"
366
+
367
+ rewrite "private to public" do
368
+ snat "joeblogsco subnet" => "www.joeblogsco.com"
369
+ end
370
+ end
371
+ ```
372
+
373
+ The above SNAT rule will rewrite all outgoing traffic from the
374
+ `joeblogsco subnet` to appear as if it's originating from `www.joeblogsco.com`
375
+ (`172.19.56.216`).
376
+
377
+ If you need to explicitly drop traffic from somewhere, Ript makes this trivial:
378
+
379
+ ``` ruby
380
+ # partitions/joeblogsco.rb
381
+ partition "joeblogsco" do
382
+ label "www.joeblogsco.com", :address => "172.19.56.216"
383
+ label "app-01", :address => "192.168.5.230"
384
+ label "bad guy", :address => "172.19.110.247"
385
+
386
+ rewrite "public website + ssh access" do
387
+ ports 80, 22
388
+ dnat "www.joeblogsco.com" => "app-01"
389
+ end
390
+
391
+ drop "bad guy" do
392
+ from "bad guy"
393
+ to "www.joeblogsco.com"
394
+ end
395
+ end
396
+ ```
397
+
398
+ You can also broaden your drop to subnets, and restrict it down to a protocol:
399
+
400
+ ``` ruby
401
+ # partitions/joeblogsco.rb
402
+ partition "joeblogsco" do
403
+ label "www.joeblogsco.com", :address => "172.19.56.216"
404
+ label "app-01", :address => "192.168.5.230"
405
+ label "bad guys", :address => "10.0.0.0/8"
406
+
407
+ rewrite "public website + ssh access" do
408
+ ports 80, 22
409
+ dnat "www.joeblogsco.com" => "app-01"
410
+ end
411
+
412
+ drop "bad guys" do
413
+ protocols "udp"
414
+ from "bad guys"
415
+ to "www.joeblogsco.com"
416
+ end
417
+ end
418
+ ```
419
+
420
+ Alternatively, you can also reject the traffic:
421
+
422
+ ``` ruby
423
+ # partitions/joeblogsco.rb
424
+ partition "joeblogsco" do
425
+ label "www.joeblogsco.com", :address => "172.19.56.216"
426
+ label "app-01", :address => "192.168.5.230"
427
+ label "bad guys", :address => "10.0.0.0/8"
428
+
429
+ rewrite "public website + ssh access" do
430
+ ports 80, 22
431
+ dnat "www.joeblogsco.com" => "app-01"
432
+ end
433
+
434
+ reject "bad guys" do
435
+ protocols "udp"
436
+ from "bad guys"
437
+ to "www.joeblogsco.com"
438
+ end
439
+ end
440
+ ```
441
+
442
+ ### Logging ###
443
+
444
+ ![Logs - http://www.flickr.com/photos/crawshawt/4636162605/](http://farm5.staticflickr.com/4020/4636162605_9ac8e91b56_z.jpg)
445
+
446
+ Dropping and rejecting traffic is very useful, but if a tree falls in the
447
+ forest and no-one is there to hear it...
448
+
449
+ Ript makes flipping on logging extremely simple:
450
+
451
+ ``` ruby
452
+ # partitions/joeblogsco.rb
453
+ partition "joeblogsco" do
454
+ label "www.joeblogsco.com", :address => "172.19.56.216"
455
+ label "app-01", :address => "192.168.5.230"
456
+ label "bad guys", :address => "10.0.0.0/8"
457
+
458
+ rewrite "public website + ssh access", :log => true do
459
+ ports 80, 22
460
+ dnat "www.joeblogsco.com" => "app-01"
461
+ end
462
+
463
+ reject "bad guys", :log => true do
464
+ protocols "udp"
465
+ from "bad guys"
466
+ to "www.joeblogsco.com"
467
+ end
468
+ end
469
+ ```
470
+
471
+ You can pass `:log => true` to any rule, and Ript will automatically generate
472
+ logging statements.
473
+
474
+
475
+ ### Shortcuts ###
476
+
477
+ ![Shorthand http://www.flickr.com/photos/sizemore/2215594186/](http://farm3.staticflickr.com/2397/2215594186_c979f71689_z.jpg)
478
+
479
+ Ript provides shortcuts for setting up common rules:
480
+
481
+ ``` ruby
482
+ partition "joeblogsco" do
483
+ label "joeblogsco uat subnet", :address => "192.168.5.0/24"
484
+ label "joeblogsco stage subnet", :address => "10.60.2.0/24"
485
+ label "joeblogsco prod subnet", :address => "10.60.3.0/24"
486
+ label "www.joeblogsco.com", :address => "172.19.56.216"
487
+
488
+ rewrite "private to public" do
489
+ snat [ "joeblogsco uat subnet",
490
+ "joeblogsco stage subnet",
491
+ "joeblogsco prod subnet" ] => "www.joeblogsco.com"
492
+ end
493
+ end
494
+ ```
495
+
496
+ Ript will expand the above to:
497
+
498
+ ``` ruby
499
+ partition "joeblogsco" do
500
+ label "joeblogsco uat subnet", :address => "192.168.5.0/24"
501
+ label "joeblogsco stage subnet", :address => "10.60.2.0/24"
502
+ label "joeblogsco prod subnet", :address => "10.60.3.0/24"
503
+ label "www.joeblogsco.com", :address => "172.19.56.216"
504
+
505
+ rewrite "private to public" do
506
+ snat "joeblogsco uat subnet" => "www.joeblogsco.com"
507
+ end
508
+
509
+ rewrite "private to public" do
510
+ snat "joeblogsco stage subnet" => "www.joeblogsco.com"
511
+ end
512
+
513
+ rewrite "private to public" do
514
+ snat "joeblogsco prod subnet" => "www.joeblogsco.com"
515
+ end
516
+ end
517
+ ```
518
+
519
+ This also behaves exactly the same way with `accept`/`reject`/`drop` rules:
520
+
521
+ ``` ruby
522
+ partition "tootyfruity" do
523
+ label "apple", :address => "192.168.0.1"
524
+ label "blueberry", :address => "192.168.0.2"
525
+ label "cranberry", :address => "192.168.0.3"
526
+ label "eggplant", :address => "192.168.0.4"
527
+ label "fennel", :address => "192.168.0.5"
528
+ label "grapefruit", :address => "192.168.0.6"
529
+
530
+ accept "fruits of the forest" do
531
+ protocols "tcp"
532
+ ports 22
533
+ from %w(apple blueberry cranberry eggplant fennel grapefruit)
534
+ to %w(apple blueberry cranberry eggplant fennel grapefruit)
535
+ end
536
+ end
537
+ ```
538
+
539
+ In the above example, Ript will generate rules for all the different
540
+ combinations of `from` + `to` hosts.
541
+
542
+ You can also specify ranges of ports to generate rules for, and setup port
543
+ mappings:
544
+
545
+ ``` ruby
546
+ partition "tootyfruity" do
547
+ label "apple", :address => "192.168.0.1"
548
+ label "blueberry", :address => "192.168.0.2"
549
+ label "cranberry", :address => "192.168.0.3"
550
+ label "eggplant", :address => "192.168.0.4"
551
+ label "fennel", :address => "192.168.0.5"
552
+ label "grapefruit", :address => "192.168.0.6"
553
+
554
+ rewrite "forward lots of ports, and don't make SSH public" do
555
+ protocols "tcp"
556
+ ports 80, 8600..8900, 443 => 4443, 2222 => 22
557
+ from %w(apple blueberry cranberry eggplant fennel grapefruit)
558
+ to %w(apple blueberry cranberry eggplant fennel grapefruit)
559
+ end
560
+ end
561
+ ```
562
+
563
+ The above example will generate a *lot* of rules, but it illustrates the power
564
+ of the DSL.