asbestos 0.0.1
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 +15 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/Gemfile +10 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +461 -0
- data/Rakefile +1 -0
- data/asbestos.gemspec +26 -0
- data/bin/asbestos +112 -0
- data/examples/0_simple.rb +5 -0
- data/examples/10_kitchen_sink.rb +72 -0
- data/examples/1_two_hosts.rb +18 -0
- data/examples/2_accept_from_many.rb +19 -0
- data/examples/3_groups.rb +39 -0
- data/examples/4_host_templates.rb +29 -0
- data/examples/5_static_addresses.rb +7 -0
- data/examples/6_interface_addresses.rb +19 -0
- data/examples/7_services.rb +9 -0
- data/examples/8_rule_sets.rb +37 -0
- data/examples/9_literal_commands.rb +8 -0
- data/lib/asbestos.rb +108 -0
- data/lib/asbestos/address.rb +8 -0
- data/lib/asbestos/dsl.rb +40 -0
- data/lib/asbestos/firewalls/iptables.rb +127 -0
- data/lib/asbestos/host.rb +244 -0
- data/lib/asbestos/host_template.rb +15 -0
- data/lib/asbestos/metadata.rb +4 -0
- data/lib/asbestos/rule_set.rb +131 -0
- data/lib/asbestos/rule_sets/accept_from_self.rb +19 -0
- data/lib/asbestos/rule_sets/allow_related_established.rb +5 -0
- data/lib/asbestos/rule_sets/icmp_protection.rb +28 -0
- data/lib/asbestos/rule_sets/sanity_check.rb +41 -0
- data/lib/asbestos/service.rb +86 -0
- data/lib/asbestos/services/chef.rb +4 -0
- data/lib/asbestos/services/cube.rb +14 -0
- data/lib/asbestos/services/http.rb +8 -0
- data/lib/asbestos/services/memcached.rb +4 -0
- data/lib/asbestos/services/mongodb.rb +28 -0
- data/lib/asbestos/services/monit.rb +4 -0
- data/lib/asbestos/services/mysql.rb +4 -0
- data/lib/asbestos/services/nfs.rb +5 -0
- data/lib/asbestos/services/redis.rb +4 -0
- data/lib/asbestos/services/ssh.rb +4 -0
- data/spec/asbestos/address_spec.rb +25 -0
- data/spec/asbestos/firewalls/iptables_spec.rb +179 -0
- data/spec/asbestos/host_spec.rb +173 -0
- data/spec/asbestos/host_template_spec.rb +32 -0
- data/spec/asbestos/rule_set_spec.rb +55 -0
- data/spec/asbestos/service_spec.rb +60 -0
- data/spec/spec_helper.rb +20 -0
- metadata +159 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZDQ2N2U5NmUwMzg1NDdjMTBlNjYxNzM1MjNlY2E3MGM1MTBkNTM3ZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZDVhODYyOGIxMzRmMDcwOGY3ODE4MDExZmU4YWE0OGUwNDg2MzJmNA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MzQ4MjIwOTYxYTFlY2ZmYTk2NjljOWJjZjM3MWJhMmFhZDYwNjE5OWIyMDlh
|
10
|
+
MzAxZTZjMDA1Zjk1Mzg0YzY4M2M5NjRiMDRkMjU3ODRmNzVkZmJhMjUyZmZm
|
11
|
+
NjMxNzEyYjBlMjRkNWRlN2I2Zjg4MGNlZTU3NTUwYjhlN2I1NTE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZWI5MGVlZjY4YjY3YzZmNGExMGE5YzUyN2JiNWI0N2VlMjAxNjBiM2MxNmU4
|
14
|
+
YzJiZjU0ZGU2MzI4ZjYyZWExNDE0NWU1MTY4OWViMjVjMzQ3ZGVhMGE0ZTA3
|
15
|
+
YTRlYTIxYWZhZDY4MDg4ZGExNGY2MDgxMjY0NmMzZDYzMmEzMGU=
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Michael Shapiro
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,461 @@
|
|
1
|
+
# Asbestos
|
2
|
+
|
3
|
+
Asbestos is a mostly-declarative high-level DSL for firewalls. Show Asbestos where your services run and how they connect and it'll generate your firewall rules for you.
|
4
|
+
|
5
|
+
Trying to maintain a set of interconnected firewall rules is pretty annoying, hopefully Asbestos can help.
|
6
|
+
|
7
|
+
At the moment, Asbestos only supports IPTables (the filter table, specifically), but it can be easily expanded for other firewall types.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Simply:
|
12
|
+
|
13
|
+
$ gem install asbestos
|
14
|
+
|
15
|
+
The `asbestos` executable should now be in your PATH.
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
Asbestos is Ruby at heart, you'll need to put your Asbestos configuration in files that end with `.rb`.
|
20
|
+
|
21
|
+
### Quick Start
|
22
|
+
|
23
|
+
Check out the examples in the `examples` directory, generate firewall rules for any of the hosts like so:
|
24
|
+
|
25
|
+
`asbestos rules --host some_hostname_here asbestos_example.rb`
|
26
|
+
|
27
|
+
### (not so) Quick Start
|
28
|
+
|
29
|
+
Let's run through a basic example then expand it out as we go.
|
30
|
+
|
31
|
+
Here's a simple http server, let's call it "app_host":
|
32
|
+
|
33
|
+
```
|
34
|
+
host 'app_host' do
|
35
|
+
runs :ssh
|
36
|
+
runs :http
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
running `asbestos`, that gives us:
|
41
|
+
|
42
|
+
```
|
43
|
+
# Generated by Asbestos at 2013-06-16 20:51:13 UTC for app_host
|
44
|
+
# http://www.github.com/koudelka/asbestos
|
45
|
+
*filter
|
46
|
+
:INPUT ACCEPT [0:0]
|
47
|
+
:OUTPUT ACCEPT [0:0]
|
48
|
+
# Begin [ssh]
|
49
|
+
-A INPUT -j ACCEPT -p tcp -m state --state NEW --dport 22 -m comment --comment "allow ssh(tcp port 22) from anyone"
|
50
|
+
# End [ssh]
|
51
|
+
|
52
|
+
# Begin [http]
|
53
|
+
-A INPUT -j ACCEPT -p tcp -m state --state NEW --dport 80 -m comment --comment "allow http(tcp port 80) from anyone"
|
54
|
+
# End [http]
|
55
|
+
|
56
|
+
-A INPUT -j DROP -m comment --comment "drop packets that haven't been explicitly accepted"
|
57
|
+
COMMIT
|
58
|
+
# Asbestos completed at 2013-06-16 20:51:13 UTC
|
59
|
+
```
|
60
|
+
|
61
|
+
Asbestos has opened tcp port 80 and port 22 to everyone, on all of `app_host`'s interfaces.
|
62
|
+
|
63
|
+
(The rest of the guide excludes the pre/postamble for brevity).
|
64
|
+
|
65
|
+
|
66
|
+
Let's add another host, our app server needs to talk to our database server, which runs MongoDB. The database server should only listen for traffic from `app_host` and nobody else. To do that, we'll need to tell Asbestos a little about our network interfaces, here's `app_host` again with an interface declared.
|
67
|
+
|
68
|
+
```
|
69
|
+
host 'app_host' do
|
70
|
+
interface :internal, :eth0
|
71
|
+
# 'internal' is an arbitrary name, you can make it anything you want
|
72
|
+
|
73
|
+
runs :ssh
|
74
|
+
runs :http
|
75
|
+
end
|
76
|
+
|
77
|
+
host 'db_host' do
|
78
|
+
runs :ssh
|
79
|
+
runs :mongodb, from: { Host['app_host'] => :internal }
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
Here's the rule that Asbestos generates for the `mongodb` service on `db_host`:
|
84
|
+
|
85
|
+
```
|
86
|
+
# Begin [mongodb]
|
87
|
+
-A INPUT -j ACCEPT -p tcp -s app_host_internal -m state --state NEW --dport 27017 -m comment --comment "allow mongodb(tcp port 27017) from app_host:eth0 (internal)"
|
88
|
+
# End [mongodb]
|
89
|
+
```
|
90
|
+
|
91
|
+
You'll notice that Asbestos makes an assumption about the address of `app_host`'s "internal" interface, we'll cover that later (don't worry, you can change it).
|
92
|
+
|
93
|
+
Now `mongodb` is only accepting connections from `app_host`'s internal interface, we can lock it down a little more by requiring that traffic to be through `db_host`'s own internal interface (assuming packets are routable between the two).
|
94
|
+
|
95
|
+
```
|
96
|
+
host 'db_host' do
|
97
|
+
interface :internal, :eth0
|
98
|
+
|
99
|
+
runs :ssh
|
100
|
+
runs :mongodb, on: :internal, from: { Host['app_host'] => :internal }
|
101
|
+
end
|
102
|
+
```
|
103
|
+
|
104
|
+
Asbestos will now give the following more stringent rule for `mongodb` on `db_host`:
|
105
|
+
|
106
|
+
```
|
107
|
+
# Begin [mongodb]
|
108
|
+
-A INPUT -j ACCEPT -i eth0 -p tcp -s app_host_internal -m state --state NEW --dport 27017 -m comment --comment "allow mongodb(tcp port 27017) from app_host:eth0 (internal) on eth0"
|
109
|
+
# End [mongodb]
|
110
|
+
```
|
111
|
+
|
112
|
+
Not only does our app host need to talk to the database, but we've also got a developer that needs to make db dumps, her machine is named `dax`, `mongodb` needs to listen for her connections.
|
113
|
+
|
114
|
+
```
|
115
|
+
host 'dax' do
|
116
|
+
interface :internal, :eth0
|
117
|
+
end
|
118
|
+
|
119
|
+
host 'db_host' do
|
120
|
+
interface :internal, :eth0
|
121
|
+
|
122
|
+
runs :ssh
|
123
|
+
runs :mongodb, on: :internal, from: { Host['app_host'] => :internal,
|
124
|
+
Host['dax'] => :internal }
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
Resulting in the additional of a single rule for `dax`.
|
129
|
+
|
130
|
+
```
|
131
|
+
# Begin [mongodb]
|
132
|
+
-A INPUT -j ACCEPT -i eth0 -p tcp -s app_host_internal -m state --state NEW --dport 27017 -m comment --comment "allow mongodb(tcp port 27017) from app_host:eth0 (internal) on eth0"
|
133
|
+
-A INPUT -j ACCEPT -i eth0 -p tcp -s dax_internal -m state --state NEW --dport 27017 -m comment --comment "allow mongodb(tcp port 27017) from dax:eth0 (internal) on eth0"
|
134
|
+
# End [mongodb]
|
135
|
+
```
|
136
|
+
|
137
|
+
#### Groups
|
138
|
+
|
139
|
+
It's pretty unlikely that we'll only have two hosts in our topology, let's add some more hosts and explore how Asbestos' groups work. We'll add a couple app hosts and start using the `group` DSL call.
|
140
|
+
|
141
|
+
```
|
142
|
+
host 'app_host_0' do
|
143
|
+
group :app_hosts
|
144
|
+
|
145
|
+
interface :internal, :eth0
|
146
|
+
|
147
|
+
runs :ssh
|
148
|
+
runs :http
|
149
|
+
end
|
150
|
+
|
151
|
+
host 'app_host_1' do
|
152
|
+
group :app_hosts
|
153
|
+
|
154
|
+
interface :internal, :eth0
|
155
|
+
|
156
|
+
runs :ssh
|
157
|
+
runs :http
|
158
|
+
end
|
159
|
+
|
160
|
+
host 'app_host_2' do
|
161
|
+
group :app_hosts
|
162
|
+
|
163
|
+
interface :internal, :eth0
|
164
|
+
|
165
|
+
runs :ssh
|
166
|
+
runs :http
|
167
|
+
end
|
168
|
+
|
169
|
+
host 'dax' do
|
170
|
+
interface :internal, :eth0
|
171
|
+
end
|
172
|
+
|
173
|
+
host 'db_host' do
|
174
|
+
interface :internal, :eth0
|
175
|
+
|
176
|
+
runs :ssh
|
177
|
+
runs :mongodb, on: :internal, from: { :app_hosts => :internal,
|
178
|
+
Host['dax'] => :internal }
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
Our three app hosts belong to the group called `app_hosts`. Now `mongodb` listens for connections from any host in that group, Asbestos gives the following rules for the `mongodb`:
|
183
|
+
|
184
|
+
```
|
185
|
+
# Begin [mongodb]
|
186
|
+
-A INPUT -j ACCEPT -i eth0 -p tcp -s app_host_0_internal -m state --state NEW --dport 27017 -m comment --comment "allow mongodb(tcp port 27017) from app_host_0:eth0 (internal) on eth0"
|
187
|
+
-A INPUT -j ACCEPT -i eth0 -p tcp -s app_host_1_internal -m state --state NEW --dport 27017 -m comment --comment "allow mongodb(tcp port 27017) from app_host_1:eth0 (internal) on eth0"
|
188
|
+
-A INPUT -j ACCEPT -i eth0 -p tcp -s app_host_2_internal -m state --state NEW --dport 27017 -m comment --comment "allow mongodb(tcp port 27017) from app_host_2:eth0 (internal) on eth0"
|
189
|
+
-A INPUT -j ACCEPT -i eth0 -p tcp -s dax_internal -m state --state NEW --dport 27017 -m comment --comment "allow mongodb(tcp port 27017) from dax:eth0 (internal) on eth0"
|
190
|
+
# End [mongodb]
|
191
|
+
```
|
192
|
+
|
193
|
+
### Host Templates
|
194
|
+
So we've got groups now, but wrangling more than a couple machines with common attributes is pretty ungainly, let's DRY up the app hosts with a `host_template` and a little Ruby.
|
195
|
+
|
196
|
+
```
|
197
|
+
host_template 'app_host' do
|
198
|
+
group :app_hosts
|
199
|
+
|
200
|
+
interface :internal, :eth0
|
201
|
+
|
202
|
+
runs :ssh
|
203
|
+
runs :http
|
204
|
+
end
|
205
|
+
|
206
|
+
0.upto(2) do |i|
|
207
|
+
app_host "app_host_#{i}"
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
host 'dax' do
|
212
|
+
interface :internal, :eth0
|
213
|
+
end
|
214
|
+
|
215
|
+
host 'db_host' do
|
216
|
+
interface :internal, :eth0
|
217
|
+
|
218
|
+
runs :ssh
|
219
|
+
runs :mongodb, on: :internal, from: { :app_hosts => :internal,
|
220
|
+
Host['dax'] => :internal }
|
221
|
+
end
|
222
|
+
```
|
223
|
+
|
224
|
+
The `host_template` DSL call has created a new `app_host` DSL call for us, it's just like the `host` DSL call. You can pass these custom hosts blocks to extend them further than their template, too:
|
225
|
+
|
226
|
+
```
|
227
|
+
app_host 'app_host_3' do
|
228
|
+
runs :nfs
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
### Arbitrary Addresses
|
233
|
+
|
234
|
+
Sometimes you need to allow traffic from external addresses, you could do that with a `host` entity, but that's a lot of overhead to get a simple address into the mix. To make it dead simple, Asbestos provides the `address` DSL call to maintain a list of named addresses.
|
235
|
+
|
236
|
+
```
|
237
|
+
address :load_balancers, ['lb0.myprovider.com', 'lb1.myprovider.com']
|
238
|
+
address :monitoring, 'pinger.monitoringservice.com'
|
239
|
+
|
240
|
+
host 'app_host' do
|
241
|
+
runs :http, from: [:load_balancers, :monitoring]
|
242
|
+
end
|
243
|
+
```
|
244
|
+
|
245
|
+
Results in:
|
246
|
+
|
247
|
+
```
|
248
|
+
# Begin [http]
|
249
|
+
-A INPUT -j ACCEPT -p tcp -s lb0.myprovider.com -m state --state NEW --dport 80 -m comment --comment "allow http(tcp port 80) from lb0.myprovider.com"
|
250
|
+
-A INPUT -j ACCEPT -p tcp -s lb1.myprovider.com -m state --state NEW --dport 80 -m comment --comment "allow http(tcp port 80) from lb1.myprovider.com"
|
251
|
+
-A INPUT -j ACCEPT -p tcp -s pinger.monitoringservice.com -m state --state NEW --dport 80 -m comment --comment "allow http(tcp port 80) from pinger.monitoringservice.com"
|
252
|
+
# End [http]
|
253
|
+
```
|
254
|
+
|
255
|
+
### Interface Addresses
|
256
|
+
|
257
|
+
By default, Asbestos sets interface addresses to sensible defaults, like so:
|
258
|
+
|
259
|
+
```
|
260
|
+
host 'kira' do
|
261
|
+
interface :external, :eth0 #=> address is "kira_external"
|
262
|
+
|
263
|
+
interface :dmz, [:eth1, :eth2] #=> addresses are "kira_dmz_eth1" and "kira_dmz_eth2"
|
264
|
+
end
|
265
|
+
```
|
266
|
+
|
267
|
+
You're more than welcome to override Asbestos' defaults:
|
268
|
+
|
269
|
+
```
|
270
|
+
host 'kira' do
|
271
|
+
group :developers
|
272
|
+
|
273
|
+
interface :external, :eth3 do |host|
|
274
|
+
[host.group, host.name, 'foo'].join('_')
|
275
|
+
end
|
276
|
+
#=> address is "developers_kira_foo"
|
277
|
+
|
278
|
+
interface :internal, :eth4, 'bar' #=> address is "bar"
|
279
|
+
end
|
280
|
+
```
|
281
|
+
|
282
|
+
Of course, these addresses will need to be resolvable by the hosts executng the rules (via DNS or `/etc/hosts`).
|
283
|
+
|
284
|
+
### Services
|
285
|
+
|
286
|
+
For the most part, Services are simply defined as a set of port numbers (or names, via `/etc/services`), like so:
|
287
|
+
|
288
|
+
```
|
289
|
+
service :nfs do
|
290
|
+
ports :nfs, :sunrpc
|
291
|
+
protocols :tcp, :udp
|
292
|
+
end
|
293
|
+
|
294
|
+
host 'myhost' do
|
295
|
+
runs :nfs
|
296
|
+
end
|
297
|
+
```
|
298
|
+
|
299
|
+
Results in:
|
300
|
+
|
301
|
+
```
|
302
|
+
# Begin [nfs]
|
303
|
+
-A INPUT -j ACCEPT -p udp -m state --state NEW --dport nfs -m comment --comment "allow nfs(udp port nfs) from anyone"
|
304
|
+
-A INPUT -j ACCEPT -p udp -m state --state NEW --dport sunrpc -m comment --comment "allow nfs(udp port sunrpc) from anyone"
|
305
|
+
-A INPUT -j ACCEPT -p tcp -m state --state NEW --dport nfs -m comment --comment "allow nfs(tcp port nfs) from anyone"
|
306
|
+
-A INPUT -j ACCEPT -p tcp -m state --state NEW --dport sunrpc -m comment --comment "allow nfs(tcp port sunrpc) from anyone"
|
307
|
+
# End [nfs]
|
308
|
+
```
|
309
|
+
|
310
|
+
Asbestos comes with a small set of service definitions, located in `lib/asbestos/services`.
|
311
|
+
|
312
|
+
|
313
|
+
### RuleSets
|
314
|
+
|
315
|
+
Simply opening ports between hosts is usually not sufficient for most needs, that's where `RuleSets` come in. `RuleSets` are named chunks of Asbestos/Ruby that are executed in the context of the host. They can easily expose lower level firewall functionality in a clean way. For example, the included `icmp_protection` ruleset:
|
316
|
+
|
317
|
+
```
|
318
|
+
rule_set :icmp_protection do
|
319
|
+
|
320
|
+
accept :chain => :output,
|
321
|
+
:protocol => :icmp,
|
322
|
+
:icmp_type => 'echo-request',
|
323
|
+
:comment => "allow us to ping others"
|
324
|
+
|
325
|
+
accept :protocol => :icmp,
|
326
|
+
:icmp_type => 'echo-reply',
|
327
|
+
:comment => "allow us to receive ping responses"
|
328
|
+
|
329
|
+
|
330
|
+
interfaces[:external].each do |interface|
|
331
|
+
from_each_address(allowed_from) do |address|
|
332
|
+
accept :protocol => :icmp,
|
333
|
+
:icmp_type => 'echo-request',
|
334
|
+
:interface => interface,
|
335
|
+
:remote_address => address,
|
336
|
+
:limit => '22s',
|
337
|
+
:comment => "allow icmp from #{address}"
|
338
|
+
end
|
339
|
+
|
340
|
+
drop :protocol => :icmp,
|
341
|
+
:interface => interface,
|
342
|
+
:comment => "drop any icmp packets that haven't been explicitly allowed"
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
address :monitoring, 'pinger.monitoringservice.com'
|
347
|
+
|
348
|
+
host 'kira' do
|
349
|
+
interface :external, ['eth1', 'eth1:0']
|
350
|
+
|
351
|
+
icmp_protection allowed_from: :monitoring
|
352
|
+
end
|
353
|
+
|
354
|
+
```
|
355
|
+
|
356
|
+
Results in:
|
357
|
+
|
358
|
+
```
|
359
|
+
# Begin [icmp_protection]
|
360
|
+
-A OUTPUT -j ACCEPT -p icmp --icmp-type echo-request -m comment --comment "allow us to ping others"
|
361
|
+
-A INPUT -j ACCEPT -p icmp --icmp-type echo-reply -m comment --comment "allow us to receive ping responses"
|
362
|
+
-A INPUT -j ACCEPT -i eth1 -p icmp -s pinger.monitoringservice.com -m limit --limit 22s --icmp-type echo-request -m comment --comment "allow icmp from pinger.monitoringservice.com on eth1"
|
363
|
+
-A INPUT -j DROP -i eth1 -p icmp -m comment --comment "drop any icmp packets that haven't been explicitly allowed on eth1"
|
364
|
+
-A INPUT -j ACCEPT -i eth1:0 -p icmp -s pinger.monitoringservice.com -m limit --limit 22s --icmp-type echo-request -m comment --comment "allow icmp from pinger.monitoringservice.com on eth1:0"
|
365
|
+
-A INPUT -j DROP -i eth1:0 -p icmp -m comment --comment "drop any icmp packets that haven't been explicitly allowed on eth1:0"
|
366
|
+
# End [icmp_protection]
|
367
|
+
```
|
368
|
+
|
369
|
+
The functions available to RuleSets are translated to firewall rules by the appropriate firewall module, just `lib/asbestos/firewalls/iptables.rb` for now.
|
370
|
+
|
371
|
+
Asbestos comes with a small number of rule sets , located in `lib/asbestos/rule_sets`.
|
372
|
+
|
373
|
+
### Overriding Defaults
|
374
|
+
|
375
|
+
`Services` and `RuleSets` are akin to classes, when a host includes them, a new instance is created. The arguments of any method sent to them (that isn't a firewall module method) get stored as an attribute of the instance and become accessible as a DSL method, this makes `RulesSets` and `Services` easy to write in a DSL-y manner. For example, the `allowed_from` attribute in the `icmp_protection` example above, or the `port` attribute below:
|
376
|
+
|
377
|
+
```
|
378
|
+
host 'kira' do
|
379
|
+
runs :ssh, port: 22022
|
380
|
+
end
|
381
|
+
```
|
382
|
+
|
383
|
+
becomes:
|
384
|
+
|
385
|
+
```
|
386
|
+
# Begin [ssh]
|
387
|
+
-A INPUT -j ACCEPT -p tcp -m state --state NEW --dport 22022 -m comment --comment "allow ssh(tcp port 22022) from anyone"
|
388
|
+
# End [ssh]
|
389
|
+
```
|
390
|
+
|
391
|
+
### Literal Commands
|
392
|
+
|
393
|
+
If you just want to add a literal firewall command, you can use the `command` DSL call inside of a `rule_set`:
|
394
|
+
|
395
|
+
```
|
396
|
+
rule_set :creates_chaos do
|
397
|
+
command "-A INPUT -m statistic --mode random --probability 0.01 -j REJECT --reject-with host-unreach"
|
398
|
+
end
|
399
|
+
|
400
|
+
host 'kira' do
|
401
|
+
creates_chaos
|
402
|
+
end
|
403
|
+
```
|
404
|
+
|
405
|
+
as expected, will give you:
|
406
|
+
|
407
|
+
```
|
408
|
+
# Begin [creates_chaos]
|
409
|
+
-A INPUT -m statistic --mode random --probability 0.01 -j REJECT --reject-with host-unreach
|
410
|
+
# End [creates_chaos]
|
411
|
+
```
|
412
|
+
|
413
|
+
If you find yourself needing to use `command`, please consider expanding the functionality of `Asbestos::Firewall::IPTables#rule` instead.
|
414
|
+
|
415
|
+
### Generating Rules
|
416
|
+
|
417
|
+
**Development**
|
418
|
+
|
419
|
+
While you're developing your rules, you can generate the rules for an arbitrary host like so:
|
420
|
+
|
421
|
+
`asbestos rules --host some_hostname_here asbestos_example.rb`
|
422
|
+
|
423
|
+
**Production**
|
424
|
+
|
425
|
+
When you're ready to run your rules against your hosts, you'll need to send the rules from `asbestos`'s stdout somewhere. You can pipe it directly to `iptables-restore`:
|
426
|
+
|
427
|
+
`asbestos rules asbestos_example.rb | iptables-restore`
|
428
|
+
|
429
|
+
(Calling the `asbestos` executable without `--host` will generate the corresponding rules for the current host)
|
430
|
+
|
431
|
+
However, I suggest you send the rules to a file somewhere in `/etc` and have your `if-up` process automatically apply them when the interface is brought up. Your flavor of linux may already have this mechanism built-in, try looking in `/etc/network/if-up.d`.
|
432
|
+
|
433
|
+
The `asbestos` executable can output your firewall rules on both stdout and stderr, with a slight difference, the rules that are printed on stderr contain line numbers. If there's a problem with your rules, `iptables-restore` will give you the line number of the error. To turn on the stderr output, use the `--debug-stderr` flag. You use this flag to pipe stdout directly to `iptables-restore` and view the rules in your terminal at the same time:
|
434
|
+
|
435
|
+
`asbestos rules --debug-stderr asbestos_example.rb | iptables-restore`
|
436
|
+
|
437
|
+
|
438
|
+
### Keeping Things Organized
|
439
|
+
|
440
|
+
It's probably a good idea to keep various parts of your Asbestos configuration in different files, it's up to you how you do it.
|
441
|
+
|
442
|
+
You can use Ruby's `require` functionality to assemble your files, or you can provide all the file names to the `asbestos` executable.
|
443
|
+
|
444
|
+
### Caveats
|
445
|
+
|
446
|
+
- As with any framework, you may be sacrificing some degree of low-level control. Asbestos was designed to make firewalls for large networks a little saner, which means a degree of standardization. If you find yourself wishing for more control, try expanding the `#rule` method of the `Asbestos::Firewall::IPTables` module.
|
447
|
+
|
448
|
+
- Of course, you are a fully qualified operator, conversant in your firewall of choice. You'll read all the rules that Asbestos generates before running them on your machines. Shit happens, it's best to give things a once over before making a mistake. :)
|
449
|
+
|
450
|
+
- This is just a tool I built to make my life easier, I hope it helps you too. If you take issue with how Asbestos does things, please drop me a line, I'd love hear your thoughts so we can make a better tool for everyone. The infighting in OSS that comes from hiding behind a computer is not cool, let's be excellent to eachother and do kickass work. :)
|
451
|
+
|
452
|
+
## Contributing
|
453
|
+
|
454
|
+
Hug and a beer for anyone submitting pull requests!
|
455
|
+
|
456
|
+
1. Fork it
|
457
|
+
2. Fix my bugs or add new features with tests (please). :)
|
458
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
459
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
460
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
461
|
+
6. Create new Pull Request
|