unicorn-lockdown 0.12.0 → 1.1.0
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 +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'
|