Make script safer with set -e and set -u, change parts that might fail to continue
[lxc-debian-unprivileged.git] / templates / lxc-debian-unprivileged
1 #!/bin/bash
2
3 # lxc template for debootstrapping in userns
4
5 # Authors:
6 # Brett Parker <iDunno@sommitrealweird.co.uk>
7
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 MAPPED=no
23
24 # Only support usage in userns.
25 for arg in "$@"; do
26     [ "$arg" = "--" ] && break
27     if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
28         MAPPED=yes
29     fi
30 done
31
32 if [ "$MAPPED" == "no" ]; then
33     echo "This template can only be used for unprivileged containers." 1>&2
34     echo "You might want the \"debian\" template instead." 1>&2
35     exit 1
36 fi
37
38 set -e
39 set -u
40
41 # Make sure the usual locations are in PATH
42 export PATH=/usr/sbin:/usr/bin:/sbin:/bin:$PATH
43 export GREP_OPTIONS=""
44
45 usage() {
46     cat <<EOF
47 LXC debootstrap in user namespace for unprivileged containers
48
49 Special arguments:
50 [ -h | --help ]: Print this help message and exit.
51
52 Required arguments:
53 [ -r | --release <release> ]: The debian release, e.g. jessie or stretch.
54
55 Optional arguments:
56 [ -m | --mirror <mirrorurl> ]: The debian mirror to user
57 EOF
58     return 0
59 }
60
61 options=$(getopt -o r:m:h -l release:,mirror:,help,mapped-uid:,mapped-gid:,name:,path:,rootfs: -- "$@")
62
63 if [ $? -ne 0 ]; then
64     usage
65     exit 1
66 fi
67
68 eval set -- "$options"
69
70 DEBIAN_MIRROR="http://mirror.mythic-beasts.com/debian/"
71 DEBIAN_RELEASE="jessie"
72
73 disable_initscripts() {
74     cat <<EOF > "${LXC_ROOTFS}/usr/sbin/policy-rc.d"
75 #!/bin/sh
76
77 exit 101
78 EOF
79     chmod 755 "${LXC_ROOTFS}/usr/sbin/policy-rc.d"
80 }
81
82 enable_initscripts() {
83     if [ -e "${LXC_ROOTFS}/usr/sbin/policy-rc.d" ]; then
84         rm "${LXC_ROOTFS}/usr/sbin/policy-rc.d"
85     fi
86 }
87
88 while :; do
89     case "$1" in
90         -h|--help)      usage && exit 1;;
91         -r|--release)   DEBIAN_RELEASE="$2"; shift 2;;
92         -m|--mirror)    DEBIAN_MIRROR="$2"; shift 2;;
93         --mapped-uid)   MAPPED_UID="$2"; shift 2;;
94         --mapped-gid)   MAPPED_GID="$2"; shift 2;;
95         --name)         LXC_NAME="$2"; shift 2;;
96         --path)         LXC_PATH="$2"; shift 2;;
97         --rootfs)       LXC_ROOTFS="$2"; shift 2;;
98         *)              break;;
99     esac
100 done
101
102 # rewrite the default config file
103
104 sed -i -e "/lxc./{w ${LXC_PATH}/config-auto" -e "d}" "${LXC_PATH}/config"
105 sed -i -e '4,$d' "${LXC_PATH}/config"
106
107 cat <<EOF >> "${LXC_PATH}/config"
108
109 # Useful includes
110 lxc.include = /usr/share/lxc/config/debian.common.conf
111 lxc.include = /usr/share/lxc/config/debian.userns.conf
112
113 # Set our hostname
114 lxc.utsname = $LXC_NAME
115
116 # Automatic configuration
117 EOF
118
119 # add back in the auto foo
120 cat "${LXC_PATH}/config-auto" >> "${LXC_PATH}/config"
121 rm "${LXC_PATH}/config-auto"
122
123 mkdir "${LXC_PATH}/bin"
124 cat <<EOF > "${LXC_PATH}/bin/mknod"
125 #!/bin/sh
126
127 exec touch "\$1"
128 EOF
129
130 chmod 755 "${LXC_PATH}/bin/mknod"
131
132 export PATH="${LXC_PATH}/bin:$PATH"
133
134 debootstrap --foreign --include debian-archive-keyring,ifupdown,isc-dhcp-client,locales,openssh-server $DEBIAN_RELEASE "${LXC_ROOTFS}" $DEBIAN_MIRROR
135
136 # now totally skip that check in the new root, because it sucks.
137 sed -i -e 's#check_sane_mount () {#check_sane_mount () {\n\treturn 0#;' "${LXC_ROOTFS}/debootstrap/functions"
138
139 # and stop it from bothering to try to setup proc
140 sed -i -e 's#setup_proc () {#setup_proc () {\n\treturn 0#;' "${LXC_ROOTFS}/debootstrap/functions"
141
142 keyring_dpkg=$(sed -ne "/^debian-archive-keyring/ { s#.* ##; p; }" "${LXC_ROOTFS}/debootstrap/debpaths")
143 # and unpack debian-archive-keyring, because we'll need that
144 (cd "${LXC_ROOTFS}" && dpkg-deb -x ".$keyring_dpkg" .)
145
146 # replace the tar containing devices with something that doesn't contain any
147 (cd "$LXC_ROOTFS/debootstrap" && rm devices.tar.gz && tar czvf devices.tar.gz --files-from=/dev/null)
148
149 # and mount a shitload of things for fun and profit...
150 for file in /var/lib/lxcfs/proc/*; do
151     fname="$(basename $file)"
152     touch "${LXC_ROOTFS}/proc/$fname"
153     mount -n -o bind "$file" "${LXC_ROOTFS}/proc/$fname"
154 done
155
156 for dev in null random urandom; do
157     touch "${LXC_ROOTFS}/dev/$dev"
158     mount -n -o bind /dev/$dev "${LXC_ROOTFS}/dev/$dev"
159 done
160
161 # set /proc/cmdline to something
162 echo "debootstrapping" > "${LXC_ROOTFS}/proc/cmdline"
163
164 # and disable initscripts
165 disable_initscripts
166
167 # and run the second stage
168 chroot "${LXC_ROOTFS}" /debootstrap/debootstrap --second-stage
169
170 # make sure that initscripts are still disabled
171 disable_initscripts
172
173 # configure locales
174 lang=en_GB.UTF-8
175 enc=UTF-8
176 if [ ! -z "$LANG" ]; then
177     lang=${LANG}
178     enc=${LANG#*.}
179 fi
180
181 cat >> "${LXC_ROOTFS}/etc/locale.gen" <<EOF
182 $lang $enc
183 EOF
184
185 chroot "${LXC_ROOTFS}" /usr/sbin/locale-gen $lang $enc
186 chroot "${LXC_ROOTFS}" /usr/sbin/update-locale LANG=$LANG
187
188 # configure timezone
189 if [ -f /etc/timezone ]; then
190     cat /etc/timezone > "${LXC_ROOTFS}/etc/timezone"
191 elif [ -f /etc/sysconfig/clock ]; then
192     . /etc/sysconfig/clock
193     echo $ZONE > "${LXC_ROOTFS}/etc/timezone"
194 fi
195 chroot "${LXC_ROOTFS}" dpkg-reconfigure -f noninteractive tzdata
196
197 # "setup" networking
198 NETWORK_FILE=/etc/network/interfaces
199 if [ -e "${LXC_ROOTFS}/etc/network/interfaces.d" ]; then
200     NETWORK_FILE=/etc/network/interfaces.d/eth0
201 fi
202
203 # remove some interesting breakages in pam for unpriv foo
204 sed -i -e 's#^\(session.*required.*pam_loginuid.so\)#\#\1#;' "${LXC_ROOTFS}"/etc/pam.d/*
205
206 # set the hostname
207 echo $LXC_NAME > "${LXC_ROOTFS}/etc/hostname"
208
209 # setup sources.list
210 cat <<EOF > "${LXC_ROOTFS}/etc/apt/sources.list"
211 deb $DEBIAN_MIRROR $DEBIAN_RELEASE main
212 deb http://security.debian.org/ $DEBIAN_RELEASE/updates main
213 EOF
214
215 # disable bits of systemd / initrd that break things
216 chroot "${LXC_ROOTFS}" /usr/sbin/update-rc.d -f checkroot.sh disable > /dev/null 2>&1 || true
217 chroot "${LXC_ROOTFS}" /usr/sbin/update-rc.d -f umountfs disable > /dev/null 2>&1 || true
218 chroot "${LXC_ROOTFS}" /usr/sbin/update-rc.d -f hwclock.sh disable > /dev/null 2>&1 || true
219 chroot "${LXC_ROOTFS}" /usr/sbin/update-rc.d -f hwclockfirst.sh disable > /dev/null 2>&1 || true
220
221 if [ -e "${LXC_ROOTFS}/etc/systemd/system/" ]; then
222     touch "${LXC_ROOTFS}/etc/systemd/system/systemd-setup-dgram-qlen.service"
223     touch "${LXC_ROOTFS}/etc/systemd/system/dev-hugepages.mount"
224     touch "${LXC_ROOTFS}/etc/systemd/system/udev.service"
225     touch "${LXC_ROOTFS}/etc/systemd/system/systemd-udevd.service"
226     chroot "${LXC_ROOTFS}" systemctl set-default multi-user.target
227     chroot "${LXC_ROOTFS}" ln -s /lib/systemd/system/halt.target /etc/systemd/system/sigpwr.target
228 fi
229
230 if [ -e "${LXC_ROOTFS}/lib/systemd/system/systemd-journald-audit.socket" ]; then
231     touch "${LXC_ROOTFS}/etc/systemd/system/systemd-journald-audit.socket"
232 fi
233
234 cat <<EOF >> "${LXC_ROOTFS}${NETWORK_FILE}"
235 auto eth0
236 iface eth0 inet dhcp
237 EOF
238
239 # and update to the latest security
240 chroot "${LXC_ROOTFS}" apt-get update
241 chroot "${LXC_ROOTFS}" apt-get -y upgrade
242
243 # if we're all good here, unmount things and clean up
244 [ -e "${LXC_ROOTFS}/usr/sbin/policy-rc.d" ] && rm "${LXC_ROOTFS}/usr/sbin/policy-rc.d"
245 rm "${LXC_ROOTFS}/proc/cmdline"
246
247 for dev in null random urandom; do
248     umount "${LXC_ROOTFS}/dev/$dev"
249     rm "${LXC_ROOTFS}/dev/$dev"
250 done
251
252 for file in /var/lib/lxcfs/proc/*; do
253     fname="$(basename $file)"
254     umount "${LXC_ROOTFS}/proc/$fname"
255     rm "${LXC_ROOTFS}/proc/$fname"
256 done
257
258 enable_initscripts
259
260 rm -r "${LXC_PATH}/bin"
261
262 exit 0