unicorn-lockdown 0.12.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +30 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +158 -88
- data/bin/unicorn-lockdown-add +1 -223
- data/bin/unicorn-lockdown-setup +1 -67
- data/files/unicorn_lockdown_add.rb +227 -0
- data/files/unicorn_lockdown_setup.rb +74 -0
- data/lib/rack/email_exceptions.rb +6 -1
- data/lib/roda/plugins/pg_disconnect.rb +8 -9
- data/lib/unicorn-lockdown.rb +93 -101
- data/lib/unveiler.rb +42 -0
- metadata +69 -8
- data/lib/chrooter.rb +0 -110
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f0b84f88c8502c942f5b15b50bb7ac6946de87ef31ee14cf96e9d71b569b8a3
|
4
|
+
data.tar.gz: 69d55260a85368464b5dbb0b9b24120eacb3d9f95f07c4be765f8d913b8e7f2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2622fa1ea4b31f117037175273420574269b8f976e905d39a76137aefb4da44e94e13e1ec121db5a9d21fcef901dc3d5fec42434c36d5dd5cc21640d64379131
|
7
|
+
data.tar.gz: 032dbedbb2e5eab750fb10ae6f9ef0cb108fdedac239bf3adead2faa637bddfb8613a1d9a865730d449e2d4d6d334f35bab5b762f5b97bf4e946872ebdbf1d63
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
= 1.1.0 (2022-07-18)
|
2
|
+
|
3
|
+
* Make unveiler still pledge if SimpleCov is loaded, but update pledge promises (jeremyevans)
|
4
|
+
|
5
|
+
* Fix roda pg_disconnect plugin to correctly error if error_handler is already loaded (jeremyevans)
|
6
|
+
|
7
|
+
* Avoid SSL error in newer versions of net/smtp when notifying about worker crashes (jeremyevans)
|
8
|
+
|
9
|
+
* Add flock pledge, needed on Ruby 3.1+ (jeremyevans)
|
10
|
+
|
11
|
+
= 1.0.0 (2020-11-09)
|
12
|
+
|
13
|
+
* Require unicorn-lockdown-add -o and -u options, and require options have arguments (jeremyevans)
|
14
|
+
|
15
|
+
* Switch to starting unicorn master process as application user, drop chroot support, require unveil (jeremyevans)
|
16
|
+
|
17
|
+
* Remove chrooter library (jeremyevans)
|
18
|
+
|
19
|
+
* Add unveiler library for testing pledged/unveiled applications, similar to chrooter but smaller (jeremyevans)
|
20
|
+
|
21
|
+
* Add :master_execpledge option to Unicorn.lockdown, for initial pledge of worker processes (jeremyevans)
|
22
|
+
|
23
|
+
* Add :master_pledge option to Unicorn.lockdown, for pledging the master process (jeremyevans)
|
24
|
+
|
25
|
+
= 0.13.0 (2019-07-09)
|
26
|
+
|
27
|
+
* Add Chrooter.unveil for using unveil in tests (jeremyevans)
|
28
|
+
|
29
|
+
* Support Unicorn.lockdown :unveil and :dev_unveil options for use of unveil instead of chroot (jeremyevans)
|
30
|
+
|
1
31
|
= 0.12.0 (2019-04-29)
|
2
32
|
|
3
33
|
* Do not reference the rack middleware unicorn loads by default if unicorn is set to not load default middleware (jeremyevans)
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,22 +1,20 @@
|
|
1
1
|
= unicorn-lockdown
|
2
2
|
|
3
|
-
unicorn-lockdown is a helper library for running Unicorn on OpenBSD
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
and then runs as the application user (privdrop), then runs pledge to limit
|
13
|
-
the allowed system calls to the minimum required to run the application.
|
3
|
+
unicorn-lockdown is a helper library for running Unicorn on OpenBSD with pledge,
|
4
|
+
unveil, and fork+exec for increased security.
|
5
|
+
|
6
|
+
With unicorn-lockdown, unicorn should be started as the application user, which
|
7
|
+
should be different than the user that owns the application's files. unicorn
|
8
|
+
will pledge the master process, then fork worker processes. The worker
|
9
|
+
processes will re-exec (fork+exec), then load the application, then set unveil
|
10
|
+
to restrict file system access, then pledge to limit the allowed system calls
|
11
|
+
at runtime.
|
14
12
|
|
15
13
|
== Assumptions
|
16
14
|
|
17
|
-
unicorn-lockdown assumes you are using OpenBSD 6.
|
18
|
-
rubyXY-unicorn packages installed, and that
|
19
|
-
the PATH to the appropriate unicornXY executable.
|
15
|
+
unicorn-lockdown assumes you are using OpenBSD 6.6+ with the nginx and
|
16
|
+
<tt>rubyXY-unicorn</tt> and <tt>rubyXY-pledge</tt> packages installed, and that
|
17
|
+
you have a +unicorn+ symlink in the PATH to the appropriate +unicornXY+ executable.
|
20
18
|
|
21
19
|
It also assumes you have a SMTP server listening on localhost port 25 to
|
22
20
|
receive notification emails of worker crashes, if you are notifying for those.
|
@@ -33,14 +31,14 @@ the following as root after reading the file and understanding what it does.
|
|
33
31
|
Briefly, the configuration this uses the following directories:
|
34
32
|
|
35
33
|
/var/www/sockets :: Stores unix sockets that Unicorn listens on and Nginx uses.
|
36
|
-
/var/www/
|
37
|
-
|
34
|
+
/var/www/request-error-info :: Stores temporary files for each request with request info,
|
35
|
+
used for crash notifications
|
38
36
|
/var/log/unicorn :: Stores unicorn log files, one per application
|
39
37
|
/var/log/nginx :: Stores nginx log files, two per application, one for access
|
40
38
|
and one for errors
|
41
39
|
|
42
|
-
This adds a _unicorn group that all
|
43
|
-
|
40
|
+
This adds a _unicorn group that all application users will use as one of their
|
41
|
+
groups, as well as a /etc/rc.d/rc.unicorn file that the application
|
44
42
|
/etc/rc.d/unicorn_* files will use.
|
45
43
|
|
46
44
|
=== unicorn-lockdown-add
|
@@ -48,30 +46,38 @@ group, as well as a /etc/rc.d/rc.unicorn file that the per application
|
|
48
46
|
For each application you want to run with unicorn lockdown, run the following
|
49
47
|
as root, again after reading the file and understanding what it does:
|
50
48
|
|
51
|
-
unicorn-lockdown-add
|
49
|
+
unicorn-lockdown-add -o $owner -u $user $app_name
|
52
50
|
|
53
|
-
Here's
|
51
|
+
Here's the usage:
|
54
52
|
|
55
|
-
Usage: unicorn-lockdown-add [options] app_name
|
53
|
+
Usage: unicorn-lockdown-add -o owner -u user [options] app_name
|
56
54
|
Options:
|
57
|
-
-c
|
58
|
-
-d
|
59
|
-
-f
|
60
|
-
-o
|
61
|
-
-u
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
55
|
+
-c RACKUP_FILE rackup configuration file
|
56
|
+
-d DIR application directory name
|
57
|
+
-f UNICORN_FILE unicorn configuration file relative to application directory
|
58
|
+
-o OWNER operating system application owner
|
59
|
+
-u USER operating system user to run application
|
60
|
+
--uid UID user id to use if creating the user when -U is specified
|
61
|
+
-h, -?, --help Show this message
|
62
|
+
|
63
|
+
The <tt>-o</tt> and <tt>-u</tt> options are required. Default values for other options are:
|
64
|
+
|
65
|
+
<tt>-c</tt> :: None, Unicorn will use <tt>config.ru</tt> by default.
|
66
|
+
<tt>-d</tt> :: Same as +app_name+. The value provided should a relative path under <tt>/var/www</tt>.
|
67
|
+
<tt>-f</tt> :: <tt>unicorn.conf</tt>. This file should be relative to +dir+.
|
68
|
+
<tt>--uid</tt> :: The uid automatically generated by +useradd+.
|
69
|
+
|
70
|
+
The owner <tt>-o</tt> and the user <tt>-u</tt> should be different. The user is the user the
|
71
|
+
application runs as, and should have read-only access to the application directory,
|
72
|
+
other than locations where you want the application user to be able to modify files
|
73
|
+
at runtime. The owner is the user that owns the application directory and can make
|
74
|
+
modifications to the application.
|
69
75
|
|
70
76
|
=== unicorn-lockdown
|
71
77
|
|
72
78
|
unicorn-lockdown is the library required in your unicorn configuration
|
73
79
|
file for the application, to handle configuring unicorn to run the app
|
74
|
-
with
|
80
|
+
with fork+exec, unveil, and pledge.
|
75
81
|
|
76
82
|
When you run unicorn-lockdown-add, it will create the unicorn configuration
|
77
83
|
file for the app if one does not already exist, looking similar to:
|
@@ -80,41 +86,76 @@ file for the app if one does not already exist, looking similar to:
|
|
80
86
|
|
81
87
|
Unicorn.lockdown(self,
|
82
88
|
:app=>"app_name",
|
83
|
-
|
84
|
-
|
85
|
-
:email=>'root'
|
89
|
+
|
90
|
+
# Update this with correct email
|
91
|
+
:email=>'root',
|
92
|
+
|
93
|
+
# More pledges may be needed depending on application
|
94
|
+
:pledge=>'rpath prot_exec inet unix flock',
|
95
|
+
:master_pledge=>'rpath prot_exec cpath wpath inet proc exec',
|
96
|
+
:master_execpledge=>'stdio rpath prot_exec inet unix cpath wpath unveil flock',
|
97
|
+
|
98
|
+
# More unveils may be needed depending on application
|
99
|
+
:unveil=>{
|
100
|
+
'views'=>'r'
|
101
|
+
},
|
102
|
+
:dev_unveil=>{
|
103
|
+
'models'=>'r'
|
104
|
+
},
|
86
105
|
)
|
87
106
|
|
88
107
|
Unicorn.lockdown options:
|
89
108
|
|
90
109
|
:app :: (required) a short string for the name of the application, used
|
91
110
|
for socket/log file names and in notifications
|
92
|
-
:user :: (required) the user to drop privileges to
|
93
|
-
:group :: (optional) the group to use to run the application. On Unicorn
|
94
|
-
5.5.0+, can be an array with two entries, the first used as the
|
95
|
-
process primary group, the second as the owner of the unicorn
|
96
|
-
log files.
|
97
|
-
:pledge :: (optional) a pledge string to limit the allowed system calls
|
98
|
-
after privileges have been dropped
|
99
111
|
:email :: (optional) an email address to use for notifications when the
|
100
112
|
worker process crashes or an unhandled exception is raised by
|
101
113
|
the application or middleware.
|
114
|
+
:pledge :: (required) a pledge string to limit the allowed system calls
|
115
|
+
after privileges have been dropped
|
116
|
+
:master_pledge :: (optional) The string to use when pledging the master process before
|
117
|
+
spawning worker processes
|
118
|
+
:master_execpledge :: (optional) The pledge string for processes spawned by the master
|
119
|
+
process (i.e. worker processes before loading the app)
|
120
|
+
:unveil :: (required) a hash of paths to limit file system access, passed
|
121
|
+
to +Pledge.unveil+.
|
122
|
+
:dev_unveil :: (optional) a hash of paths to limit file system, merged into the :unveil
|
123
|
+
option paths if in the development environment. Useful if you are
|
124
|
+
allowing more access in development, such as access needed
|
125
|
+
for file reloading.
|
102
126
|
|
103
127
|
With this example pledge:
|
104
128
|
|
105
|
-
* rpath is needed to read files
|
129
|
+
* rpath is needed to read files
|
106
130
|
* prot_exec is needed in most cases
|
107
131
|
* unix is needed for the unix socket to nginx
|
108
|
-
* inet is not needed in all cases, but
|
109
|
-
of network access
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
132
|
+
* inet is not needed in all cases, but most applications need some form
|
133
|
+
of network access, and it is needed by default for emailing about
|
134
|
+
exceptions that occur without process crashes. pf (OpenBSD's firewall)
|
135
|
+
should be used to limit access for the application's operating system
|
136
|
+
user to the minimum necessary access needed.
|
137
|
+
* flock is needed in Ruby 3.1+ (not necessarily required in older Ruby versions).
|
138
|
+
|
139
|
+
With this example master pledge:
|
140
|
+
|
141
|
+
* rpath is needed to read files
|
142
|
+
* prot_exec is needed in most cases
|
143
|
+
* cpath and wpath are needed to unlink the request error files
|
144
|
+
* inet is needed to send emails for worker crashes
|
145
|
+
* proc and exec are needed to spawn worker processes
|
146
|
+
|
147
|
+
With this examle master exec pledge:
|
148
|
+
|
149
|
+
* stdio must be added because ruby-pledge doesn't add it automatically
|
150
|
+
to execpromises, and Ruby requires it
|
151
|
+
* rpath, prot_exec, unix, inet are needed for the worker (see above)
|
152
|
+
* cpath and wpath are needed to create the request error files
|
153
|
+
* unveil is needed to restrict file system access
|
154
|
+
|
155
|
+
unicorn-lockdown has specific support for allowing emails to be sent
|
156
|
+
for Unicorn worker crashes (e.g. pledge violations) and unhandled
|
157
|
+
application exceptions (e.g. pledge violations). Additionally,
|
158
|
+
unicorn-lockdown modifies unicorn's process status line in a
|
118
159
|
way that allows it to be controllable via OpenBSD's rcctl program for
|
119
160
|
stopping/starting/reloading/restarting daemons.
|
120
161
|
|
@@ -123,7 +164,12 @@ with the expectation of an Nginx limit of 10MB, such that all client
|
|
123
164
|
requests will be buffered in memory and unicorn will not need to write
|
124
165
|
temporary files to disk. If this limit is not correct for your
|
125
166
|
application, please call client_body_buffer_size after calling
|
126
|
-
Unicorn.lockdown to set an appropriate limit.
|
167
|
+
Unicorn.lockdown to set an appropriate limit. Note that rack still
|
168
|
+
creates temporary files for file uploads by default, you'll need to
|
169
|
+
configure rack to disallow file uploads if your application does not
|
170
|
+
need to accept uploaded files and you don't want file upload attempts
|
171
|
+
to cause pledge violations. With Roda, you can use the
|
172
|
+
disallow_file_uploads plugin to prevent file upload attempts.
|
127
173
|
|
128
174
|
When Unicorn.lockdown is used with the :email option, if the worker
|
129
175
|
process crashes, it will email the address using the contents specified
|
@@ -142,6 +188,8 @@ and then at the top of the route block, do:
|
|
142
188
|
|
143
189
|
if defined?(Unicorn) && Unicorn.respond_to?(:write_request)
|
144
190
|
Unicorn.write_request(error_email_content("Unicorn Worker Process Crash"))
|
191
|
+
# or
|
192
|
+
Unicorn.write_request(error_mail_content("Unicorn Worker Process Crash"))
|
145
193
|
end
|
146
194
|
|
147
195
|
If you don't have useful information in the request file, an email will
|
@@ -153,10 +201,20 @@ underlying problem.
|
|
153
201
|
|
154
202
|
If you are using PostgreSQL as the database for the application, and using
|
155
203
|
unix sockets to connect the application to the database, if the database
|
156
|
-
is restarted, the application will no longer be able to connect to it
|
157
|
-
|
158
|
-
|
159
|
-
|
204
|
+
is restarted, the application will no longer be able to connect to it unless
|
205
|
+
you unveil the path the database socket (stored in /tmp by default). It can
|
206
|
+
be a better approach security wise not to allow this, to prevent the
|
207
|
+
application from being able to establish new database connections with
|
208
|
+
potentially different credentials, as a mitigation in case the server is
|
209
|
+
compromised.
|
210
|
+
|
211
|
+
To allow the application to handle cases where the database is disconnected,
|
212
|
+
such as due to a restart of PostgreSQL, you can kill the worker process if
|
213
|
+
a disconnect error is detected, and have the master process then spawn a new
|
214
|
+
worker.
|
215
|
+
|
216
|
+
The roda-pg_disconnect plugin is a plugin for the roda web toolkit to kill the
|
217
|
+
worker process after handling the connection if it detects the database
|
160
218
|
connection has been lost. This plugin assumes the use of the Sequel database
|
161
219
|
library and postgres adapter with the pg driver.
|
162
220
|
|
@@ -165,51 +223,63 @@ In your Roda application:
|
|
165
223
|
# Sometime before loading the error_handler plugin
|
166
224
|
plugin :pg_disconnect
|
167
225
|
|
226
|
+
To specifically restrict access to the database socket even when access to
|
227
|
+
/tmp is allowed, you can unveil the database socket path with no permissions:
|
228
|
+
|
229
|
+
'/tmp/.s.PGSQL.5432'=>''
|
230
|
+
|
231
|
+
Note that there are potentially other security issues with unveiling access
|
232
|
+
to /tmp beyond granting access to the database server, so it is recommended
|
233
|
+
you do not unveil it. If the application needs a directory for temporary
|
234
|
+
files (e.g. for handling uploaded files with rack), you can set the +TMPDIR+
|
235
|
+
environment variable to an appropriate directory that is writable by the
|
236
|
+
application user and not other users, and most web applications will respect
|
237
|
+
that (assuming they use the tmpfile/tmpdir libraries in the standard library).
|
238
|
+
|
168
239
|
=== rack-email_exceptions
|
169
240
|
|
170
|
-
rack-email_exceptions is a rack middleware designed to
|
171
|
-
middleware
|
241
|
+
rack-email_exceptions is a rack middleware designed to wrap all other
|
242
|
+
middleware and the application. It rescues unhandled exceptions
|
172
243
|
raised by subsequent middleware or the application itself.
|
173
|
-
|
174
244
|
Unicorn.lockdown will automatically setup this middleware if the :email
|
175
|
-
option is used
|
176
|
-
such that it wraps the application and all other middleware.
|
245
|
+
option is used.
|
177
246
|
|
178
247
|
It is possible to use this middleware manually:
|
179
248
|
|
180
249
|
require 'rack/email_exceptions'
|
181
250
|
use Rack::EmailExceptions, "app_name", 'foo@example.com'
|
182
251
|
|
183
|
-
===
|
252
|
+
=== unveiler
|
184
253
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
the application into production, such as a file being read from outside
|
190
|
-
the chroot.
|
254
|
+
unveiler is a library designed to help with testing applications that
|
255
|
+
use pledge and unveil. If you are running your application pledged and
|
256
|
+
unveiled, you want your tests to run pledged and unveiled to find
|
257
|
+
problems.
|
191
258
|
|
192
|
-
|
259
|
+
unveiler assumes you are using minitest for testing. To use unveiler:
|
193
260
|
|
194
261
|
require 'minitest/autorun'
|
195
|
-
require '
|
196
|
-
at_exit
|
197
|
-
|
198
|
-
|
199
|
-
chrooting, but in a way that can still catch some problems that occur
|
200
|
-
when chrooted. If you run your specs as root, it will chroot to
|
201
|
-
the current directory after loading the specs, then drop
|
202
|
-
privileges to the user given (and optionally pledging using the given
|
203
|
-
pledge string), then run the specs.
|
262
|
+
require 'unveiler'
|
263
|
+
at_exit do
|
264
|
+
Unveiler.pledge_and_unveil('rpath prot_exec inet unix', 'views' => 'r')
|
265
|
+
end
|
204
266
|
|
205
267
|
== autoload
|
206
268
|
|
207
|
-
As you'll find out if you try to run your applications with
|
208
|
-
autoload
|
209
|
-
|
210
|
-
If you use other gems that use
|
211
|
-
|
212
|
-
|
269
|
+
As you'll find out if you try to run your applications with unveil,
|
270
|
+
autoload and other forms of runtime requires are the enemy. Both
|
271
|
+
unicorn-lockdown and unveiler have support for handling common autoloaded
|
272
|
+
constants in the rack and mail gems. If you use other gems that use
|
273
|
+
autoload or runtime requires, you'll have to add unveils for the appropriate
|
274
|
+
gems:
|
275
|
+
|
276
|
+
Unicorn.lockdown(self,
|
277
|
+
# ...
|
278
|
+
:unveil=>{
|
279
|
+
'views' => 'r',
|
280
|
+
'gem-name' => :gem,
|
281
|
+
}
|
282
|
+
)
|
213
283
|
|
214
284
|
== Author
|
215
285
|
|
data/bin/unicorn-lockdown-add
CHANGED
@@ -1,224 +1,2 @@
|
|
1
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
|
-
unicorn_conf_dir = File.dirname(unicorn_conf_file)
|
141
|
-
unless File.directory?(unicorn_conf_dir)
|
142
|
-
puts "Creating #{unicorn_conf_dir}"
|
143
|
-
Dir.mkdir(unicorn_conf_dir)
|
144
|
-
File.chmod(0755, unicorn_conf_dir)
|
145
|
-
File.chown(owner_uid, owner_gid, unicorn_conf_dir) if owner
|
146
|
-
end
|
147
|
-
puts "Creating #{unicorn_conf_file}"
|
148
|
-
File.binwrite(unicorn_conf_file, <<END)
|
149
|
-
require 'unicorn-lockdown'
|
150
|
-
|
151
|
-
Unicorn.lockdown(self,
|
152
|
-
:app=>#{app.inspect},
|
153
|
-
:user=>#{user.inspect}, # Set application user here
|
154
|
-
:pledge=>'rpath prot_exec inet unix', # More may be needed
|
155
|
-
:email=>'root' # update this with correct email
|
156
|
-
)
|
157
|
-
END
|
158
|
-
setup_file_owner.call(unicorn_conf_file)
|
159
|
-
end
|
160
|
-
|
161
|
-
# Setup /etc/nginx/* file for nginx configuration
|
162
|
-
unless File.file?(nginx_file)
|
163
|
-
puts "Creating #{nginx_file}"
|
164
|
-
File.binwrite(nginx_file, <<END)
|
165
|
-
upstream #{app}_unicorn {
|
166
|
-
server unix:/sockets/#{app}.sock fail_timeout=0;
|
167
|
-
}
|
168
|
-
server {
|
169
|
-
server_name #{app};
|
170
|
-
access_log #{nginx_access_log_file} main;
|
171
|
-
error_log #{nginx_error_log_file} warn;
|
172
|
-
root #{dir}/public;
|
173
|
-
error_page 500 503 /500.html;
|
174
|
-
error_page 502 504 /502.html;
|
175
|
-
proxy_set_header X-Real-IP $remote_addr;
|
176
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
177
|
-
proxy_set_header Host $http_host;
|
178
|
-
proxy_redirect off;
|
179
|
-
add_header X-Content-Type-Options nosniff;
|
180
|
-
add_header X-Frame-Options deny;
|
181
|
-
add_header X-XSS-Protection "1; mode=block";
|
182
|
-
try_files $uri @#{app}_unicorn;
|
183
|
-
location @#{app}_unicorn {
|
184
|
-
proxy_pass http://#{app}_unicorn;
|
185
|
-
}
|
186
|
-
}
|
187
|
-
END
|
188
|
-
|
189
|
-
setup_file_owner.call(nginx_file)
|
190
|
-
end
|
191
|
-
|
192
|
-
# Setup nginx log file
|
193
|
-
[nginx_access_log_file, nginx_error_log_file].each do |f|
|
194
|
-
unless File.file?(f)
|
195
|
-
puts "Creating #{f}"
|
196
|
-
File.binwrite(f, '')
|
197
|
-
File.chmod(0644, f)
|
198
|
-
File.chown(www_id, root_id, f)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
# Setup unicorn log file
|
203
|
-
unless File.file?(unicorn_log_file)
|
204
|
-
puts "Creating #{unicorn_log_file}"
|
205
|
-
File.binwrite(unicorn_log_file, '')
|
206
|
-
File.chmod(0640, unicorn_log_file)
|
207
|
-
File.chown(app_uid, app_uid, unicorn_log_file) if app_uid
|
208
|
-
end
|
209
|
-
|
210
|
-
# Setup /etc/rc.d/unicorn_* file for daemon management
|
211
|
-
unless File.file?(rc_file)
|
212
|
-
puts "Creating #{rc_file}"
|
213
|
-
File.binwrite(rc_file, <<END)
|
214
|
-
#!/bin/ksh
|
215
|
-
|
216
|
-
unicorn_app=#{app}
|
217
|
-
unicorn_dir=#{dir}
|
218
|
-
#{unicorn}#{rackup}
|
219
|
-
. /etc/rc.d/rc.unicorn
|
220
|
-
END
|
221
|
-
|
222
|
-
File.chmod(0755, rc_file)
|
223
|
-
File.chown(root_id, bin_id, rc_file)
|
224
|
-
end
|
2
|
+
require_relative '../files/unicorn_lockdown_add'
|