Skip to content

Instantly share code, notes, and snippets.

@ansemjo
Last active April 26, 2016 21:37
Show Gist options
  • Save ansemjo/ab00cd895e1cc155f26580c9ad1f9efd to your computer and use it in GitHub Desktop.
Save ansemjo/ab00cd895e1cc155f26580c9ad1f9efd to your computer and use it in GitHub Desktop.
A script to setup nginx in a mostly read-only jail.
#!/bin/env bash
#
# MIT License
#
# Copyright (c) 2016 Anton Semjonov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# refuse action. hint: $ export variable="value"
test "$ireadthroughthescript" = "yes" || { echo "refusing to do anything. read the script."; exit 1; }
jail="/srv/http"
# jail="$(mktemp -d /tmp/nginx-jail-test-XXXXXX)"
user="$(id -un 33)" # by default uid/gid 33 is the http webserver user
group="$(id -gn 33)"
www_data="var/www" # without leading / !
# output function for bold font
info() { echo -e "\e[1m--> $@\e[0m"; }
# exit on errors
set -e
test "$UID" -eq 0 || info "you'll almost certainly need superuser rights ..."
info 'starting nginx jailer.
_) _) _) |
__ \ _` | | __ \\\ \ / | _` | | | _ \ __|
| | ( | | | |` < | ( | | | __/ |
_| _|\__, |_|_| _|_/\_\ |\__,_|_|_|\___|_|
|___/ ___/
'
info "creating jail in '$jail' for $user:$group"
# create chroot filesystem tree
info "make filetree"
mkdir --verbose --parent $jail/{dev,etc/nginx,run,tmp,usr/{bin,lib},var/{log,lib}/nginx} {$jail,}/$www_data
# create /dev/null,random,urandom
info "create /dev/null, /dev/random and /dev/urandom"
n=({null,0666,3} {random,0666,8} {urandom,0444,9})
for i in 0 3 6; do
mknod --mode=${n[$i+1]} $jail/dev/${n[$i]} c 1 ${n[$i+2]}
done
# symlinks to /usr/lib
info "create symlinks for /usr/lib"
cd $jail; ln --verbose --symbolic {usr/,}lib
uname --machine | grep 'x86_64' >/dev/null &&\
for l in {usr/,}lib64; do ln --verbose --symbolic lib $l; done
# mount tmpfs in /run and /tmp
info "mounting tmpfs"
t=({run,1024k} {tmp,102400k})
for i in 0 2; do
mount --verbose tmpfs $jail/${t[$i]} --type tmpfs --options "noexec,size=${t[$i+1]}"
done
# create some files for binds later on
info "create or touch files for bind mounts"
robinds=$(echo {usr/{bin/nginx,lib},etc/{nginx,hosts,services,localtime,nsswitch.conf,nscd.conf,protocols,ld.so.cache,ld.so.conf,resolv.conf,host.conf}})
rwbinds=$(echo var/{lib,log}/nginx $www_data)
for bindm in $robinds $rwbinds; do
touch $jail/$bindm
ls -d $jail/$bindm
done
# bind files and folders
info "read-only binds:"
for ro in $robinds; do
mount --verbose --bind --read-only /$ro $jail/$ro
done
info "writeable binds:"
for rw in $rwbinds; do
mount --verbose --bind /$rw $jail/$rw
done
# print fstab for persistence
info "mounting and binding complete."
info "use this in your /etc/fstab for persistence:"
fstabtmp="$(mktemp ~/nginx-jail-fstab.tmpXXXX)"
echo "# a copy of this will be saved to $fstabtmp"
grep "$jail" /etc/mtab | tee $fstabtmp
# minimal users and groups db
info "copy minimal users and groups db"
for db in group passwd {,g}shadow; do
echo "## /etc/$db"
grep "$user\|$group\|nobody" /etc/$db | sed "s:\(/srv/http\|/var/www\):/$www_data:" | tee $jail/etc/$db
done
# set some permissions
info "set ownership on writeable (non-tmpfs) binds to $user:$group"
chown -vR $user:$group $jail/{$www_data,var/{log,lib}/nginx}
# check read-writeable mounts and inspect permissions ..
ls -lda $(mount | sed -n "s:.*\($jail.*\) type .* (rw,.*:\1:p")
# ----------------------------------------------------------------
echo
info "finished. printing some useful info:
The jail has been created in ..
$jail
You can unmount & delete everything in this jail with:
# umount --verbose \$(mount | sed -n \"s:.* on \($jail.*\) type.*:\1:p\")
# rm -rf \"$jail\"
Check all permissions manually, especially in the
writeable mounts listed above! More information:
https://wiki.archlinux.org/index.php/nginx#Installation_in_a_chroot
You need to modify your nginx config yourself and populate
your webroot at $www_data.
Test your nginx config from within chroot with
# chroot --userspec=$user:$group $jail /usr/bin/nginx -t
"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment