ript 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.rbenv-version +1 -0
- data/AUTHORS.md +16 -0
- data/CHANGELOG.md +93 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +62 -0
- data/LICENCE +19 -0
- data/README.md +564 -0
- data/Rakefile +136 -0
- data/bin/rbenv-sudo +18 -0
- data/bin/ript +207 -0
- data/dist/init.d +48 -0
- data/examples/accept-multiple-from-and-to.rb +16 -0
- data/examples/accept-with-a-list-of-ports.rb +13 -0
- data/examples/accept-with-specific-port-and-interface.rb +14 -0
- data/examples/accept-without-specific-from.rb +11 -0
- data/examples/accept.rb +12 -0
- data/examples/basic.rb +4 -0
- data/examples/dash-in-partition-name.rb +2 -0
- data/examples/drop.rb +11 -0
- data/examples/duplicate-partition-names/foobar1.rb +2 -0
- data/examples/duplicate-partition-names/foobar2.rb +2 -0
- data/examples/errors-undefined-method-with-no-match.rb +12 -0
- data/examples/errors-undefined-method.rb +12 -0
- data/examples/forward-dnat-with-different-destination-port.rb +16 -0
- data/examples/forward-dnat-with-explicit-from-and-port-mappings.rb +11 -0
- data/examples/forward-dnat-with-explicit-from-and-ports.rb +11 -0
- data/examples/forward-dnat-with-explicit-from.rb +11 -0
- data/examples/forward-dnat-with-explicit-protocols.rb +15 -0
- data/examples/forward-dnat-with-multiple-froms.rb +13 -0
- data/examples/forward-dnat-with-multiple-ports.rb +10 -0
- data/examples/forward-dnat-with-multiple-sources.rb +15 -0
- data/examples/forward-dnat.rb +16 -0
- data/examples/forward-snat-with-explicit-from.rb +16 -0
- data/examples/forward-snat-with-multiple-sources.rb +13 -0
- data/examples/forward-snat.rb +9 -0
- data/examples/log-and-accept.rb +12 -0
- data/examples/log-and-drop.rb +11 -0
- data/examples/log-dnat.rb +10 -0
- data/examples/log-snat.rb +13 -0
- data/examples/log.rb +11 -0
- data/examples/missing-address-definition-in-destination.rb +15 -0
- data/examples/missing-address-definition-in-from.rb +15 -0
- data/examples/multiple-partitions-in-this-file.rb +14 -0
- data/examples/multiple-partitions/bar.rb +11 -0
- data/examples/multiple-partitions/foo.rb +17 -0
- data/examples/partition-name-exactly-20-characters.rb +2 -0
- data/examples/partition-name-longer-than-20-characters.rb +2 -0
- data/examples/postclean.rb +10 -0
- data/examples/preclean.rb +10 -0
- data/examples/raw-with-chain-deletion.rb +9 -0
- data/examples/raw-with-flush.rb +9 -0
- data/examples/raw.rb +50 -0
- data/examples/reject.rb +11 -0
- data/examples/space-in-partition-name.rb +2 -0
- data/features/cli.feature +115 -0
- data/features/dsl/errors.feature +107 -0
- data/features/dsl/filter.feature +187 -0
- data/features/dsl/logging.feature +114 -0
- data/features/dsl/nat.feature +271 -0
- data/features/dsl/raw.feature +28 -0
- data/features/setup.feature +58 -0
- data/features/step_definitions/cli_steps.rb +15 -0
- data/features/step_definitions/example_steps.rb +44 -0
- data/features/support/env.rb +25 -0
- data/lib/ript/bootstrap.rb +20 -0
- data/lib/ript/dsl.rb +14 -0
- data/lib/ript/dsl/primitives.rb +7 -0
- data/lib/ript/dsl/primitives/common.rb +78 -0
- data/lib/ript/dsl/primitives/filter.rb +145 -0
- data/lib/ript/dsl/primitives/nat.rb +206 -0
- data/lib/ript/dsl/primitives/raw.rb +45 -0
- data/lib/ript/exceptions.rb +2 -0
- data/lib/ript/partition.rb +162 -0
- data/lib/ript/patches.rb +10 -0
- data/lib/ript/rule.rb +70 -0
- data/lib/ript/version.rb +3 -0
- data/ript.gemspec +33 -0
- metadata +232 -0
data/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.2-p290
|
data/AUTHORS.md
ADDED
@@ -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.
|
data/CHANGELOG.md
ADDED
@@ -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
data/Gemfile.lock
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
+

|
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
|
+

|
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
|
+

|
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
|
+

|
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.
|