shutter 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -3,10 +3,8 @@
3
3
  Shutter is a tool that gives system administrators the ability to manage
4
4
  iptables firewall settings through simple lists instead of complex iptables commands, making it
5
5
  easier to define host and service firewall setting with configuration management tools. Please note:
6
- This application currently only works with Red Hat based distributions, as the need arises more
7
- distributions will be added.
8
-
9
- **Note: Shutter server is not yet complete**
6
+ This application is currently only tested with Red Hat based distributions. Ubuntu and Debian should
7
+ work but are not supported.
10
8
 
11
9
  ## Installation
12
10
 
@@ -14,9 +12,11 @@ Instalation is through the gem package management program.
14
12
 
15
13
  $ gem install shutter
16
14
 
17
- ## Upgrading from 0.0.6 to 0.0.7
15
+ ## Upgrading from <= 0.0.7 to 0.1.0
18
16
 
19
- Version 0.0.7 adds forwarding capabilities to shutter. To upgrade the base template and add the new configuration files, use the following command:
17
+ Version 0.0.7 added forwarding capabilities to shutter so the base.ipt changed and needs to be upgraded. Version 0.1.0 was a complete rewrite which fixed multiple
18
+ bugs as well as the problem with the maximum prefix length for iptables logging in base.ipt. Support for ubuntu and debian was added but not tested well and
19
+ requires the iptables-persistant package. To upgrade the base template and add the new configuration files, use the following command:
20
20
 
21
21
  $ shutter --upgrade
22
22
 
@@ -26,7 +26,8 @@ Version 0.0.7 adds forwarding capabilities to shutter. To upgrade the base temp
26
26
 
27
27
  $ gem install shutter
28
28
 
29
- #### Create the initial configuration files.
29
+ #### OPTIONAL: Create the initial configuration files.
30
+ Shutter automatically creates any missing configuration files anytime it is run, but you can create them prior to
30
31
 
31
32
  $ shutter --init
32
33
 
@@ -39,6 +40,7 @@ just make sure you include the appropriate placeholder directives to allow
39
40
  shutter to dynamically fill in the rules. It is possible to leave out any unwanted
40
41
  placeholders. By default the files are will be found in the */etc/shutter.d* directory
41
42
  * **iface.dmz:** Enter any private interfaces that will be unprotected by the firewall. One per line.
43
+ * **iface.forward:** Enter any source and destination interfaces that forwarding will occur.
42
44
  * **ip.allow:** A list of IP addresses and ranges that are allowed to access the 'private' ports
43
45
  * **ip.deny:** A list of IP addresses and ranges that are denied access to both public and private ports.
44
46
  * **ports.private:** A list of ports and protocols that are available to traffic that passes through the AllowIP chain
@@ -50,65 +52,33 @@ access 'on-the-fly'. To work correctly, you configure fail2ban to use the Jail
50
52
  INPUT. The dynamic rules that fail2ban has created in the jail chain remain persistant when
51
53
  shutter is 'restored' or reloaded.
52
54
 
53
- Shutter can also run as a server to recieve requests from clients to populate the ip.allow and ip.deny files from a central location. To use this feature, you will need to generate an encryption key on the system you plan on using as the server by running the command:
54
-
55
- server $ shutter --keygen
56
-
57
- This will create the file validation.pem in the /etc/shutter.d (or the user defined) folder. The validation key can then be distributed to the shutter clients to pull in lists. On the shutter server, you will need to define the available lists in the server.json configuration file. It could look like this:
58
-
59
- {
60
- 'allow_lists': [
61
- 'default.allow',
62
- 'private.allow',
63
- 'public.allow'
64
- ],
65
- 'deny_lists': [
66
- 'default.deny',
67
- 'bastards.deny'
68
- ]
69
- }
70
-
71
- To start the server run:
72
-
73
- server $ shutter --server start
74
-
75
- To stop the server run:
76
-
77
- server $ shutter --server stop
78
-
79
- To restart the server run:
80
-
81
- server $ shutter --server restart
82
-
83
- The first time you run shutter-server, empty files will be created in /etc/shutter.d/lists. Edit the files just like you would the ip.allow and ip.deny files. Make sure you copy the validation.pem file to your client and then on the client run:
84
-
85
- client $ shutter --allow private --remote shutter.example.com
86
-
87
- If the '--allow' is not specified it will grab default.allow file and if the file does not exist on the server it will return an error. In this case, shutter will grab the private.allow file from the remote site and replace ip.allow with the contents if the contents have changed.
88
-
89
- Under the hood: A request is sent out to retrieve the MD5 sum of the file that lives on the server, if the md5sum of the file on the remote server is different than the one that is on the local server, the file is retrieved and updated on the client.
90
-
91
-
92
55
  #### To check your firewall you can run:
93
56
 
94
- client $ shutter --save
57
+ $ shutter --save
95
58
 
96
59
  This command mimics the 'iptables-save' command which prints the rules out to the screen.
97
60
  This does not modify the firewall settings.
98
61
 
99
62
  #### To implement the changes, use:
100
63
 
101
- client $ shutter --restore
64
+ $ shutter --restore
102
65
 
103
66
  This command uses 'iptables-restore' under the hood to update the firewall. You can use the '--persist' option
104
- to make the changes permanent and survive reboots.
105
-
106
- #### Useful environment variables:
107
- **SHUTTER_CONFIG:** Use this variable to set the location to the configuration files.
108
-
109
- **SHUTTER_PERSIST_FILE:** Use this variable to set the location of the 'persist' file. i.e. /etc/sysconfig/iptables (default for Redhat)
110
-
111
- **SHUTTER_MODE:** Sets the mode of operation. Currently only used for testing, but in the future it will include a development mode for increased log output for automated runs
67
+ to make the changes permanent and survive reboots. Persist can optionally take an argument which defines the location of the
68
+ persist file if it is in a non-standard location.
69
+
70
+ #### Command line options
71
+ Usage: shutter [options]
72
+ --init Create the initial configuration files.
73
+ --reinit Rereate the initial configuration files.
74
+ --upgrade Upgrade the configuration files that have changes with a new version.
75
+ -s, --save Output the firewall to stdout. This is the default behavior.
76
+ -r, --restore Restore the firewall through iptables-restore.
77
+ -p, --persist [FILE] Write the firewall to the persistance file. If an argument is given, it will be used as the persistance file
78
+ -d, --dir DIR Set the directory for configuration files. Default is /etc/shutter.d.
79
+ --debug Turn on debugging for extra output.
80
+ -h, --help Display help and exit.
81
+ --version Display version and exit.
112
82
 
113
83
  More documentation to come...
114
84
 
data/bin/shutter CHANGED
@@ -4,8 +4,14 @@ begin
4
4
  require 'rubygems'
5
5
  rescue LoadError
6
6
  end
7
-
8
7
  require 'shutter'
9
- config_path = ENV['SHUTTER_CONFIG'] || "/etc/shutter.d"
10
- ENV['SHUTTER_MODE'] = ENV['SHUTTER_MODE'] || "production"
11
- Shutter::CommandLine.new(config_path).execute
8
+
9
+ os = Shutter::OS.new
10
+ os.validate!
11
+ SHUTTER_PERSIST_FILE = os.persist_file
12
+
13
+ #TODO: Should make these not constant
14
+ #IPTABLES_RESTORE="/sbin/iptables-restore"
15
+ #IPTABLES_SAVE="/sbin/iptables-save"
16
+
17
+ Shutter::CommandLine.new.execute(ARGV)
data/lib/shutter.rb CHANGED
@@ -1,15 +1,9 @@
1
1
  require "shutter/version"
2
2
  require "shutter/content"
3
3
  require "shutter/command_line"
4
+ require "shutter/iptables"
5
+ require "shutter/os"
6
+ require "shutter/files"
4
7
 
5
8
  module Shutter
6
- CONFIG_FILES = %w[
7
- base.ipt
8
- iface.dmz
9
- iface.forward
10
- ip.allow
11
- ip.deny
12
- ports.private
13
- ports.public
14
- ]
15
9
  end
@@ -1,135 +1,117 @@
1
1
  require 'optparse'
2
- require 'shutter/iptables'
3
- require 'shutter/os'
4
2
 
5
3
  module Shutter
6
4
  class CommandLine
5
+ DISPLAY_OPTS_INIT = %q{Create the initial configuration files.}
6
+ DISPLAY_OPTS_REINIT = %q{Rereate the initial configuration files.}
7
+ DISPLAY_OPTS_UPGRADE = %q{Upgrade the configuration files that have changes with a new version.}
8
+ DISPLAY_OPTS_DIR = %q{Set the directory for configuration files. Default is /etc/shutter.d.}
9
+ DISPLAY_OPTS_SAVE = %q{Output the firewall to stdout. This is the default behavior.}
10
+ DISPLAY_OPTS_RESTORE = %q{Restore the firewall through iptables-restore.}
11
+ DISPLAY_OPTS_PERSIST = %q{Write the firewall to the persistance file. If an argument is given, it will be used as the persistance file}
12
+ DISPLAY_OPTS_DEBUG = %q{Turn on debugging for extra output.}
13
+ DISPLAY_OPTS_HELP = %q{Display help and exit.}
14
+ DISPLAY_OPTS_VERSION = %q{Display version and exit.}
15
+
7
16
  def initialize( path = "/etc/shutter.d")
8
- # Currently only available to RedHat variants uless testing
9
- unless ENV['SHUTTER_MODE'] == "testing"
10
- @os = Shutter::OS.new
11
- unless @os.redhat?
12
- puts "Shutter is currently only compatible with RedHat and its variants."
13
- puts "Help make it compatible with others (github.com/rlyon/shutter)"
14
- exit
15
- end
16
- end
17
17
  @config_path = path
18
+ @os = Shutter::OS.new
19
+ end
20
+
21
+ def persist
22
+ @persist ||= false
23
+ end
24
+
25
+ def persist_file
26
+ @persist_file ||= @os.persist_file
27
+ end
28
+
29
+ def command
30
+ @command ||= :save
18
31
  end
19
32
 
20
- def iptables
21
- @iptables ||= Shutter::IPTables::Base.new(@config_path)
33
+ def debug
34
+ @debug ||= false
22
35
  end
23
36
 
24
- def execute
37
+ def config_path
38
+ @config_path ||= "/etc/shutter.d"
39
+ end
40
+
41
+ def firewall
42
+ @firewall ||= Shutter::Firewall::IPTables.new(@config_path)
43
+ end
44
+
45
+ def execute(args, noop=false)
25
46
  options = {}
26
47
  optparse = OptionParser.new do |opts|
27
48
  opts.banner = "Usage: shutter [options]"
28
- options[:command] = :save
29
- opts.on( '--init', 'Create the initial configuration files' ) do
30
- options[:command] = :init
49
+ # Initialize the configuration files
50
+ opts.on( '--init', DISPLAY_OPTS_INIT ) do
51
+ @command = :init
31
52
  end
32
- opts.on( '--reinit', 'Rereate the initial configuration files' ) do
33
- options[:command] = :reinit
53
+ # Recreate the configuration files. Overwrites all changes
54
+ opts.on( '--reinit', DISPLAY_OPTS_REINIT ) do
55
+ @command = :reinit
34
56
  end
35
- opts.on( '--upgrade', 'Rereate the base template to add new features' ) do
36
- options[:command] = :upgrade
57
+ # Upgrade the configuration files that have changes with a new version
58
+ opts.on( '--upgrade', DISPLAY_OPTS_UPGRADE ) do
59
+ @command = :upgrade
37
60
  end
38
- opts.on( '-s', '--save', 'Output the firewall to stdout. (DEFAULT)') do
39
- options[:command] = :save
61
+ # Output the firewall to stdout
62
+ opts.on( '-s', '--save', DISPLAY_OPTS_SAVE) do
63
+ @command = :save
40
64
  end
41
- opts.on( '-r', '--restore', 'Load the firewall through iptables-restore.') do
42
- options[:command] = :restore
65
+ # Restore the firewall through iptables-restore
66
+ opts.on( '-r', '--restore', DISPLAY_OPTS_RESTORE) do
67
+ @command = :restore
43
68
  end
44
- @persist = false
45
- opts.on( '-p', '--persist', 'Make the changes persistant. (with --restore)') do
69
+ # Write the firewall to the persistance file
70
+ opts.on( '-p', "--persist [FILE]", DISPLAY_OPTS_PERSIST) do |file|
46
71
  @persist = true
72
+ @persist_file = file || persist_file
47
73
  end
48
- options[:debug] = false
49
- opts.on( '-d', '--debug', 'Be a bit more chatty') do
50
- options[:debug] = true
51
- end
52
- opts.on_tail( '-h', '--help', 'Display this screen' ) do
53
- puts opts
54
- exit
74
+ # Sets the directory for configuration files
75
+ opts.on( '-d', '--dir DIR', DISPLAY_OPTS_DIR) do |dir|
76
+ @config_path = dir
55
77
  end
56
- opts.on_tail( '--version', "Show the version") do
57
- puts Shutter::VERSION
58
- exit
59
- end
60
- end
61
- optparse.parse!
62
- puts "* Using config path: #{@config_path}" if @debug
63
- puts "* Running command: #{options[:command].to_s}" if @debug
64
- send(options[:command])
65
- end
66
-
67
- def init
68
- create_config_dir
69
- Shutter::CONFIG_FILES.each do |name|
70
- file = "#{@config_path}/#{name}"
71
- unless File.exists?(file)
72
- # puts "Creating: #{file}"
73
- File.open(file, 'w') do |f|
74
- f.write(Shutter.const_get(name.upcase.gsub(/\./, "_")))
75
- end
78
+ # Turn on debugging
79
+ opts.on_tail( '--debug', DISPLAY_OPTS_DEBUG) do
80
+ @debug = true
76
81
  end
77
- end
78
- end
79
-
80
- def reinit
81
- create_config_dir
82
- Shutter::CONFIG_FILES.each do |name|
83
- file = "#{@config_path}/#{name}"
84
- File.open(file, 'w') do |f|
85
- f.write(Shutter.const_get(name.upcase.gsub(/\./, "_")))
82
+ # Display help and exit
83
+ opts.on_tail( '-h', '--help', DISPLAY_OPTS_HELP ) do
84
+ puts opts ; exit
86
85
  end
87
- end
88
- end
89
-
90
- def upgrade
91
- create_config_dir
92
- ["base.ipt", "iface.forward"].each do |name|
93
- file = "#{@config_path}/#{name}"
94
- File.open(file, 'w') do |f|
95
- f.write(Shutter.const_get(name.upcase.gsub(/\./, "_")))
86
+ # Display version and exit
87
+ opts.on_tail( '--version', DISPLAY_OPTS_VERSION) do
88
+ puts Shutter::VERSION ; exit
96
89
  end
97
90
  end
91
+ optparse.parse!(args)
92
+ puts "* Using config path: #{@config_path}" if @debug
93
+ puts "* Running command: #{@command}" if @debug
94
+ puts "* Using persistance file: #{persist_file}" if @debug && persist
95
+ Shutter::Files.create_config_dir(config_path) unless noop
96
+ Shutter::Files.create(config_path)
97
+ run unless noop
98
98
  end
99
99
 
100
- def save
101
- init
102
- @ipt = iptables.generate
103
- puts @ipt
104
- end
105
-
106
- def restore
107
- init
108
- @ipt = iptables.generate
109
- IO.popen("#{Shutter::IPTables::IPTABLES_RESTORE}", "r+") do |iptr|
110
- iptr.puts @ipt ; iptr.close_write
111
- end
112
- persist if @persist
113
- end
114
-
115
- def persist
116
- pfile = ENV['SHUTTER_PERSIST_FILE'] ? ENV['SHUTTER_PERSIST_FILE'] : iptables.persist_file(@os)
117
- File.open(pfile, "w") do |f|
118
- f.write(@ipt)
119
- end
120
- end
121
-
122
- private
123
- def create_config_dir
124
- # Check to see if the path to the config files exist
125
- unless File.directory?(@config_path)
126
- begin
127
- Dir.mkdir(@config_path)
128
- rescue Errno::ENOENT
129
- raise "Could not create the configuration directory. Check to see if the parent directory exists."
130
- end
100
+ def run
101
+ case @command
102
+ when :init
103
+ Shutter::Files.create(config_path)
104
+ when :reinit
105
+ Shutter::Files.create(config_path,true)
106
+ when :upgrade
107
+ Shutter::Files.create(config_path,false,["base.ipt", "iface.forward"])
108
+ when :save
109
+ firewall.save
110
+ when :restore
111
+ firewall.restore
112
+ puts "Writing to #{persist_file}" if persist
113
+ firewall.persist(persist_file) if persist
131
114
  end
132
115
  end
133
-
134
116
  end
135
117
  end
@@ -1,4 +1,14 @@
1
1
  module Shutter
2
+ module Content
3
+ CONFIG_FILES = %w[
4
+ base.ipt
5
+ iface.dmz
6
+ iface.forward
7
+ ip.allow
8
+ ip.deny
9
+ ports.private
10
+ ports.public
11
+ ]
2
12
 
3
13
  BASE_IPT = %q{# Generated by Shutter
4
14
  *filter
@@ -143,7 +153,7 @@ BASE_IPT = %q{# Generated by Shutter
143
153
  # NATing
144
154
  ##################################################################
145
155
  # [RULES:FORWARD]
146
- -A FORWARD ! -d 0.0.0.255/0.0.0.255 -m limit --limit 3/min -j LOG --log-prefix "iptables: Unauthorized Forward:"
156
+ -A FORWARD ! -d 0.0.0.255/0.0.0.255 -m limit --limit 3/min -j LOG --log-prefix "iptables: Bad NAT:"
147
157
  -A FORWARD -j DROP
148
158
 
149
159
  ##################################################################
@@ -163,7 +173,7 @@ COMMIT
163
173
  }
164
174
 
165
175
  IFACE_DMZ = %q{# Generated by Shutter
166
- # iface
176
+ # device
167
177
  # eth0
168
178
  # eth1
169
179
  }
@@ -195,4 +205,41 @@ IFACE_FORWARD = %q{
195
205
  # src iface | dst iface
196
206
  # eth0 eth1
197
207
  }
208
+
209
+ IFACE_DMZ_MOCK = %q{# Generated by Shutter
210
+ # device
211
+ eth0
212
+ eth1
213
+ }
214
+
215
+ IP_ALLOW_MOCK = %q{# Generated by Shutter
216
+ # ipaddr
217
+ # ipaddr/subnet
218
+ 192.168.0.0/16
219
+ 10.0.0.1
220
+ }
221
+
222
+ IP_DENY_MOCK = %q{# Generated by Shutter
223
+ # ipaddr
224
+ # ipaddr/subnet
225
+ 172.31.0.0/24
226
+ 8.9.9.9
227
+ }
228
+
229
+ PORTS_PUBLIC_MOCK = %q{
230
+ # proto port
231
+ 80 tcp
232
+ 443 tcp
233
+ }
234
+
235
+ PORTS_PRIVATE_MOCK = %q{
236
+ # proto port
237
+ 22 tcp
238
+ }
239
+
240
+ IFACE_FORWARD_MOCK = %q{
241
+ # src iface | dst iface
242
+ eth0 eth1
243
+ }
244
+ end
198
245
  end