[lxc-devel] [PATCH] CentOS and Fedora Templates: Harden root passwords and add static MAC network addresses.
Michael H. Warfield
mhw at WittsEnd.com
Thu Dec 26 23:08:57 UTC 2013
CentOS and Fedora Templates: Harden root passwords and add static MAC network addresses.
1) Add logic to root password setting. Root password is now set to
"Root-${name}-${RANDOM} to defeat common brute force scans.
2) Enhance exit messages to explain root password and password changing.
3) Add random generated hwaddr (MAC) entires for any network interfaces
in default config copied to container.
4) Add shell variable expansion of default config.
5) Cross patch templates to bring them more into coherence with each other.
Signed-off-by: Michael H. Warfield <mhw at WittsEnd.com>
---
templates/lxc-centos.in | 114 +++++++++++++++++++++++++++++++++++++-----------
templates/lxc-fedora.in | 99 +++++++++++++++++++++++++++++++++++++----
2 files changed, 180 insertions(+), 33 deletions(-)
diff --git a/templates/lxc-centos.in b/templates/lxc-centos.in
index 7d47715..5bb5349 100644
--- a/templates/lxc-centos.in
+++ b/templates/lxc-centos.in
@@ -33,6 +33,7 @@ default_path=@LXCPATH@
# We really need something better here!
root_password=root
+# These are only going into comments in the resulting config...
lxc_network_type=veth
lxc_network_link=lxcbr0
@@ -256,8 +257,10 @@ EOF
mknod -m 600 ${dev_path}/initctl p
mknod -m 666 ${dev_path}/ptmx c 5 2
- echo "setting root passwd to $root_password"
+ echo "Setting root passwd to '$root_password'"
echo "root:$root_password" | chroot $rootfs_path chpasswd
+ # Also set this password as expired to force the user to change it!
+ chroot $rootfs_path passwd -e root
# This will need to be enhanced for CentOS 7 when systemd
# comes into play... /\/\|=mhw=|\/\/
@@ -374,6 +377,7 @@ copy_centos()
# i prefer rsync (no reason really)
mkdir -p $rootfs_path
rsync -a $cache/rootfs/ $rootfs_path/
+ echo
return 0
}
@@ -428,28 +432,71 @@ install_centos()
return $?
}
-copy_configuration()
+create_hwaddr()
{
+ echo $(dd if=/dev/urandom bs=8 count=1 2>/dev/null | md5sum
+ | sed -e 's/\(..\)\(..\)\(..\)\(..\)\(..\).*/fe:\1:\2:\3:\4:\5/')
+}
+copy_configuration()
+{
mkdir -p $config_path
+
+ grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "
+lxc.rootfs = $rootfs_path
+" >> $config_path/config
+
+ # The following code is to create static MAC addresses for each
+ # interface in the container. This code will work for multiple
+ # interfaces in the default config.
+ mv $config_path/config $config_path/config.def
+ while read LINE
+ do
+ # This should catch variable expansions from the default config...
+ if expr "${LINE}" : '.*\$' > /dev/null 2>&1
+ then
+ LINE=$(eval "echo \"${LINE}\"")
+ fi
+
+ # There is a tab and a space in the regex bracket below!
+ # Seems that \s doesn't work in brackets.
+ KEY=$(expr $LINE : '\s*\([^ ]*\)\s*=')
+
+ if [[ "${KEY}" != "lxc.network.hwaddr" ]]
+ then
+ echo ${LINE} >> $config_path/config
+
+ if [[ "${KEY}" == "lxc.network.link" ]]
+ then
+ echo "lxc.network.hwaddr = $(create_hwaddr)" >> $config_path/config
+ fi
+ fi
+ done < $config_path/config.def
+
+ rm -f $config_path/config.def
+
cat <<EOF >> $config_path/config
lxc.utsname = $utsname
lxc.tty = 4
lxc.pts = 1024
-lxc.rootfs = $rootfs_path
-lxc.mount = $config_path/fstab
+lxc.mount = $config_path/fstab
lxc.cap.drop = sys_module mac_admin mac_override sys_time
lxc.autodev = $auto_dev
+# When using LXC with apparmor, uncomment the next line to run unconfined:
+#lxc.aa_profile = unconfined
+
# example simple networking setup, uncomment to enable
#lxc.network.type = $lxc_network_type
#lxc.network.flags = up
#lxc.network.link = $lxc_network_link
#lxc.network.name = eth0
-# additional example for veth network type, static MAC address,
-# and persistent veth device name on host side
+# Additional example for veth network type
+# static MAC address,
#lxc.network.hwaddr = 00:16:3e:77:52:20
+# persistent veth device name on host side
+# Note: This may potentially collide with other containers of same name!
#lxc.network.veth.pair = v-$name-e0
#cgroups
@@ -460,8 +507,6 @@ lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
-lxc.cgroup.devices.allow = c 4:0 rwm
-lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
@@ -473,13 +518,12 @@ EOF
cat <<EOF > $config_path/fstab
proc proc proc nodev,noexec,nosuid 0 0
-devpts dev/pts devpts defaults 0 0
sysfs sys sysfs defaults 0 0
EOF
if [ $? -ne 0 ]; then
- echo "Failed to add configuration"
- return 1
+ echo "Failed to add configuration"
+ return 1
fi
return 0
@@ -489,22 +533,21 @@ clean()
{
if [ ! -e $cache ]; then
- exit 0
+ exit 0
fi
# lock, so we won't purge while someone is creating a repository
(
- flock -x 200
- if [ $? != 0 ]; then
- echo "Cache repository is busy."
- exit 1
- fi
-
- echo -n "Purging the download cache for centos-$release..."
- rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
- exit 0
+ flock -x 200
+ if [ $? != 0 ]; then
+ echo "Cache repository is busy."
+ exit 1
+ fi
- ) 200>/var/lock/subsys/lxc-centos
+ echo -n "Purging the download cache for centos-$release..."
+ rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
+ exit 0
+ ) 200>@LOCALSTATEDIR@/lock/subsys/lxc-centos
}
usage()
@@ -554,6 +597,12 @@ if [ ! -z "$clean" -a -z "$path" ]; then
exit 0
fi
+# Let's do something better for the initial root password.
+# It's not perfect but it will defeat common scanning brute force
+# attacks in the case where ssh is exposed. It will also be set to
+# expired, forcing the user to change it at first login.
+root_password=Root-${name}-${RANDOM}
+
if [ -z "${utsname}" ]; then
utsname=${name}
fi
@@ -572,7 +621,7 @@ fi
# utsname and hostname = Container_Name.Domain_Name
if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
- if [ -n "$(dnsdomainname)" ]; then
+ if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then
utsname=${utsname}.$(dnsdomainname)
fi
fi
@@ -666,5 +715,20 @@ if [ ! -z $clean ]; then
clean || exit 1
exit 0
fi
-echo "container rootfs and config created, default root password is '$root_password'"
-echo "edit the config file to check/enable networking setup"
+echo "
+Container rootfs and config have been created.
+Edit the config file to check/enable networking setup.
+"
+
+echo "The temporary password for root is: '$root_password'
+
+You may want to note that password down before starting the container.
+
+The password set up as "expired" and will require it to be changed it at
+first login, which you should do as soon as possible. If you lose the
+root password or wish to change it without starting the container, you
+can change it from the host by running the following command (which will
+also reset the expired flag):
+
+ chroot ${rootfs_path} passwd
+"
diff --git a/templates/lxc-fedora.in b/templates/lxc-fedora.in
index 5f66ff1..b0c214a 100644
--- a/templates/lxc-fedora.in
+++ b/templates/lxc-fedora.in
@@ -33,6 +33,10 @@ default_path=@LXCPATH@
# We really need something better here!
root_password=root
+# These are only going into comments in the resulting config...
+lxc_network_type=veth
+lxc_network_link=lxcbr0
+
# is this fedora?
# Alow for weird remixes like the Raspberry Pi
#
@@ -194,8 +198,10 @@ EOF
mknod -m 600 ${dev_path}/initctl p
mknod -m 666 ${dev_path}/ptmx c 5 2
- echo "setting root passwd to $root_password"
+ echo "Setting root passwd to '$root_password'"
echo "root:$root_password" | chroot $rootfs_path chpasswd
+ # Also set this password as expired to force the user to change it!
+ chroot $rootfs_path passwd -e root
# specifying this in the initial packages doesn't always work.
# Even though it should have...
@@ -243,7 +249,7 @@ configure_fedora_init()
configure_fedora_systemd()
{
- unlink ${rootfs_path}/etc/systemd/system/default.target
+ rm -f ${rootfs_path}/etc/systemd/system/default.target
touch ${rootfs_path}/etc/fstab
chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/udev.service
chroot ${rootfs_path} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
@@ -837,6 +843,7 @@ copy_fedora()
# i prefer rsync (no reason really)
mkdir -p $rootfs_path
rsync -Ha $cache/rootfs/ $rootfs_path/
+ echo
return 0
}
@@ -891,11 +898,53 @@ install_fedora()
return $?
}
-copy_configuration()
+# Generate a random hardware (MAC) address composed of FE followed by
+# 5 random bytes...
+create_hwaddr()
{
+ echo $(dd if=/dev/urandom bs=8 count=1 2>/dev/null | md5sum |
+ sed -e 's/\(..\)\(..\)\(..\)\(..\)\(..\).*/fe:\1:\2:\3:\4:\5/')
+}
+copy_configuration()
+{
mkdir -p $config_path
- grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "lxc.rootfs = $rootfs_path" >> $config_path/config
+
+ grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "
+lxc.rootfs = $rootfs_path
+" >> $config_path/config
+
+ # The following code is to create static MAC addresses for each
+ # interface in the container. This code will work for multiple
+ # interfaces in the default config. It will also strip any
+ # hwaddr stanzas out of the default config since we can not share
+ # MAC addresses between containers.
+ mv $config_path/config $config_path/config.def
+ while read LINE
+ do
+ # This should catch variable expansions from the default config...
+ if expr "${LINE}" : '.*\$' > /dev/null 2>&1
+ then
+ LINE=$(eval "echo \"${LINE}\"")
+ fi
+
+ # There is a tab and a space in the regex bracket below!
+ # Seems that \s doesn't work in brackets.
+ KEY=$(expr "${LINE}" : '\s*\([^ ]*\)\s*=')
+
+ if [[ "${KEY}" != "lxc.network.hwaddr" ]]
+ then
+ echo "${LINE}" >> $config_path/config
+
+ if [[ "${KEY}" == "lxc.network.link" ]]
+ then
+ echo "lxc.network.hwaddr = $(create_hwaddr)" >> $config_path/config
+ fi
+ fi
+ done < $config_path/config.def
+
+ rm -f $config_path/config.def
+
cat <<EOF >> $config_path/config
lxc.utsname = $utsname
lxc.tty = 4
@@ -908,6 +957,18 @@ lxc.autodev = $auto_dev
# When using LXC with apparmor, uncomment the next line to run unconfined:
#lxc.aa_profile = unconfined
+# example simple networking setup, uncomment to enable
+#lxc.network.type = $lxc_network_type
+#lxc.network.flags = up
+#lxc.network.link = $lxc_network_link
+#lxc.network.name = eth0
+# Additional example for veth network type
+# static MAC address,
+#lxc.network.hwaddr = 00:16:3e:77:52:20
+# persistent veth device name on host side
+# Note: This may potentially collide with other containers of same name!
+#lxc.network.veth.pair = v-$name-e0
+
#cgroups
lxc.cgroup.devices.deny = a
# /dev/null and zero
@@ -929,6 +990,7 @@ EOF
proc proc proc nodev,noexec,nosuid 0 0
sysfs sys sysfs defaults 0 0
EOF
+
if [ $? -ne 0 ]; then
echo "Failed to add configuration"
return 1
@@ -1006,6 +1068,12 @@ if [ ! -z "$clean" -a -z "$path" ]; then
exit 0
fi
+# Let's do something better for the initial root password.
+# It's not perfect but it will defeat common scanning brute force
+# attacks in the case where ssh is exposed. It will also be set to
+# expired, forcing the user to change it at first login.
+root_password=Root-${name}-${RANDOM}
+
if [ -z "${utsname}" ]; then
utsname=${name}
fi
@@ -1024,7 +1092,7 @@ fi
# utsname and hostname = Container_Name.Domain_Name
if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
- if [ -n "$(dnsdomainname)" ]; then
+ if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then
utsname=${utsname}.$(dnsdomainname)
fi
fi
@@ -1128,12 +1196,14 @@ if [ ! -z $clean ]; then
clean || exit 1
exit 0
fi
-echo "container rootfs and config created"
+echo "
+Container rootfs and config have been created.
+Edit the config file to check/enable networking setup.
+"
if [[ -d ${cache_base}/bootstrap ]]
then
- echo "
-You have successfully built a Fedora container and cache. This cache may
+ echo "You have successfully built a Fedora container and cache. This cache may
be used to create future containers of various revisions. The directory
${cache_base}/bootstrap contains a bootstrap
which may no longer needed and can be removed.
@@ -1147,3 +1217,16 @@ This is only used in the creation of the bootstrap run-time-environment
and may be removed.
"
fi
+
+echo "The temporary password for root is: '$root_password'
+
+You may want to note that password down before starting the container.
+
+The password set up as "expired" and will require it to be changed it at
+first login, which you should do as soon as possible. If you lose the
+root password or wish to change it without starting the container, you
+can change it from the host by running the following command (which will
+also reset the expired flag):
+
+ chroot ${rootfs_path} passwd
+"
--
1.8.3.1
--
Michael H. Warfield (AI4NB) | (770) 978-7061 | mhw at WittsEnd.com
/\/\|=mhw=|\/\/ | (678) 463-0932 | http://www.wittsend.com/mhw/
NIC whois: MHW9 | An optimist believes we live in the best of all
PGP Key: 0x674627FF | possible worlds. A pessimist is sure of it!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 482 bytes
Desc: This is a digitally signed message part
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20131226/18b8455c/attachment-0001.pgp>
More information about the lxc-devel
mailing list