#!/bin/bash # lxc template for debootstrapping in userns # Authors: # Brett Parker # 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 exit 1 fi set -e set -u # Make sure the usual locations are in PATH export PATH=/usr/sbin:/usr/bin:/sbin:/bin:$PATH export GREP_OPTIONS="" usage() { cat < ]: The debian release, e.g. jessie or stretch. Optional arguments: [ -m | --mirror ]: 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" disable_initscripts() { cat < "${LXC_ROOTFS}/usr/sbin/policy-rc.d" #!/bin/sh exit 101 EOF chmod 755 "${LXC_ROOTFS}/usr/sbin/policy-rc.d" } enable_initscripts() { if [ -e "${LXC_ROOTFS}/usr/sbin/policy-rc.d" ]; then rm "${LXC_ROOTFS}/usr/sbin/policy-rc.d" fi } 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 # 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 <> "${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 < "${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,openssh-server $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 null random urandom; do touch "${LXC_ROOTFS}/dev/$dev" mount -n -o bind /dev/$dev "${LXC_ROOTFS}/dev/$dev" done # set /proc/cmdline to something echo "debootstrapping" > "${LXC_ROOTFS}/proc/cmdline" # and disable initscripts disable_initscripts # and run the second stage chroot "${LXC_ROOTFS}" /debootstrap/debootstrap --second-stage # make sure that initscripts are still disabled disable_initscripts # 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" < "${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 # remove some interesting breakages in pam for unpriv foo sed -i -e 's#^\(session.*required.*pam_loginuid.so\)#\#\1#;' "${LXC_ROOTFS}"/etc/pam.d/* # set the hostname echo $LXC_NAME > "${LXC_ROOTFS}/etc/hostname" # setup sources.list cat < "${LXC_ROOTFS}/etc/apt/sources.list" deb $DEBIAN_MIRROR $DEBIAN_RELEASE main deb http://security.debian.org/ $DEBIAN_RELEASE/updates main EOF # disable bits of systemd / initrd that break things chroot "${LXC_ROOTFS}" /usr/sbin/update-rc.d -f checkroot.sh disable > /dev/null 2>&1 || true chroot "${LXC_ROOTFS}" /usr/sbin/update-rc.d -f umountfs disable > /dev/null 2>&1 || true chroot "${LXC_ROOTFS}" /usr/sbin/update-rc.d -f hwclock.sh disable > /dev/null 2>&1 || true chroot "${LXC_ROOTFS}" /usr/sbin/update-rc.d -f hwclockfirst.sh disable > /dev/null 2>&1 || true 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 if [ -e "${LXC_ROOTFS}/lib/systemd/system/systemd-journald-audit.socket" ]; then touch "${LXC_ROOTFS}/etc/systemd/system/systemd-journald-audit.socket" fi cat <> "${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 -y 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 null 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 enable_initscripts rm -r "${LXC_PATH}/bin" exit 0