First draft (ish)
authorBrett Parker <iDunno@sommitrealweird.co.uk>
Sat, 21 May 2016 22:04:49 +0000 (23:04 +0100)
committerBrett Parker <iDunno@sommitrealweird.co.uk>
Sat, 21 May 2016 22:04:49 +0000 (23:04 +0100)
templates/lxc-debian-unprivileged [new file with mode: 0755]

diff --git a/templates/lxc-debian-unprivileged b/templates/lxc-debian-unprivileged
new file mode 100755 (executable)
index 0000000..30d4912
--- /dev/null
@@ -0,0 +1,236 @@
+#!/bin/bash
+
+# lxc template for debootstrapping in userns
+
+# Authors:
+# Brett Parker <iDunno@sommitrealweird.co.uk>
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+MAPPED=no
+
+# Only support usage in userns.
+for arg in "$@"; do
+    [ "$arg" = "--" ] && break
+    if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
+        MAPPED=yes
+    fi
+done
+
+if [ "$MAPPED" == "no" ]; then
+    echo "This template can only be used for unprivileged containers." 1>&2
+    echo "You might want the \"debian\" template instead." 1|&2
+fi
+
+# Make sure the usual locations are in PATH
+export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
+export GREP_OPTIONS=""
+
+usage() {
+    cat <<EOF
+LXC debootstrap in user namespace for unprivileged containers
+
+Special arguments:
+[ -h | --help ]: Print this help message and exit.
+
+Required arguments:
+[ -r | --release <release> ]: The debian release, e.g. jessie or stretch.
+
+Optional arguments:
+[ -m | --mirror <mirrorurl> ]: The debian mirror to user
+EOF
+    return 0
+}
+
+options=$(getopt -o r:m:h -l release:,mirror:,help,mapped-uid:,mapped-gid:,name:,path:,rootfs: -- "$@")
+
+if [ $? -ne 0 ]; then
+    usage
+    exit 1
+fi
+
+eval set -- "$options"
+
+DEBIAN_MIRROR="http://mirror.mythic-beasts.com/debian/"
+DEBIAN_RELEASE="jessie"
+
+while :; do
+    case "$1" in
+        -h|--help)      usage && exit 1;;
+        -r|--release)   DEBIAN_RELEASE=$2; shift 2;;
+        -m|--mirror)    DEBIAN_MIRROR=$2; shift 2;;
+        --mapped-uid)   MAPPED_UID=$2; shift 2;;
+        --mapped-gid)   MAPPED_GID=$2; shift 2;;
+        --name)         LXC_NAME=$2; shift 2;;
+        --path)         LXC_PATH=$2; shift 2;;
+        --rootfs)       LXC_ROOTFS=$2; shift 2;;
+        *)              break;;
+    esac
+done
+
+echo "Mapped UID: $MAPPED_UID"
+echo "Mapped GID: $MAPPED_GID"
+echo "RootFS: $LXC_ROOTFS"
+echo "Name: $LXC_NAME"
+echo "Path: $LXC_PATH"
+
+# rewrite the default config file
+
+sed -i -e "/lxc./{w ${LXC_PATH}/config-auto" -e "d}" ${LXC_PATH}/config
+sed -i -e '4,$d' ${LXC_PATH}/config
+
+cat <<EOF >> ${LXC_PATH}/config
+
+# Useful includes
+lxc.include = /usr/share/lxc/config/debian.common.conf
+lxc.include = /usr/share/lxc/config/debian.userns.conf
+
+# Set our hostname
+lxc.utsname = $LXC_NAME
+
+# Automatic configuration
+EOF
+
+# add back in the auto foo
+cat "${LXC_PATH}/config-auto" >> ${LXC_PATH}/config
+rm ${LXC_PATH}/config-auto
+
+mkdir ${LXC_PATH}/bin
+cat <<EOF > ${LXC_PATH}/bin/mknod
+#!/bin/sh
+
+exec touch "\$1"
+EOF
+
+chmod 755 ${LXC_PATH}/bin/mknod
+
+export PATH=${LXC_PATH}/bin:$PATH
+
+debootstrap --foreign --include debian-archive-keyring,ifupdown,isc-dhcp-client,locales $DEBIAN_RELEASE ${LXC_ROOTFS} $DEBIAN_MIRROR
+
+# now totally skip that check in the new root, because it sucks.
+sed -i -e 's#check_sane_mount () {#check_sane_mount () {\n\treturn 0#;' ${LXC_ROOTFS}/debootstrap/functions
+
+# and stop it from bothering to try to setup proc
+sed -i -e 's#setup_proc () {#setup_proc () {\n\treturn 0#;' ${LXC_ROOTFS}/debootstrap/functions
+
+keyring_dpkg=$(sed -ne "/^debian-archive-keyring/ { s#.* ##; p; }" ${LXC_ROOTFS}/debootstrap/debpaths)
+# and unpack debian-archive-keyring, because we'll need that
+(cd ${LXC_ROOTFS} && dpkg-deb -x .$keyring_dpkg .)
+
+# replace the tar containing devices with something that doesn't contain any
+(cd $LXC_ROOTFS/debootstrap && rm devices.tar.gz && tar czvf devices.tar.gz --files-from=/dev/null)
+
+# and mount a shitload of things for fun and profit...
+for file in /var/lib/lxcfs/proc/*; do
+    fname=$(basename $file)
+    touch ${LXC_ROOTFS}/proc/$fname
+    mount -n -o bind $file ${LXC_ROOTFS}/proc/$fname
+done
+
+for dev in random urandom; do
+    touch ${LXC_ROOTFS}/dev/$dev
+    mount -n -o bind /dev/$dev ${LXC_ROOTFS}/dev/$dev
+done
+
+# set /proc/cmdline to something silly
+echo "debootstrapping - hahaha" > ${LXC_ROOTFS}/proc/cmdline
+
+# and disable initscripts
+cat <<EOF > ${LXC_ROOTFS}/usr/sbin/policy-rc.d
+#!/bin/sh
+
+exit 101
+EOF
+
+# and run the second stage
+chroot ${LXC_ROOTFS} /debootstrap/debootstrap --second-stage
+
+# configure locales
+lang=en_GB.UTF-8
+enc=UTF-8
+if [ ! -z "$LANG" ]; then
+    lang=${LANG}
+    enc=${LANG#*.}
+fi
+
+cat >> ${LXC_ROOTFS}/etc/locale.gen <<EOF
+$lang $enc
+EOF
+
+chroot ${LXC_ROOTFS} /usr/sbin/locale-gen $lang $enc
+chroot ${LXC_ROOTFS} /usr/sbin/update-locale LANG=$LANG
+
+# configure timezone
+if [ -f /etc/timezone ]; then
+    cat /etc/timezone > ${LXC_ROOTFS}/etc/timezone
+elif [ -f /etc/sysconfig/clock ]; then
+    . /etc/sysconfig/clock
+    echo $ZONE > ${LXC_ROOTFS}/etc/timezone
+fi
+chroot ${LXC_ROOTFS} dpkg-reconfigure -f noninteractive tzdata
+
+# "setup" networking
+NETWORK_FILE=/etc/network/interfaces
+if [ -e ${LXC_ROOTFS}/etc/network/interfaces.d ]; then
+    NETWORK_FILE=/etc/network/interfaces.d/eth0
+fi
+
+# setup sources.list
+cat <<EOF > ${LXC_ROOTFS}/etc/apt/sources.list
+deb $DEBIAN_MIRROR $DEBIAN_RELEASE main
+deb http://security.debian.org/ $DEBIAN_RELEASE/update main
+EOF
+
+# disable bits of systemd that we hates
+chroot $LXC_ROOTFS /usr/sbin/update-rc.d -f checkroot.sh disable > /dev/null 2>&1
+chroot $LXC_ROOTFS /usr/sbin/update-rc.d -f umountfs disable > /dev/null 2>&1
+chroot $LXC_ROOTFS /usr/sbin/update-rc.d -f hwclock.sh disable > /dev/null 2>&1
+chroot $LXC_ROOTFS /usr/sbin/update-rc.d -f hwclockfirst.sh disable > /dev/null 2>&1
+
+if [ -e ${LXC_ROOTFS}/etc/systemd/system/ ]; then
+    touch ${LXC_ROOTFS}/etc/systemd/system/systemd-setup-dgram-qlen.service
+    touch ${LXC_ROOTFS}/etc/systemd/system/dev-hugepages.mount
+    touch ${LXC_ROOTFS}/etc/systemd/system/udev.service
+    touch ${LXC_ROOTFS}/etc/systemd/system/systemd-udevd.service
+    chroot ${LXC_ROOTFS} systemctl set-default multi-user.target
+    chroot ${LXC_ROOTFS} ln -s /lib/systemd/system/halt.target /etc/systemd/system/sigpwr.target
+fi
+
+cat <<EOF >> ${LXC_ROOTFS}${NETWORK_FILE}
+auto eth0
+iface eth0 inet dhcp
+EOF
+
+# and update to the latest security
+chroot ${LXC_ROOTFS} apt-get update
+chroot ${LXC_ROOTFS} apt-get upgrade
+
+# if we're all good here, unmount things and clean up
+[ -e ${LXC_ROOTFS}/usr/sbin/policy-rc.d ] && rm ${LXC_ROOTFS}/usr/sbin/policy-rc.d
+rm ${LXC_ROOTFS}/proc/cmdline
+
+for dev in random urandom; do
+    umount ${LXC_ROOTFS}/dev/$dev
+    rm ${LXC_ROOTFS}/dev/$dev
+done
+
+for file in /var/lib/lxcfs/proc/*; do
+    fname=$(basename $file)
+    umount ${LXC_ROOTFS}/proc/$fname
+    rm ${LXC_ROOTFS}/proc/$fname
+done
+
+exit 0