forked from neil/lxc-templates
dcd92c8556
Signed-off-by: Nikolay Martynov <mar.kolya@gmail.com>
278 lines
6.7 KiB
Bash
278 lines
6.7 KiB
Bash
#!/bin/bash
|
|
|
|
#
|
|
# lxc: linux Container library
|
|
|
|
# Authors:
|
|
# Daniel Lezcano <daniel.lezcano@free.fr>
|
|
|
|
# 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
|
|
|
|
# Detect use under userns (unsupported)
|
|
for arg in "$@"; do
|
|
[ "$arg" = "--" ] && break
|
|
if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
|
|
echo "This template can't be used for unprivileged containers." 1>&2
|
|
echo "You may want to try the \"download\" template instead." 1>&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# Make sure the usual locations are in PATH
|
|
export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
|
|
|
|
install_sshd()
|
|
{
|
|
rootfs=$1
|
|
|
|
tree="\
|
|
$rootfs/var/empty/sshd \
|
|
$rootfs/var/lib/empty/sshd \
|
|
$rootfs/etc/init.d \
|
|
$rootfs/etc/rc.d \
|
|
$rootfs/etc/ssh \
|
|
$rootfs/etc/sysconfig/network-scripts \
|
|
$rootfs/dev/shm \
|
|
$rootfs/run/sshd \
|
|
$rootfs/proc \
|
|
$rootfs/sys \
|
|
$rootfs/bin \
|
|
$rootfs/sbin \
|
|
$rootfs/usr \
|
|
$rootfs/tmp \
|
|
$rootfs/home \
|
|
$rootfs/root \
|
|
$rootfs/lib \
|
|
$rootfs/lib64"
|
|
|
|
mkdir -p $tree
|
|
if [ $? -ne 0 ]; then
|
|
return 1
|
|
fi
|
|
|
|
ln -s /run $rootfs/var/run
|
|
if [ $? -ne 0 ]; then
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
configure_sshd()
|
|
{
|
|
rootfs=$1
|
|
|
|
cat <<EOF > $rootfs/etc/passwd
|
|
root:x:0:0:root:/root:/bin/bash
|
|
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
|
|
EOF
|
|
|
|
cat <<EOF > $rootfs/etc/group
|
|
root:x:0:root
|
|
sshd:x:74:
|
|
EOF
|
|
|
|
ssh-keygen -t rsa -N "" -f $rootfs/etc/ssh/ssh_host_rsa_key
|
|
ssh-keygen -t dsa -N "" -f $rootfs/etc/ssh/ssh_host_dsa_key
|
|
|
|
# by default setup root password with no password
|
|
cat <<EOF > $rootfs/etc/ssh/sshd_config
|
|
Port 22
|
|
Protocol 2
|
|
HostKey /etc/ssh/ssh_host_rsa_key
|
|
HostKey /etc/ssh/ssh_host_dsa_key
|
|
UsePrivilegeSeparation yes
|
|
SyslogFacility AUTH
|
|
LogLevel INFO
|
|
LoginGraceTime 120
|
|
PermitRootLogin yes
|
|
StrictModes yes
|
|
PubkeyAuthentication yes
|
|
IgnoreRhosts yes
|
|
HostbasedAuthentication no
|
|
PermitEmptyPasswords yes
|
|
ChallengeResponseAuthentication no
|
|
EOF
|
|
|
|
if [ -n "$auth_key" -a -f "$auth_key" ]; then
|
|
u_path="/root/.ssh"
|
|
root_u_path="$rootfs/$u_path"
|
|
mkdir -p $root_u_path
|
|
cp $auth_key "$root_u_path/authorized_keys"
|
|
chown -R 0:0 "$rootfs/$u_path"
|
|
chmod 700 "$rootfs/$u_path"
|
|
echo "Inserted SSH public key from $auth_key into $rootfs/$u_path"
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
copy_configuration()
|
|
{
|
|
path=$1
|
|
rootfs=$2
|
|
name=$3
|
|
|
|
init_path=$(realpath --relative-to=/ $(readlink -f /sbin/init))
|
|
|
|
grep -q "^lxc.rootfs.path" $path/config 2>/dev/null || echo "lxc.rootfs.path = $rootfs" >> $path/config
|
|
cat <<EOF >> $path/config
|
|
lxc.uts.name = $name
|
|
lxc.pty.max = 1024
|
|
lxc.cap.drop = sys_module mac_admin mac_override sys_time
|
|
|
|
# When using LXC with apparmor, uncomment the next line to run unconfined:
|
|
#lxc.apparmor.profile = unconfined
|
|
|
|
lxc.autodev = 1
|
|
|
|
lxc.mount.entry = /lib lib none ro,bind 0 0
|
|
lxc.mount.entry = /bin bin none ro,bind 0 0
|
|
lxc.mount.entry = /usr usr none ro,bind 0 0
|
|
lxc.mount.entry = /sbin sbin none ro,bind 0 0
|
|
lxc.mount.entry = tmpfs run/sshd tmpfs mode=0644 0 0
|
|
lxc.mount.entry = @LXCTEMPLATEDIR@/lxc-sshd $init_path none ro,bind 0 0
|
|
lxc.mount.entry = /etc/init.d etc/init.d none ro,bind 0 0
|
|
|
|
lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed
|
|
EOF
|
|
|
|
# Oracle Linux and Fedora need the following two bind mounted
|
|
if [ -d /etc/sysconfig/network-scripts ]; then
|
|
cat <<EOF >> $path/config
|
|
lxc.mount.entry = /etc/sysconfig/network-scripts etc/sysconfig/network-scripts none ro,bind 0 0
|
|
EOF
|
|
fi
|
|
|
|
if [ -d /etc/rc.d ]; then
|
|
cat <<EOF >> $path/config
|
|
lxc.mount.entry = /etc/rc.d etc/rc.d none ro,bind 0 0
|
|
EOF
|
|
fi
|
|
|
|
# if no .ipv4 section in config, then have the container run dhcp
|
|
grep -q "^lxc.net.0.ipv4.address" $path/config || touch $rootfs/run-dhcp
|
|
|
|
if [ "$(uname -m)" = "x86_64" ]; then
|
|
cat <<EOF >> $path/config
|
|
lxc.mount.entry = /lib64 lib64 none ro,bind 0 0
|
|
EOF
|
|
fi
|
|
}
|
|
|
|
usage()
|
|
{
|
|
cat <<EOF
|
|
$1 -h|--help -p|--path=<path> [--rootfs=<path>]
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
check_for_cmd()
|
|
{
|
|
cmd_path=`type $1`
|
|
if [ $? -ne 0 ]; then
|
|
echo "The command '$1' $cmd_path is not accessible on the system"
|
|
exit 1
|
|
fi
|
|
# we use cut instead of awk because awk is alternatives symlink on ubuntu
|
|
# and /etc/alternatives isn't bind mounted
|
|
cmd_path=`echo $cmd_path |cut -d ' ' -f 3`
|
|
}
|
|
|
|
options=$(getopt -o hp:n:S: -l help,rootfs:,path:,name:,auth-key: -- "$@")
|
|
if [ $? -ne 0 ]; then
|
|
usage $(basename $0)
|
|
exit 1
|
|
fi
|
|
eval set -- "$options"
|
|
|
|
while true
|
|
do
|
|
case "$1" in
|
|
-h|--help) usage $0 && exit 0;;
|
|
-p|--path) path=$2; shift 2;;
|
|
--rootfs) rootfs=$2; shift 2;;
|
|
-n|--name) name=$2; shift 2;;
|
|
-S|--auth-key) auth_key=$2; shift 2;;
|
|
--) shift 1; break ;;
|
|
*) break ;;
|
|
esac
|
|
done
|
|
|
|
if [ "$(id -u)" != "0" ]; then
|
|
echo "This script should be run as 'root'"
|
|
exit 1
|
|
fi
|
|
|
|
if [ $0 = "/sbin/init" ]; then
|
|
|
|
PATH="$PATH:/bin:/sbin:/usr/sbin"
|
|
check_for_cmd @SBINDIR@/init.lxc
|
|
check_for_cmd sshd
|
|
sshd_path=$cmd_path
|
|
|
|
# run dhcp?
|
|
if [ -f /run-dhcp ]; then
|
|
check_for_cmd dhclient
|
|
check_for_cmd ifconfig
|
|
touch /etc/fstab
|
|
rm -f /dhclient.conf
|
|
cat > /dhclient.conf << EOF
|
|
send host-name = gethostname();
|
|
EOF
|
|
ifconfig eth0 up
|
|
dhclient eth0 -cf /dhclient.conf
|
|
echo "Container IP address:"
|
|
ifconfig eth0 |grep inet
|
|
fi
|
|
|
|
exec @SBINDIR@/init.lxc --name $name -- $sshd_path
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$path" ]; then
|
|
echo "'path' parameter is required"
|
|
exit 1
|
|
fi
|
|
|
|
# detect rootfs
|
|
config="$path/config"
|
|
if [ -z "$rootfs" ]; then
|
|
if grep -q '^lxc.rootfs.path' $config 2>/dev/null ; then
|
|
rootfs=$(awk -F= '/^lxc.rootfs.path =/{ print $2 }' $config)
|
|
else
|
|
rootfs=$path/rootfs
|
|
fi
|
|
fi
|
|
|
|
install_sshd $rootfs
|
|
if [ $? -ne 0 ]; then
|
|
echo "failed to install sshd's rootfs"
|
|
exit 1
|
|
fi
|
|
|
|
configure_sshd $rootfs
|
|
if [ $? -ne 0 ]; then
|
|
echo "failed to configure sshd template"
|
|
exit 1
|
|
fi
|
|
|
|
copy_configuration $path $rootfs $name
|
|
if [ $? -ne 0 ]; then
|
|
echo "failed to write configuration file"
|
|
exit 1
|
|
fi
|