[lxc-devel] [PATCH] [Cancel] CentOS and Fedora Templates: Harden root passwords and add static MAC network addresses.

Michael H. Warfield mhw at WittsEnd.com
Sat Jan 11 21:01:38 UTC 2014


This patch hasn't made it into the repo yet and there's been a lot of
other changes.  I'm canceling this one and will reissue after rebasing
to include some changes after some discussion with Serge and others.
Please drop this patch.

Regards,
Mike

On Thu, 2013-12-26 at 18:08 -0500, Michael H. Warfield wrote: 
> 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: 465 bytes
Desc: This is a digitally signed message part
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140111/74af9daf/attachment.pgp>


More information about the lxc-devel mailing list