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

lxc at zitta.fr lxc at zitta.fr
Mon Jan 13 19:24:10 UTC 2014


Le 13/01/2014 20:09, Michael H. Warfield a écrit :
> On Mon, 2014-01-13 at 18:13 +0200, Marian Marinov wrote: 
>> 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:'
> Forgot to mention...  I don't know where you got the 52:53:54 prefix
> from (02: bit is set so it's a "locally managed" address and it doesn't
> matter all that much) but we seem to have settled in on MAC addresses
> with the upper octet of fe: (which is also locally managed).  That's
> what I've been coding into my generation routines and that's what's been
> added to some of the C code by others.
>
>>          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/.$//')"
>> }
Hi,

There is a recent (today) patch to manage this natively in lxc-create.

https://github.com/lxc/lxc/commit/508c263ee6ed2fac73f6979af287caba38963b4b

I think templates should drop this kind of tricky feature and let
lxc-create do it.
Or at least, it should warn if a NIC don't have an hwaddr and route user to
the lxc.network.hwaddr entry in lxc.conf man page

>>
>>> 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
>>> +"
>>>
>>>
>>>
>>> _______________________________________________
>>> lxc-devel mailing list
>>> lxc-devel at lists.linuxcontainers.org
>>> http://lists.linuxcontainers.org/listinfo/lxc-devel
>>>
>> _______________________________________________
>> lxc-devel mailing list
>> lxc-devel at lists.linuxcontainers.org
>> http://lists.linuxcontainers.org/listinfo/lxc-devel
>>
>
>
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel



More information about the lxc-devel mailing list