unicorn-lockdown 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3ce59cddf9d01567fd8a064530c8d1cc54e45a96eecb54fbacfc376ed73c030
4
- data.tar.gz: 7e52c5cc4e6ed7673e84fdce2b67516284a49409d1e5a5adcc0a489a401f52e6
3
+ metadata.gz: 95a450be80782d592a0b960b2855f27332371039ede4ce5459df32a273985240
4
+ data.tar.gz: 9fb35bc3da1921fb3562bc4f1aa35962e08e628da61c33e14e9beac0b51696e4
5
5
  SHA512:
6
- metadata.gz: 42147643aa1eb541874fc61ef91152800617b91fb69e57f3765d0ea33f372f787a1fa9074eb9eb74400fe2f4ec4f699213875a0ec9446ac08ae6b8f1baad3e08
7
- data.tar.gz: c74fb916793633f0da277b1541cce8d9773a985035b0f36bfef9f545abf28e1c8f38796d0fd18da5525ab49ff2a46e4be428cc25384461e53c8615095b9a1ec9
6
+ metadata.gz: dc4ca6d927ab239a144cc3b3f4f405c03d0280f2e6a1e148f32a8ac416d48eb7ebc898f7b7a7ff09b67863ea0676d0b2b8660e212347fe4466691c000eca591a
7
+ data.tar.gz: 3240933f222409c814dac82049c055cfd183c275e1a998cf2aa10f539d36a1c9dbec5abef32b35f8c5729dc32d9cc87e506e9d4bf6b2a602e026314dc7e3bd70
@@ -0,0 +1,9 @@
1
+ = 0.10.0 (2018-05-21)
2
+
3
+ * Use Mail.eager_autoload! if using the mail gem (jeremyevans)
4
+
5
+ * Add bin files to gemspec (jeremyevans)
6
+
7
+ = 0.9.0 (2018-05-02)
8
+
9
+ * Initial public release
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'etc'
4
+ require 'optparse'
5
+
6
+ def sh(*args)
7
+ puts "Running: #{args.join(' ')}"
8
+ system(*args) || raise("Error while running: #{args.join(' ')}")
9
+ end
10
+
11
+ unicorn = ''
12
+ rackup = ''
13
+ unicorn_file = 'unicorn.conf'
14
+ dir = nil
15
+ user = nil
16
+ new_user_uid = nil
17
+ owner = nil
18
+ owner_uid = nil
19
+ owner_gid = nil
20
+
21
+ options = OptionParser.new do |opts|
22
+ opts.banner = "Usage: unicorn-lockdown-add [options] app_name"
23
+ opts.separator "Options:"
24
+
25
+ opts.on_tail("-h", "-?", "--help", "Show this message") do
26
+ puts opts
27
+ exit
28
+ end
29
+
30
+ opts.on("-c rackup_file", "rackup configuration file") do |v|
31
+ rackup = "rackup_file=#{v}\n"
32
+ end
33
+
34
+ opts.on("-d dir", "application directory name") do |v|
35
+ dir = v
36
+ end
37
+
38
+ opts.on("-f unicorn_file", "unicorn configuration file relative to application directory") do |v|
39
+ unicorn_file = v
40
+ unicorn = "unicorn_conf=#{v}\n"
41
+ end
42
+
43
+ opts.on("-o owner", "operating system application owner") do |v|
44
+ owner = v
45
+ ent = Etc.getpwnam(v)
46
+ owner_uid = ent.uid
47
+ owner_gid = ent.gid
48
+ end
49
+
50
+ opts.on("-u user", "operating system user to run application") do |v|
51
+ user = v
52
+ end
53
+
54
+ opts.on("--uid uid", "user id to use if creating the user when -U is specified") do |v|
55
+ new_user_uid = Integer(v, 10)
56
+ end
57
+ end
58
+ options.parse!
59
+
60
+ app = ARGV.shift
61
+ dir ||= app
62
+ base_dir = dir
63
+
64
+ root_id = 0
65
+ bin_id = 7
66
+ www_id = 67
67
+
68
+ www_root = '/var/www'
69
+ dir = "#{www_root}/#{dir}"
70
+ etc_dir = "#{dir}/etc"
71
+ hosts_file = "#{etc_dir}/hosts"
72
+ resolv_file = "#{etc_dir}/resolv.conf"
73
+ rc_file = "/etc/rc.d/unicorn_#{app.tr('-', '_')}"
74
+ nginx_file = "/etc/nginx/#{app}.conf"
75
+ unicorn_conf_file = "#{dir}/#{unicorn_file}"
76
+ unicorn_log_file = "/var/log/unicorn/#{app}.log"
77
+ nginx_access_log_file = "/var/log/nginx/#{app}.access.log"
78
+ nginx_error_log_file = "/var/log/nginx/#{app}.error.log"
79
+
80
+ # Add application user if it doesn't exist
81
+ if user
82
+ passwd = begin
83
+ Etc.getpwnam(user)
84
+ rescue ArgumentError
85
+ args = ['/usr/sbin/useradd', '-d', '/var/empty', '-g', '=uid', '-G', '_unicorn', '-L', 'daemon', '-s', '/sbin/nologin']
86
+ if new_user_uid
87
+ args << '-u' << new_user_uid.to_s
88
+ end
89
+ args << user
90
+ sh(*args)
91
+ Etc.getpwnam(user)
92
+ end
93
+ app_uid = passwd.uid
94
+ end
95
+
96
+ # Create application directory and chroot directories if they doesn't exist
97
+ [dir, "#{dir}/var", "#{dir}/var/www", "#{dir}/etc", "#{dir}/public"].each do |d|
98
+ unless File.directory?(d)
99
+ puts "Creating #{d}"
100
+ Dir.mkdir(d)
101
+ File.chmod(0755, d)
102
+ File.chown(owner_uid, owner_gid, d) if owner
103
+ end
104
+ end
105
+
106
+ # DRY up file ownership code
107
+ setup_file_owner = lambda do |file|
108
+ File.chmod(0644, file)
109
+ File.chown(owner_uid, owner_gid, file) if owner
110
+ end
111
+
112
+ # Setup symlink to root so that the same paths work both when
113
+ # chrooted and when not chrooted.
114
+ chroot_link = "#{dir}#{dir}"
115
+ unless File.symlink?(chroot_link)
116
+ puts "Creating #{chroot_link}"
117
+ File.symlink('/', chroot_link)
118
+ end
119
+
120
+ # Add /etc/hosts files to chroot
121
+ unless File.file?(hosts_file)
122
+ puts "Creating #{hosts_file}"
123
+ File.binwrite(hosts_file, <<END)
124
+ 127.0.0.1 localhost
125
+ END
126
+ setup_file_owner.call(hosts_file)
127
+ end
128
+
129
+ # Add /etc/resolv.conf files to chroot
130
+ unless File.file?(resolv_file)
131
+ puts "Creating #{resolv_file}"
132
+ File.binwrite(resolv_file, <<END)
133
+ lookup file
134
+ END
135
+ setup_file_owner.call(resolv_file)
136
+ end
137
+
138
+ # Setup unicorn configuration file
139
+ unless File.file?(unicorn_conf_file)
140
+ puts "Creating #{unicorn_conf_file}"
141
+ File.binwrite(unicorn_conf_file, <<END)
142
+ require 'unicorn-lockdown'
143
+
144
+ Unicorn.lockdown(self,
145
+ :app=>#{app.inspect},
146
+ :user=>#{user.inspect}, # Set application user here
147
+ :pledge=>'rpath prot_exec inet unix', # More may be needed
148
+ :email=>'root' # update this with correct email
149
+ )
150
+ END
151
+ setup_file_owner.call(unicorn_conf_file)
152
+ end
153
+
154
+ # Setup /etc/nginx/* file for nginx configuration
155
+ unless File.file?(nginx_file)
156
+ puts "Creating #{nginx_file}"
157
+ File.binwrite(nginx_file, <<END)
158
+ upstream #{app}_unicorn {
159
+ server unix:/sockets/#{app}.sock fail_timeout=0;
160
+ }
161
+ server {
162
+ server_name #{app};
163
+ access_log #{nginx_access_log_file} main;
164
+ error_log #{nginx_error_log_file} warn;
165
+ root #{dir}/public;
166
+ error_page 500 503 /500.html;
167
+ error_page 502 504 /502.html;
168
+ proxy_set_header X-Real-IP $remote_addr;
169
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
170
+ proxy_set_header Host $http_host;
171
+ proxy_redirect off;
172
+ add_header X-Content-Type-Options nosniff;
173
+ add_header X-Frame-Options deny;
174
+ add_header X-XSS-Protection "1; mode=block";
175
+ try_files $uri @#{app}_unicorn;
176
+ location @#{app}_unicorn {
177
+ proxy_pass http://#{app}_unicorn;
178
+ }
179
+ }
180
+ END
181
+
182
+ setup_file_owner.call(nginx_file)
183
+ end
184
+
185
+ # Setup nginx log file
186
+ [nginx_access_log_file, nginx_error_log_file].each do |f|
187
+ unless File.file?(f)
188
+ puts "Creating #{f}"
189
+ File.binwrite(f, '')
190
+ File.chmod(0644, f)
191
+ File.chown(www_id, root_id, f)
192
+ end
193
+ end
194
+
195
+ # Setup unicorn log file
196
+ unless File.file?(unicorn_log_file)
197
+ puts "Creating #{unicorn_log_file}"
198
+ File.binwrite(unicorn_log_file, '')
199
+ File.chmod(0640, unicorn_log_file)
200
+ File.chown(app_uid, app_uid, unicorn_log_file) if app_uid
201
+ end
202
+
203
+ # Setup /etc/rc.d/unicorn_* file for daemon management
204
+ unless File.file?(rc_file)
205
+ puts "Creating #{rc_file}"
206
+ File.binwrite(rc_file, <<END)
207
+ #!/bin/ksh
208
+
209
+ unicorn_app=#{app}
210
+ unicorn_dir=#{dir}
211
+ #{unicorn}#{rackup}
212
+ . /etc/rc.d/rc.unicorn
213
+ END
214
+
215
+ File.chmod(0755, rc_file)
216
+ File.chown(root_id, bin_id, rc_file)
217
+ end
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'etc'
4
+
5
+ def sh(*args)
6
+ puts "Running: #{args.join(' ')}"
7
+ system(*args) || raise("Error while running: #{args.join(' ')}")
8
+ end
9
+
10
+ request_dir = '/var/www/requests'
11
+ socket_dir = '/var/www/sockets'
12
+ unicorn_log_dir = '/var/log/unicorn'
13
+ nginx_log_dir = "/var/log/nginx"
14
+ rc_unicorn_file = '/etc/rc.d/rc.unicorn'
15
+
16
+ unicorn_group = '_unicorn'
17
+ root_id = 0
18
+ daemon_id = 1
19
+ www_id = 67
20
+
21
+ # Add _unicorn group if it doesn't exist
22
+ group = begin
23
+ Etc.getgrnam(unicorn_group)
24
+ rescue ArgumentError
25
+ sh('groupadd', unicorn_group)
26
+ Etc.getgrnam(unicorn_group)
27
+ end
28
+ unicorn_group_id = group.gid
29
+
30
+ # Setup requests directory to hold per-request information for crash notifications
31
+ unless File.directory?(request_dir)
32
+ puts "Creating #{request_dir}"
33
+ Dir.mkdir(request_dir)
34
+ File.chmod(0700, request_dir)
35
+ File.chown(root_id, daemon_id, request_dir)
36
+ end
37
+
38
+ # Setup sockets directory to hold PostgreSQL database connection sockets
39
+ unless File.directory?(socket_dir)
40
+ puts "Creating #{socket_dir}"
41
+ Dir.mkdir(socket_dir)
42
+ File.chmod(0770, socket_dir)
43
+ File.chown(www_id, unicorn_group_id, socket_dir)
44
+ end
45
+
46
+ # Setup log directory to hold unicorn application logs
47
+ unless File.directory?(unicorn_log_dir)
48
+ puts "Creating #{unicorn_log_dir}"
49
+ Dir.mkdir(unicorn_log_dir)
50
+ File.chmod(0755, unicorn_log_dir)
51
+ File.chown(root_id, daemon_id, unicorn_log_dir)
52
+ end
53
+
54
+ # Setup log directory to hold nginx logs
55
+ unless File.directory?(nginx_log_dir)
56
+ puts "Creating #{nginx_log_dir}"
57
+ Dir.mkdir(nginx_log_dir)
58
+ File.chmod(0775, nginx_log_dir)
59
+ File.chown(www_id, root_id, nginx_log_dir)
60
+ end
61
+
62
+ # Setup rc.unicorn file
63
+ unless File.file?(rc_unicorn_file)
64
+ puts "Creating #{rc_unicorn_file}"
65
+ File.binwrite(rc_unicorn_file, File.binread(File.join(File.dirname(__dir__), 'files', 'rc.unicorn')))
66
+ File.chmod(0644, rc_unicorn_file)
67
+ File.chown(root_id, root_id, rc_unicorn_file)
68
+ end
@@ -133,12 +133,10 @@ class << Unicorn
133
133
  # that are probably needed at runtime. This must be done
134
134
  # before chrooting as attempting to load the constants after
135
135
  # chrooting will break things.
136
- #
137
- # This part is the most prone to breakage, as new versions
138
- # of the rack or mail libraries (or new libraries that
139
- # use autoload) could break things, as well as existing
140
- # applications using new features at runtime that were
141
- # not loaded at load time.
136
+
137
+ # Start with rack, which uses autoload for all constants.
138
+ # Most of rack's constants are not used at runtime, this
139
+ # lists the ones most commonly needed.
142
140
  Rack::Multipart
143
141
  Rack::Multipart::Parser
144
142
  Rack::Multipart::Generator
@@ -150,17 +148,13 @@ class << Unicorn
150
148
  Rack::Lint
151
149
  Rack::ShowExceptions
152
150
  end
151
+
152
+ # If using the mail library, eagerly autoload all constants.
153
+ # This costs about 9MB of memory, but the mail gem changes
154
+ # their autoloaded constants on a regular basis, so it's
155
+ # better to be safe than sorry.
153
156
  if defined?(Mail)
154
- Mail::Address
155
- Mail::AddressList
156
- Mail::Parsers::AddressListsParser
157
- Mail::ContentTransferEncodingElement
158
- Mail::ContentDispositionElement
159
- Mail::MessageIdsElement
160
- Mail::MimeVersionElement
161
- Mail::OptionalField
162
- Mail::ContentTypeElement
163
- Mail::SMTP
157
+ Mail.eager_autoload!
164
158
  end
165
159
 
166
160
  # Strip path prefixes from the reloader. This is only
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unicorn-lockdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-02 00:00:00.000000000 Z
11
+ date: 2018-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pledge
@@ -40,12 +40,17 @@ dependencies:
40
40
  version: '0'
41
41
  description:
42
42
  email: code@jeremyevans.net
43
- executables: []
43
+ executables:
44
+ - unicorn-lockdown-add
45
+ - unicorn-lockdown-setup
44
46
  extensions: []
45
47
  extra_rdoc_files: []
46
48
  files:
49
+ - CHANGELOG
47
50
  - MIT-LICENSE
48
51
  - README.rdoc
52
+ - bin/unicorn-lockdown-add
53
+ - bin/unicorn-lockdown-setup
49
54
  - files/rc.unicorn
50
55
  - lib/chrooter.rb
51
56
  - lib/rack/email_exceptions.rb