CentOS kickstart: more automation!

This is the third post in a series on building/setting up/improving a PXE boot server with CentOS.
By the end of this post, we’ll have added a pre-installation block to gather network information before installation, and some post-installation scripts to our our kickstart file to allow for copying of files and automatic configuration of the SMTP service and randomisation of our root password.

A requirement for this to work correctly is for you to have your own mail server, or an email account accessible to you – either via your own O365 or GSuite subscription, or a self-hosted mail solution like Modoboa or IRedMail. Personally I’m a fan of both self-hosted options, although in this example I’ll be using Modoboa. I’d previously it up and am using it to send alerts out from my lab (Veeam, monitoring, etc) to my own email account within GSuite.
If you do not have any of the above, you can configure the SMTP service to use a gmail/yahoo/etc account instead, however I won’t be covering that in this post.

Prompting for network info

To get things started, we’re going to make the kickstart prompt us for the machines hostname and IP address, so there’s one less thing we have to do before we can start using the VM after it’s built.

open up the kickstart file we created previously, and delete lines 18 and 19, and replace them with the below text.

# Network Information
%include /tmp/network.ks

%pre --interpreter=/usr/bin/bash
exec < /dev/tty6 > /dev/tty6 2> /dev/tty6
chvt 6
 echo "#######################################"
 echo "Kickstarted CentOS 7 x64"
 echo "Enter details to continue"
 echo "#######################################"
 read -p "Enter hostname: " HOSTNAME
 read -p "Enter IP address: " IPADDR
 read -p "Enter netmask: " NETMASK
 read -p "Enter default gateway: " GATEWAY
 read -p "Enter DNS server: " DNSSERVER
echo
sleep 1

echo "network --bootproto=static --hostname=$HOSTNAME --device=ens192 --gateway=$GATEWAY --ip=$IPADDR --netmask=$NETMASK --nameserver=$DNSSERVER --noipv6 --onboot=on --activate" > /tmp/network.ks

chvt 1
exec < /dev/tty1 > /dev/tty1 2> /dev/tty1
%end

What’s basically happening here, is that when the machine is PXE booted and the kickstart selected, the installer will prompt you to enter the requested details. The interpreter will then set the listed variables to the entered details and then echo them into the /tmp/network.ks file.
The VM will then use this IP for the rest of the installation process, and once it reboots, the entered hostname and IP will be used for the completed VM build.

Configure SSMTP

Next, we’re going to add the ssmtp package to our kickstart file, and also create and edit the config files for the SSMTP service.
Inside our kickstart file, we want to add ssmtp to the %packages section like so:

%packages
@base
@core
...
ssmtp
...
%end

We also need to add a few lines into the kickstart file to create a temporary working directory in /tmp and also copy our script to configure ssmtp.
Why copy a script instead of making the kickstart create it for us? In my experience it just makes things simpler, and it means we can have a handful of kickstart files doing different configs for the VMs but referencing back to our core installation scripts.
In other words, if we need to edit the ssmtp setup process for multiple kickstart files, we only have to update that script and not all the kickstart files.

At the top of the %post section of our kickstart, we’ll need to add the following

%post --log=/tmp/post-build.log
...
#########################################
# Create our temporary working directory
mkdir /tmp/build

#########################################
# Copy ssmtp setup script
wget -O /tmp/build/ssmtpsetup.sh ftp://10.176.40.10/centos7/config/ssmtpsetup.sh
chmod +x /tmp/build/ssmtpsetup.sh
/bin/bash /tmp/build/ssmtpsetup.sh

%end

For ssmtp to work correctly, there’s 2 files that need to be configured: ssmtp.conf and revaliases – these can both be found in /etc/ssmtp.
To make it easier for the files to be accessed from the kickstart file, we’re going to put them in the following location: /var/ftp/centos7/config.

We’re going to create our ssmtp.conf file, making sure to set the username/password/server to your own, or a public mail service:

[email protected]
mailhub=mail.yourdomain.tld:587
hostname=BLANKHOSTNAME.AD.YOURDOMAIN.TLD
[email protected]
AuthPass=yourpassword
AuthMethod=LOGIN
UseSTARTTLS=YES
TLS_CA_File=/etc/pki/tls/certs/ca-bundle.crt
FromLineOverride=YES

Next we’re going to create the revaliases file, again making sure to set the details to your own:

root:[email protected]:mail.yourdomain.tld:587

Finally, we’re going to create our ssmtpsetup.sh script:

#!/bin/sh
# Get ssmtp config files
wget -O /tmp/build/ssmtp.conf ftp://10.176.40.10/centos7/config/ssmtp.conf
wget -O /tmp/build/revaliases ftp://10.176.40.10/centos7/config/revaliases

# Fix hostname in ssmtp.conf
sed -i s^'BLANKHOSTNAME'^"$HOSTNAME"^ /tmp/build/ssmtp.conf

# Copy files
cp -rf /tmp/build/ssmtp.conf /etc/ssmtp/
cp -rf /tmp/build/revaliases /etc/ssmtp/

# Disable sendmail and symlink to ssmtp
mv /usr/sbin/sendmail /usr/sbin/sendmail.ORIG
ln -s /usr/sbin/ssmtp /usr/sbin/sendmail
mv /usr/lib/sendmail /usr/lib/sendmail.ORIG
ln -s /usr/sbin/ssmtp /usr/lib/sendmail

The above is essentially wget-ing the files we just created from the FTP server and storing them in the /tmp/directory. We replace BLANKHOSTNAME in the ssmtp.conf file with the VM’s actual hostname as required, and then copy the files to the correct location. We also rename the default sendmail files and replace them with symlinks to ssmtp.

Randomised root password

The next thing we’re going to tackle here is randomly generating our root password – from a security standpoint, it’s more secure to have different root passwords across multiple machines. If an attacker is able to breach one of your machines, in theory they shouldn’t be able to access anything else if each VM’s root password is different.

One again, we need to open up our kickstart file and add a few lines into it.
Essentially this snip is generating a random string of 100 alphanumerical characters and then grabs the first 15 (or value for HOWLONG) characters. We then create and set permissions on a temporary password file, and echo the NEWPW value to the passwd command and also our temporary password file.

%post --log=/tmp/post-build.log
...
#########################################
# Generate random root password
# https://serverfault.com/a/976598
HOWLONG=15 # How long our root password should be
NEWPW=$(< /dev/urandom tr -dc A-Za-z0-9 | head -c100 | head -c$((20+($RANDOM%20))) | tail -c$((20+($RANDOM%20))) | head -c${HOWLONG});
echo "${NEWPW}" |  passwd --stdin  root
touch /tmp/build/password
chmod 777 /tmp/build/password
echo "${NEWPW}" >> /tmp/build/password
...
%end

Next, we need to add the following underneath the above. Once again, we’re wget-ing a script to our temp working directory, making it executable and then adding a line to the root crontab to make the script execute after the VM has rebooted.

%post --log=/tmp/post-build.log
...
#########################################
# Copy our build cleanup script
wget -O /tmp/build/buildcleanup.sh ftp://10.176.10.2/centos7/config/buildcleanup.sh
chmod + /tmp/build/buildcleanup.sh
echo "@reboot sleep 60 && /tmp/build/buildcleanup.sh && /sbin/shutdown -r now" > /var/spool/cron/root
...
%end

And here’s the buildcleanup script we need to create in our FTP directory. This script restarts the postfix service, and then emails out the password file created above to the recipient set in MAILTO. The script also deletes our temporary working directory and resets the root crontab.

#!/bin/bash
systemctl restart postfix
sleep 15
MAILTO='[email protected]'
PASSWORDFILE=$(cat /tmp/build/password)
echo "The root password is $PASSWORDFILE" | mail -s "$HOSTNAME build complete!" $MAILTO
sleep 30
/bin/rm -rf /tmp/build/
/bin/crontab -r

Bringing it all together

So at this point we’ve modified our kickstart file a bunch, and created a bunch of files in our /var/ftp/centos7/config directory, so now what?
Before we do anything else, now is a good time to run ksvalidator against the kickstart to make sure there’s nothing wrong with it. everything good? Let’s try to build a VM!

PXE boot a VM and run through the process the same as before – however, we’ll be promoted to enter a hostname, IP, subnet, default gateway and DNS server before the build starts.

Once the build has finished, you’ll be sent to a login screen – after a couple of minutes, the VM should reboot once more, and you’ll receive an email from the VM containing the root password.

Now, if all has gone to plan, we should be able to successfully login with the root account and the password in the above email

Finally, for the purpose of demonstration, I commented out line 9 of the buildcleanup.sh script so the password file was not removed. If we now cat the /tmp/build/password file, we’ll see that it contains our root password.

Wrapping up

In this post we’ve covered the process of customising our kickstart file more by making it prompt us for a hostname/IP address details, install more packages, copy files to configure a package, randomly generate our root password, and then email us once everything is completed so we know the VM is ready to be used.

In the next post I’m going to cover automatically joining our VM to Active Directory so we can both login with an AD username, and also use AD to manage user permissions on the VM.

Danny Written by: