@@ -297,11 +297,11 @@
297 297 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
The simplest method is to stop the container if it was running,
298 298 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
then say:
299 299 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
300 300 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
<pre><code> $ docker cp /path/to/my-project.fossil fossil:/jail/museum/repo.fossil
301 301 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
$ docker start fossil
302 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- $ docker exec fossil chown 0 /jail/museum/repo.fossil</code></pre>
302 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ $ docker exec fossil chown -R 499 /jail/museum</code></pre>
303 303 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
304 304 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
That copies the local Fossil repo into the container where the server
305 305 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
expects to find it, so that the "start" command causes it to serve from
306 306 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
that copied-in file instead. Since it lives atop the immutable base layers, it
307 307 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
persists as part of the container proper, surviving restarts.
@@ -315,19 +315,31 @@
315 315 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
<tt>repo.fossil</tt>, which it almost certainly was not out on the host
316 316 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
system. This is because there is only one repository inside this
317 317 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
container, so we don't have to name it after the project it contains, as
318 318 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
is traditional.
319 319 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
320 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- If you skip the following "chown" command and put "http://localhost:9999/" into
320 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ If you skip the "chown" command above and put "http://localhost:9999/" into
321 321 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
your browser, expecting to see the copied-in repo's home page, you will
322 322 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
get an opaque "Not Found" error. This is because the user and
323 323 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
group ID of the file will be that of your local user on the container's
324 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- host machine, which won't map to anything in the container's
324 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ host machine, which is unlikely to map to anything in the container's
325 325 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
<tt>/etc/passwd</tt> and <tt>/etc/group</tt> files, effectively
326 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- preventing the server from reading the copied-in repository file. You
327 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- don't have to restart the server after fixing this with <tt>chmod</tt>: simply reload the
328 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- browser, and Fossil will try again.
326 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ preventing the server from reading the copied-in repository file.
327 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ 499 is the default "fossil" user ID inside the container, causing Fossil to run
328 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with that user's privileges after it enters the chroot.
329 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ You don't have to restart the server after fixing this with
330 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ <tt>chmod</tt>: simply reload the browser, and Fossil will try again.
331 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
332 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ (Why 499? Because regular user IDs start at 500 or 1000 on most Unix
333 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ type systems, leaving those below it for "system" users like this Fossil
334 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ daemon owner; standard OS system users start at 0 and go upward, so we
335 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ started at 500 and went down one to avoid a conflict. If you use Docker
336 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ volumes, you may wish to override this at container creation time — the
337 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "run" or "create" command — by passing an option like "<tt>-e
338 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ UID=501</tt>". The internal container user IDs are used for permissions
339 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ on the volume, where the host's user/group IDs come into play, so
340 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ syncing the in-container user ID with the host can be useful.)
329 341 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
330 342 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
This simple method has a problem: Docker containers are designed to be
331 343 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
killed off at the slightest cause, rebuilt, and redeployed. If you do
332 344 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
that with the repo inside the container, it gets destroyed, too. The
333 345 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
solution is to replace the "run" command above with the following:
@@ -346,16 +358,17 @@
346 358 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
347 359 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
348 360 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
<h3>5.2 Why Chroot?</h3>
349 361 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
350 362 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
A potentially surprising feature of this container is that it runs
351 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- Fossil as root, which causes [./chroot.md | Fossil's chroot jail
352 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- feature] to kick in. Since a Docker container is a type of über-jail
363 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Fossil as root. Since that causes [./chroot.md | Fossil's chroot jail
364 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ feature] to kick in, and a Docker container is a type of über-jail
353 365 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
already, you may be wondering why we don't either:
354 366 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
355 367 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# run <tt>fossil server --nojail</tt> to skip the internal chroot; or
356 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # create a non-root user and force Docker to use that instead
368 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # set "<tt>USER fossil</tt>" in the Dockerfile so it starts Fossil as
369 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ that user instead
357 370 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
358 371 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
The reason is, although this container is quite stripped-down by today's
359 372 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
standards, it's based on the [https://www.busybox.net/BusyBox.html |
360 373 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
surprisingly powerful Busybox project]. (This author made a living for
361 374 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
years in the early 1990s using Unix systems that were less powerful than
@@ -366,10 +379,20 @@
366 379 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
from accessing the Busybox features.
367 380 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
368 381 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
We deem this risk low since a) it's never happened, that we know of;
369 382 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
and b) we've turned off all of the risky features like TH1 docs.
370 383 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
Nevertheless, we believe in defense-in-depth.
384 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
385 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ If you shell into the container and do a <tt>ps</tt>, you'll find
386 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ <tt>fossil</tt> running as <tt>root</tt>. Why? Because that's the parent
387 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ process, which may need to do rootly things like listening on port 80 or
388 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ 443. Fossil's chroot feature takes effect in the child processes forked
389 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ off to handle each HTTP/CGI hit. This is why you can fix broken
390 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ permissions with <tt>chown</tt> after the container is already running,
391 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ without restarting it: each hit reevaluates the repository file
392 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ permissions when deciding what user to become when dropping root
393 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ privileges.
371 394 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
372 395 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
373 396 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
<h3>5.3 Extracting a Static Binary</h3>
374 397 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
375 398 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
Our 2-stage build process uses Alpine Linux only as a build host. Once
376 399 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!