On 12/27/2013 01:08 AM, 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.

I'm using both the fedora and centos templates and having a static MAC is a 
problem.

I have replaced static MAC with $(gen_mac) shell function.

function gen_mac() {
        mac_vars=(0 1 2 3 4 5 6 7 8 9 a b c d e f)
        mac_base='52:53:54:'
        ret=''
        for i in {1..6}; do
                n=$RANDOM
                let 'n %= 16'
                ret="${ret}${mac_vars[$n]}"
                if [ $i -eq 2 ] || [ $i -eq 4 ]; then
                        ret="${ret}:"
                fi
        done
        echo "${mac_base}${ret}"
}

There is also another variant of this function:
function gen_mac() {
        echo "52:53:54:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')"
}


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 <m...@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
+"



_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel


_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to