iptables-ruby 0.2.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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/CHANGELOG +23 -0
- data/Gemfile +6 -0
- data/Generate.md +278 -0
- data/LICENSE +20 -0
- data/README.md +140 -0
- data/Rakefile +44 -0
- data/bin/check_firewall.rb +220 -0
- data/examples/policy/macros.json +92 -0
- data/examples/policy/policy.json +208 -0
- data/examples/policy/policy6.json +8 -0
- data/examples/policy/primitives.json +40 -0
- data/examples/policy/rules.json +30 -0
- data/examples/policy/services.json +81 -0
- data/lib/iptables.rb +5 -0
- data/lib/iptables/configuration.rb +116 -0
- data/lib/iptables/expansions.rb +189 -0
- data/lib/iptables/logger.rb +5 -0
- data/lib/iptables/primitives.rb +51 -0
- data/lib/iptables/tables.rb +851 -0
- data/test/common.rb +22 -0
- data/test/tc_all.rb +7 -0
- data/test/tc_comparison.rb +751 -0
- data/test/tc_configuration.rb +72 -0
- data/test/tc_expansions.rb +116 -0
- data/test/tc_primitives.rb +35 -0
- data/test/tc_tables.rb +652 -0
- metadata +94 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3cdee7f713d4749034b6106e46c562312fccbaf2
|
4
|
+
data.tar.gz: 24934051d8029a1798b7b8d5319274d68c2b5cce
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1bb21c4234d7b3880faa9c16aefac00b474856938f1ea2975e482238f9771b37bf24fca3af16dec71303d11db8302ed7f2785e3e37de0de898cee712562f8c9d
|
7
|
+
data.tar.gz: 5ef4fc170a0121d151963910e332ad064d622de4d1ce11e8592deca2cfaf383010cef6e496bb6cc4a5fb67ed2f5d99db966ef86d6cac69c4f25da71949baa86d
|
data/.gitignore
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
0.2.4
|
2
|
+
- Fix comparison corner case.
|
3
|
+
- Nagios example script can read iptables output from file.
|
4
|
+
- Fix Ruby 1.9-unfriendly bugs
|
5
|
+
|
6
|
+
0.2.3
|
7
|
+
- Compare two iptables.
|
8
|
+
- Add documentation.
|
9
|
+
- Add Nagios example script
|
10
|
+
- Add example policy files.
|
11
|
+
|
12
|
+
0.2.2
|
13
|
+
- Generate multi-table output correctly.
|
14
|
+
|
15
|
+
0.2.1
|
16
|
+
- Properly handle merging on top of a policy with a nil table.
|
17
|
+
|
18
|
+
0.2.0
|
19
|
+
- New Rule parameter: "has_primitive":
|
20
|
+
- Do not evaluate or add a rule if it requires a non-existent primitive.
|
21
|
+
|
22
|
+
0.1.0
|
23
|
+
- initial release
|
data/Gemfile
ADDED
data/Generate.md
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
# Generating a firewall
|
2
|
+
|
3
|
+
A complete, generated firewall requires several JSON configuration
|
4
|
+
sections. These can either be compiled into one long JSON file or split
|
5
|
+
into separate files. An example usable firewall has been included within
|
6
|
+
this gem's `examples/policy` directory.
|
7
|
+
|
8
|
+
# Example JSON configuration files
|
9
|
+
|
10
|
+
## macros.json
|
11
|
+
|
12
|
+
This file defines macros, which are reusable rules or sets of rules.
|
13
|
+
Each macro consists of an identifier (example `accept-established`), and
|
14
|
+
its expansion. For more on rules, see section `Rules`.
|
15
|
+
|
16
|
+
## policy.json
|
17
|
+
|
18
|
+
This file defines policy, which is the "top-level" configuration
|
19
|
+
for your **desired** iptables rules.
|
20
|
+
|
21
|
+
Assuming you are using configuration-management software such as
|
22
|
+
[http://www.opscode.com/chef](Chef), you can set one policy for all of
|
23
|
+
your hosts, and then customize your policy per host using rules (see
|
24
|
+
`rules.json`) and primitives (see `primitives.json`).
|
25
|
+
|
26
|
+
The policy file is a hash of the four "standard" iptables tables:
|
27
|
+
`filter`, `mangle`, `nat`, and `raw`. Each of these can in turn either
|
28
|
+
be a hash configuring the table, or `null`.
|
29
|
+
|
30
|
+
### `null`
|
31
|
+
|
32
|
+
If `null`, the policy for that table will be "whatever is already
|
33
|
+
defined". For example, the example configuration file shows
|
34
|
+
`"mangle": null`, which means: "if there is a `mangle` table, use its
|
35
|
+
rules, otherwise leave this table undefined".
|
36
|
+
|
37
|
+
### hash
|
38
|
+
|
39
|
+
If a hash, the table must contain a hash of table names. These will be
|
40
|
+
the standard tables for the corresponding iptables table. For instance,
|
41
|
+
`filter` should minimally contain `INPUT`, `FORWARD`, and `OUTPUT`.
|
42
|
+
Other user-defined tables may also be defined/named.
|
43
|
+
|
44
|
+
Each defined table must have a `policy`. This can either be `DROP`,
|
45
|
+
`ACCEPT`, or `-`.
|
46
|
+
|
47
|
+
Each defined table must also have a `rules` section. This must be an
|
48
|
+
array of firewall rules. For more on rules, see section `Rules`.
|
49
|
+
|
50
|
+
## policy6.json
|
51
|
+
|
52
|
+
This is the same as `policy.json`, but defines ipv6 rules.
|
53
|
+
|
54
|
+
## primitives.json
|
55
|
+
|
56
|
+
Primitives are values that can be interpolated into other parts of your
|
57
|
+
firewall. For more on how these interpolations are used, see section
|
58
|
+
`Interpolation`.
|
59
|
+
|
60
|
+
## rules.json
|
61
|
+
|
62
|
+
`rules` can be an empty hash, or contain any of the named iptables
|
63
|
+
tables (`filter`, `nat`, etc). Any named table is **added** to the rules
|
64
|
+
defined by policy (see example `policy.json`).
|
65
|
+
|
66
|
+
If a table is **not** found in policy, it is added to the generated
|
67
|
+
firewall. It is advised to define at least all standard chains for the
|
68
|
+
table. For instance, `nat` should minimally contain `INPUT`, `OUTPUT`,
|
69
|
+
`POSTROUTING` and `PREROUTING`, and each of these should minimally
|
70
|
+
contain a `policy` definition.
|
71
|
+
|
72
|
+
If a table **is** found in policy, each specified chain can either
|
73
|
+
override or modify the existing table within the policy.
|
74
|
+
|
75
|
+
### Overriding Chain Policy
|
76
|
+
|
77
|
+
Set `"policy": "ACCEPT"` or any other valid policy.
|
78
|
+
|
79
|
+
### Overriding Chain Rules
|
80
|
+
|
81
|
+
Set `"rules": []`. In this case, rules will be reset to be empty.
|
82
|
+
Alternately, fill the array with rules (see section `Rules`).
|
83
|
+
|
84
|
+
### Adding Chain Rules
|
85
|
+
|
86
|
+
Set `"additions": []`. Rules (see section `Rules`) added into this array
|
87
|
+
will be added at node addition points within the policy rules (see
|
88
|
+
section `additions`).
|
89
|
+
|
90
|
+
## services.json
|
91
|
+
|
92
|
+
This file defines services that you will be using within your firewall.
|
93
|
+
See section `Rules` on how to define each service.
|
94
|
+
|
95
|
+
Once defined, a service may be used within policy, rules, or macros.
|
96
|
+
|
97
|
+
# Rules
|
98
|
+
|
99
|
+
Rules fall within an array, and can consist of strings or hashes.
|
100
|
+
|
101
|
+
## String Rules
|
102
|
+
|
103
|
+
A policy that is a string is inserted as-is into the policy
|
104
|
+
firewall, preceded by `-A the_chain_name`. A very simple firewall could
|
105
|
+
consist solely of string rules.
|
106
|
+
|
107
|
+
## Hash rules
|
108
|
+
|
109
|
+
Other kinds of rules are defined as hashes, with the hash key denoting
|
110
|
+
the type of rule:
|
111
|
+
|
112
|
+
### `comment`
|
113
|
+
|
114
|
+
This is shorthand for an iptables comment:
|
115
|
+
|
116
|
+
"comment": "comment1"
|
117
|
+
|
118
|
+
becomes
|
119
|
+
|
120
|
+
-A chain_name -m comment --comment "comment1"
|
121
|
+
|
122
|
+
The `chain_name` is the name of the chain in which the `comment` rule is
|
123
|
+
found.
|
124
|
+
|
125
|
+
### `interpolated`
|
126
|
+
|
127
|
+
See section "Interpolating strings"
|
128
|
+
|
129
|
+
### `macro`
|
130
|
+
|
131
|
+
This inserts the requested macro (see section `macros.json`) into the
|
132
|
+
rules.
|
133
|
+
|
134
|
+
### `node_addition_points`
|
135
|
+
|
136
|
+
See section "`additions` and `node_addition_points`"
|
137
|
+
|
138
|
+
### `service`
|
139
|
+
|
140
|
+
This inserts the requested service (see section `services.json`) into
|
141
|
+
the rules.
|
142
|
+
|
143
|
+
### `service_tcp`
|
144
|
+
|
145
|
+
This takes an integer or string as an argument and inserts a permitted
|
146
|
+
inbound TCP port into the rules:
|
147
|
+
|
148
|
+
"service_tcp": 8080
|
149
|
+
|
150
|
+
becomes
|
151
|
+
|
152
|
+
-A chain_name -p tcp -m tcp --sport 1024:65535 --dport 8080 -m state --state NEW,ESTABLISHED -j ACCEPT
|
153
|
+
|
154
|
+
Port ranges such as `"8080:8090"` can also be used. The `chain_name` is
|
155
|
+
the name of the chain in which the `service_tcp` rule is found.
|
156
|
+
|
157
|
+
### `service_udp`
|
158
|
+
|
159
|
+
This is identical to `service_tcp`, except that it inserts a permitted
|
160
|
+
inbound UDP port.
|
161
|
+
|
162
|
+
### `ulog`
|
163
|
+
|
164
|
+
This is shorthand for an iptables logging statement:
|
165
|
+
|
166
|
+
"ulog": ""
|
167
|
+
|
168
|
+
becomes
|
169
|
+
|
170
|
+
-A chain_name -m limit --limit 1/sec --limit-burst 2 -j ULOG --ulog-prefix "chain_name:"
|
171
|
+
|
172
|
+
This can also use `-p tcp`:
|
173
|
+
|
174
|
+
"ulog": "-p tcp"
|
175
|
+
|
176
|
+
becomes
|
177
|
+
|
178
|
+
-A chain_name -p tcp -m limit --limit 1/sec --limit-burst 2 -j ULOG --ulog-prefix "chain_name:"
|
179
|
+
|
180
|
+
The `chain_name` is the name of the chain in which the `ulog` rule is
|
181
|
+
found.
|
182
|
+
|
183
|
+
# Interpolation
|
184
|
+
|
185
|
+
Primitives (see section `primitives.json`) are available within your
|
186
|
+
configuration using the `<%%>` notation within an `interpolated` rule.
|
187
|
+
|
188
|
+
## Interpolating strings
|
189
|
+
|
190
|
+
An example usage is:
|
191
|
+
|
192
|
+
"interpolated": "-s <% internet.subnet.other %> -d <% internet.address %> -i <% internet.device %> -j ACCEPT"
|
193
|
+
|
194
|
+
Depending upon the defined primitives, the above rule could expand into:
|
195
|
+
|
196
|
+
-s 192.0.2.0/24 -d 198.51.100.10/32 -i eth0 -j ACCEPT
|
197
|
+
|
198
|
+
## Interpolating arrays
|
199
|
+
|
200
|
+
Primitives that are defined as an array, such as `iana_reserved` in the
|
201
|
+
example `primitives.json`, will expand into multiple rules. For instance
|
202
|
+
|
203
|
+
"interpolated": "-s <% iana_reserved %> -j DROP"
|
204
|
+
|
205
|
+
would expand into
|
206
|
+
|
207
|
+
-s 0.0.0.0/8 -j DROP
|
208
|
+
-s 5.0.0.0/8 -j DROP
|
209
|
+
-s 10.0.0.0/8 -j DROP
|
210
|
+
-s 36.0.0.0/7 -j DROP
|
211
|
+
-s 39.0.0.0/8 -j DROP
|
212
|
+
-s 42.0.0.0/8 -j DROP
|
213
|
+
-s 49.0.0.0/8 -j DROP
|
214
|
+
-s 100.0.0.0/6 -j DROP
|
215
|
+
-s 104.0.0.0/7 -j DROP
|
216
|
+
-s 106.0.0.0/8 -j DROP
|
217
|
+
-s 127.0.0.0/8 -j DROP
|
218
|
+
-s 179.0.0.0/8 -j DROP
|
219
|
+
-s 185.0.0.0/8 -j DROP
|
220
|
+
-s 240.0.0.0/4 -j DROP
|
221
|
+
-s 169.254.0.0/16 -j DROP
|
222
|
+
-s 172.16.0.0/12 -j DROP
|
223
|
+
-s 192.0.2.0/24 -j DROP
|
224
|
+
-s 192.88.99.0/24 -j DROP
|
225
|
+
-s 192.168.0.0/16 -j DROP
|
226
|
+
|
227
|
+
|
228
|
+
# `additions` and `node_addition_points`
|
229
|
+
|
230
|
+
Since adding rules to a policy firewall is very common, there is a
|
231
|
+
shorthand for adding rules to one or more policy chains at predefined
|
232
|
+
points.
|
233
|
+
|
234
|
+
For instance, you may define the following policy (see `Rules`):
|
235
|
+
|
236
|
+
"policy": {
|
237
|
+
(other chains)
|
238
|
+
"in_public": {
|
239
|
+
"policy": "ACCEPT",
|
240
|
+
"rules": {
|
241
|
+
{ "comment": "comment1" },
|
242
|
+
{
|
243
|
+
"node_addition_points": [
|
244
|
+
"in_public",
|
245
|
+
"in_*"
|
246
|
+
]
|
247
|
+
}
|
248
|
+
{ "comment": "comment2" },
|
249
|
+
}
|
250
|
+
}
|
251
|
+
}
|
252
|
+
|
253
|
+
You may then also choose to define the following rules:
|
254
|
+
|
255
|
+
"rules": {
|
256
|
+
"filter": {
|
257
|
+
"in_public": {
|
258
|
+
"additions": [
|
259
|
+
"comment": "public"
|
260
|
+
]
|
261
|
+
},
|
262
|
+
"in_*": {
|
263
|
+
"additions": [
|
264
|
+
"comment": "all"
|
265
|
+
]
|
266
|
+
}
|
267
|
+
}
|
268
|
+
}
|
269
|
+
|
270
|
+
The `rules` defined within the `in_public` chain or `in_*`
|
271
|
+
pseudo-chain would be added at the `node_addition_points` within the
|
272
|
+
table. So the generated firewall would contain:
|
273
|
+
|
274
|
+
-A in_public -m comment --comment "comment1"
|
275
|
+
-A in_public -m comment --comment "public"
|
276
|
+
-A in_public -m comment --comment "all"
|
277
|
+
-A in_public -m comment --comment "comment2"
|
278
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Library of Congress
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
Description
|
2
|
+
===========
|
3
|
+
|
4
|
+
Iptables-gem is a Ruby API for parsing, generating, and comparing Linux
|
5
|
+
iptables rules. It is configured using JSON and oriented toward use
|
6
|
+
within configuration-management software such as
|
7
|
+
[http://www.opscode.com/chef/](Chef).
|
8
|
+
|
9
|
+
Requirements
|
10
|
+
============
|
11
|
+
|
12
|
+
## Ruby:
|
13
|
+
|
14
|
+
* Ruby: 1.8
|
15
|
+
* Likely also works on 1.9, but testing is giving me fits so I am ignoring it for now
|
16
|
+
|
17
|
+
## Platforms:
|
18
|
+
|
19
|
+
The following platforms and versions are tested:
|
20
|
+
|
21
|
+
* Ubuntu 10.04, 12.04
|
22
|
+
* CentOS 6.4, Red Hat 6.4
|
23
|
+
|
24
|
+
Ruby Usage
|
25
|
+
==========
|
26
|
+
|
27
|
+
Install this gem and `require iptables`. In the examples below,
|
28
|
+
`/path/to/json/` refers to the directory containing JSON policy files.
|
29
|
+
See [Generate.md](the firewall generation documentation) for information
|
30
|
+
on setting these up. There are also example configuration files in
|
31
|
+
`examples/policy/*.json`.
|
32
|
+
|
33
|
+
## Generate a firewall
|
34
|
+
|
35
|
+
You will first need to create JSON firewall configuration files. See the
|
36
|
+
`Generating a Firewall` section below for details. Once this is done,
|
37
|
+
you can generate a firewall like so:
|
38
|
+
|
39
|
+
config = IPTables::Configuration.new
|
40
|
+
config.parse_files('/path/to/json/')
|
41
|
+
policy_fw = config.converge_firewall
|
42
|
+
puts policy_fw.as_array
|
43
|
+
|
44
|
+
## Compare two firewalls
|
45
|
+
|
46
|
+
You can determine whether a proposed/policy firewall and the
|
47
|
+
currently-applied firewall are identical:
|
48
|
+
|
49
|
+
config = IPTables::Configuration.new
|
50
|
+
config.parse_files('/path/to/json/')
|
51
|
+
policy_fw = config.converge_firewall
|
52
|
+
active_fw = IPTables::Tables.new(%x/iptables-save/)
|
53
|
+
comparison = IPTables::TablesComparison.new(active_fw, policy_fw)
|
54
|
+
comparison.equal?
|
55
|
+
|
56
|
+
Alternately, you can compare firewalls using only `iptables-save` output:
|
57
|
+
|
58
|
+
active_fw = IPTables::Tables.new(%x/iptables-save/)
|
59
|
+
other_fw = IPTables::Tables.new(File.readlines('/path/to/another/saved/firewall'))
|
60
|
+
comparison = IPTables::TablesComparison.new(active_fw, policy_fw)
|
61
|
+
comparison.equal?
|
62
|
+
|
63
|
+
If two firewalls are the same **except** for embedded firewall comments,
|
64
|
+
you can ignore comments:
|
65
|
+
|
66
|
+
comparison.ignore_comments
|
67
|
+
comparison.equal?
|
68
|
+
|
69
|
+
If you want to see **exactly** how two firewalls differ:
|
70
|
+
|
71
|
+
comparison.as_array
|
72
|
+
|
73
|
+
## Log
|
74
|
+
|
75
|
+
If you want to see debug messages, turn on logging:
|
76
|
+
|
77
|
+
require 'logger'
|
78
|
+
$log = Logger.new(STDOUT)
|
79
|
+
$log.level = Logger::DEBUG
|
80
|
+
config = IPTables::Configuration.new
|
81
|
+
config.parse_files('/path/to/json/')
|
82
|
+
policy_fw = config.converge_firewall
|
83
|
+
|
84
|
+
Generating a Firewall
|
85
|
+
=====================
|
86
|
+
|
87
|
+
An explanation of generating a firewall can be found within
|
88
|
+
[Generate.md](the firewall generation documentation). An example set of
|
89
|
+
configuration files to create a basic working firewall can be found in
|
90
|
+
`examples/policy/*.json`.
|
91
|
+
|
92
|
+
Included Scripts
|
93
|
+
================
|
94
|
+
|
95
|
+
## Nagios
|
96
|
+
|
97
|
+
The `bin` directory contains a Nagios helper script written in Ruby to
|
98
|
+
compare the running firewall against a "policy" firewall. To try it from
|
99
|
+
within the gem source directory (that is, without first installing the
|
100
|
+
gem), first copy `examples/policy` to a temporary location and edit the
|
101
|
+
policy files to taste. Then change to the `bin` directory and run:
|
102
|
+
|
103
|
+
`./check_firewall.rb -l=/path/to/iptables/gem/lib/ -v -c=/path/to/policy/`
|
104
|
+
|
105
|
+
The above example includes debugging information which makes it
|
106
|
+
unsuitable for use with Nagios. For "live" use with Nagios, you would
|
107
|
+
want to install this gem and run:
|
108
|
+
|
109
|
+
`check_firewall.rb -c=/path/to/policy/`
|
110
|
+
|
111
|
+
Tests
|
112
|
+
=====
|
113
|
+
|
114
|
+
To run unit tests:
|
115
|
+
|
116
|
+
* change to iptables directory
|
117
|
+
* run `rake`
|
118
|
+
* examine coverage reports in directory `coverage`
|
119
|
+
|
120
|
+
Future
|
121
|
+
======
|
122
|
+
|
123
|
+
Changes/Features I would like to see:
|
124
|
+
|
125
|
+
* Is ipv6 even working?
|
126
|
+
* Write policy in YAML **or** JSON
|
127
|
+
* Deprecate `requires_primitive`: these should be ignored if there is no matching interpolation
|
128
|
+
* Deprecate `interpolated`: these should be properly handled inside **any** kind of rule
|
129
|
+
* Deprecate `comment` and `ulog`? These seem like they ought to be macros.
|
130
|
+
* `ulog` has `-p tcp` but this seems awkward; is it even useful?
|
131
|
+
* Do other stuff like ebtables too? Not sure it's in scope here. Certainly the gem name would need to be reconsidered.
|
132
|
+
* Generate better error messages when we encounter failures parsing configurations.
|
133
|
+
* Move development/testing/coverage environment to Ruby 1.9
|
134
|
+
|
135
|
+
License and Authors
|
136
|
+
===================
|
137
|
+
|
138
|
+
* Author:: Kurt Yoder <kyoder@loc.gov>
|
139
|
+
|
140
|
+
See LICENSE file for project license information.
|