{"id":146,"date":"2020-08-13T13:00:00","date_gmt":"2020-08-13T13:00:00","guid":{"rendered":"http:\/\/10.171.10.16:10000\/?p=146"},"modified":"2022-01-16T17:15:27","modified_gmt":"2022-01-16T17:15:27","slug":"centos-kickstart-more-automation","status":"publish","type":"post","link":"https:\/\/dannypayne.me\/?p=146","title":{"rendered":"CentOS kickstart: more automation!"},"content":{"rendered":"\n<p>This is the third post in a series on building\/setting up\/improving a PXE boot server with CentOS.<br>By the end of this post, we&#8217;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.<\/p>\n\n\n\n<p>A requirement for this to work correctly is for you to have your own mail server, or an email account accessible to you &#8211; either via your own O365 or GSuite subscription, or a self-hosted mail solution like <a rel=\"noreferrer noopener\" href=\"https:\/\/modoboa.org\/en\/\" target=\"_blank\">Modoboa <\/a>or <a rel=\"noreferrer noopener\" href=\"https:\/\/www.iredmail.org\/\" target=\"_blank\">IRedMail<\/a>. Personally I&#8217;m a fan of both self-hosted options, although in this example I&#8217;ll be using Modoboa. I&#8217;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. <br>If you <em>do not<\/em> have any of the above, you can configure the <code>SMTP<\/code> service to use a gmail\/yahoo\/etc account instead, however I won&#8217;t be covering that in this post.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prompting for network info<\/h3>\n\n\n\n<p>To get things started, we&#8217;re going to make the kickstart prompt us for the machines hostname and IP address, so there&#8217;s one less thing we have to do before we can start using the VM after it&#8217;s built. <br><br>open up the kickstart file we created previously, and delete lines <strong>18 <\/strong>and <strong>19<\/strong>, and replace them with the below text. <\/p>\n\n\n\n<pre title=\"\/var\/ftp\/centos7\/anaconda-ks.cfg\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\"># Network Information\n%include \/tmp\/network.ks\n\n%pre --interpreter=\/usr\/bin\/bash\nexec &lt; \/dev\/tty6 > \/dev\/tty6 2> \/dev\/tty6\nchvt 6\n echo \"#######################################\"\n echo \"Kickstarted CentOS 7 x64\"\n echo \"Enter details to continue\"\n echo \"#######################################\"\n read -p \"Enter hostname: \" HOSTNAME\n read -p \"Enter IP address: \" IPADDR\n read -p \"Enter netmask: \" NETMASK\n read -p \"Enter default gateway: \" GATEWAY\n read -p \"Enter DNS server: \" DNSSERVER\necho\nsleep 1\n\necho \"network --bootproto=static --hostname=$HOSTNAME --device=ens192 --gateway=$GATEWAY --ip=$IPADDR --netmask=$NETMASK --nameserver=$DNSSERVER --noipv6 --onboot=on --activate\" > \/tmp\/network.ks\n\nchvt 1\nexec &lt; \/dev\/tty1 > \/dev\/tty1 2> \/dev\/tty1\n%end<\/code><\/pre>\n\n\n\n<p>What&#8217;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 <code>\/tmp\/network.ks<\/code> file. <br>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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Configure SSMTP<\/h3>\n\n\n\n<p>Next, we&#8217;re going to add the <code>ssmtp<\/code> package to our kickstart file, and also create and edit the config files for the <code>SSMTP<\/code> service.<br>Inside our kickstart file, we want to add <code>ssmtp<\/code> to the <code> %packages<\/code> section like so:<\/p>\n\n\n\n<pre title=\"\/var\/ftp\/centos7\/anaconda-ks.cfg\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">%packages\n@base\n@core\n...\nssmtp\n...\n%end<\/code><\/pre>\n\n\n\n<p>We also need to add a few lines into the kickstart file to create a temporary working directory in <code>\/tmp<\/code> and also copy our script to configure <code>ssmtp<\/code>. <br>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 <em>different<\/em> configs for the VMs but referencing back to our <em>core<\/em> installation scripts. <br>In other words, if we need to edit the <code>ssmtp<\/code> setup process for multiple kickstart files, we only have to update <em>that<\/em> script and not all the kickstart files. <br><br>At the top of the <code>%post<\/code> section of our kickstart, we&#8217;ll need to add the following<\/p>\n\n\n\n<pre title=\"\/var\/ftp\/centos7\/anaconda-ks.cfg\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">%post --log=\/tmp\/post-build.log\n...\n#########################################\n# Create our temporary working directory\nmkdir \/tmp\/build\n\n#########################################\n# Copy ssmtp setup script\nwget -O \/tmp\/build\/ssmtpsetup.sh ftp:\/\/10.176.40.10\/centos7\/config\/ssmtpsetup.sh\nchmod +x \/tmp\/build\/ssmtpsetup.sh\n\/bin\/bash \/tmp\/build\/ssmtpsetup.sh\n\n%end<\/code><\/pre>\n\n\n\n<p>For <code>ssmtp<\/code> to work correctly, there&#8217;s 2 files that need to be configured: <code>ssmtp.conf<\/code> and <code>revaliases<\/code> &#8211; these can both be found in <code>\/etc\/ssmtp<\/code>. <br>To make it easier for the files to be accessed from the kickstart file, we&#8217;re going to put them in the following location: <code>\/var\/ftp\/centos7\/config<\/code>.<\/p>\n\n\n\n<p>We&#8217;re going to create our <code>ssmtp.conf<\/code> file, making sure to set the username\/password\/server to your own, or a public mail service:<\/p>\n\n\n\n<pre title=\"\/var\/ftp\/centos7\/config\/ssmtp.conf\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">root=alerts@yourdomain.tld\nmailhub=mail.yourdomain.tld:587\nhostname=BLANKHOSTNAME.AD.YOURDOMAIN.TLD\nAuthUser=alerts@yourdomain.tld\nAuthPass=yourpassword\nAuthMethod=LOGIN\nUseSTARTTLS=YES\nTLS_CA_File=\/etc\/pki\/tls\/certs\/ca-bundle.crt\nFromLineOverride=YES<\/code><\/pre>\n\n\n\n<p>Next we&#8217;re going to create the <code>revaliases<\/code> file, again making sure to set the details to your own:<\/p>\n\n\n\n<pre title=\"\/var\/ftp\/centos7\/config\/revalises\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">root:alerts@yourdomain.tld:mail.yourdomain.tld:587<\/code><\/pre>\n\n\n\n<p>Finally, we&#8217;re going to create our <code>ssmtpsetup.sh<\/code> script:<\/p>\n\n\n\n<pre title=\"\/var\/ftp\/centos7\/config\/ssmtpsetup.sh\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">#!\/bin\/sh\n# Get ssmtp config files\nwget -O \/tmp\/build\/ssmtp.conf ftp:\/\/10.176.40.10\/centos7\/config\/ssmtp.conf\nwget -O \/tmp\/build\/revaliases ftp:\/\/10.176.40.10\/centos7\/config\/revaliases\n\n# Fix hostname in ssmtp.conf\nsed -i s^'BLANKHOSTNAME'^\"$HOSTNAME\"^ \/tmp\/build\/ssmtp.conf\n\n# Copy files\ncp -rf \/tmp\/build\/ssmtp.conf \/etc\/ssmtp\/\ncp -rf \/tmp\/build\/revaliases \/etc\/ssmtp\/\n\n# Disable sendmail and symlink to ssmtp\nmv \/usr\/sbin\/sendmail \/usr\/sbin\/sendmail.ORIG\nln -s \/usr\/sbin\/ssmtp \/usr\/sbin\/sendmail\nmv \/usr\/lib\/sendmail \/usr\/lib\/sendmail.ORIG\nln -s \/usr\/sbin\/ssmtp \/usr\/lib\/sendmail\n<\/code><\/pre>\n\n\n\n<p>The above is essentially <code>wget<\/code>-ing the files we just created from the FTP server and storing them in the <code>\/tmp\/<\/code>directory. We replace <code>BLANKHOSTNAME<\/code> in the <code>ssmtp.conf<\/code> file with the VM&#8217;s <em>actual<\/em> hostname as required, and then copy the files to the correct location. We also rename the default <code>sendmail<\/code> files and replace them with symlinks to <code>ssmtp<\/code>. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Randomised root password<\/h3>\n\n\n\n<p>The next thing we&#8217;re going to tackle here is randomly generating our root password &#8211; from a security standpoint, it&#8217;s more secure to have <em>different<\/em> root passwords across multiple machines. If an attacker is able to breach <em>one<\/em> of your machines, in theory they shouldn&#8217;t be able to access anything else if each VM&#8217;s root password is different. <\/p>\n\n\n\n<p>One again, we need to open up our kickstart file and add a few lines into it. <br>Essentially this snip is generating a random string of 100 alphanumerical characters and then grabs the first <strong>15<\/strong> (or value for <code>HOWLONG<\/code>) characters. We then create and set permissions on a temporary password file, and echo the <code>NEWPW<\/code> value to the <code>passwd<\/code> command and also our temporary password file. <\/p>\n\n\n\n<pre title=\"\/var\/ftp\/centos7\/anaconda-ks.cfg\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">%post --log=\/tmp\/post-build.log\n...\n#########################################\n# Generate random root password\n# https:\/\/serverfault.com\/a\/976598\nHOWLONG=15 # How long our root password should be\nNEWPW=$(&lt; \/dev\/urandom tr -dc A-Za-z0-9 | head -c100 | head -c$((20+($RANDOM%20))) | tail -c$((20+($RANDOM%20))) | head -c${HOWLONG});\necho \"${NEWPW}\" |  passwd --stdin  root\ntouch \/tmp\/build\/password\nchmod 777 \/tmp\/build\/password\necho \"${NEWPW}\" >> \/tmp\/build\/password\n...\n%end<\/code><\/pre>\n\n\n\n<p>Next, we need to add the following underneath the above. Once again, we&#8217;re <code>wget<\/code>-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.  <\/p>\n\n\n\n<pre title=\"\/var\/ftp\/centos7\/anaconda-ks.cfg\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">%post --log=\/tmp\/post-build.log\n...\n#########################################\n# Copy our build cleanup script\nwget -O \/tmp\/build\/buildcleanup.sh ftp:\/\/10.176.10.2\/centos7\/config\/buildcleanup.sh\nchmod + \/tmp\/build\/buildcleanup.sh\necho \"@reboot sleep 60 &amp;&amp; \/tmp\/build\/buildcleanup.sh &amp;&amp; \/sbin\/shutdown -r now\" > \/var\/spool\/cron\/root\n...\n%end<\/code><\/pre>\n\n\n\n<p>And here&#8217;s the <code>buildcleanup<\/code> 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 <code>MAILTO<\/code>. The script also deletes our temporary working directory and resets the root crontab. <\/p>\n\n\n\n<pre title=\"\/var\/ftp\/centos7\/config\/buildcleanup.sh\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">#!\/bin\/bash\nsystemctl restart postfix\nsleep 15\nMAILTO='admin@yourdomain.tld'\nPASSWORDFILE=$(cat \/tmp\/build\/password)\necho \"The root password is $PASSWORDFILE\" | mail -s \"$HOSTNAME build complete!\" $MAILTO\nsleep 30\n\/bin\/rm -rf \/tmp\/build\/\n\/bin\/crontab -r<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Bringing it all together<\/h3>\n\n\n\n<p>So at this point we&#8217;ve modified our kickstart file a bunch, and created a bunch of files in our <code>\/var\/ftp\/centos7\/config<\/code> directory, so now what?<br>Before we do anything else, now is a good time to run <code>ksvalidator<\/code> against the kickstart to make sure there&#8217;s nothing wrong with it. everything good? Let&#8217;s try to build a VM!<\/p>\n\n\n\n<p>PXE boot a VM and run through the process the same as before &#8211; however, we&#8217;ll be promoted to enter a hostname, IP, subnet, default gateway and DNS server <em>before<\/em> the build starts. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1316\" height=\"800\" src=\"http:\/\/10.171.10.16:10000\/wp-content\/uploads\/2020\/08\/Install1.gif\" alt=\"\" class=\"wp-image-166\"\/><\/figure><\/div>\n\n\n\n<p>Once the build has finished, you&#8217;ll be sent to a login screen &#8211; after a couple of minutes, the VM should reboot once more, and you&#8217;ll receive an email from the VM containing the root password. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/10.171.10.16:10000\/wp-content\/uploads\/2020\/08\/2020-08-15-22_33_53-Webmail.jpg\" alt=\"\" class=\"wp-image-176\" width=\"609\" height=\"184\" srcset=\"https:\/\/dannypayne.me\/wp-content\/uploads\/2020\/08\/2020-08-15-22_33_53-Webmail.jpg 617w, https:\/\/dannypayne.me\/wp-content\/uploads\/2020\/08\/2020-08-15-22_33_53-Webmail-300x90.jpg 300w\" sizes=\"auto, (max-width: 609px) 100vw, 609px\" \/><\/figure><\/div>\n\n\n\n<p>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<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/10.171.10.16:10000\/wp-content\/uploads\/2020\/08\/2020-08-15-22_37_42-B-PXEBOOT-VMware-Workstation.jpg\" alt=\"\" class=\"wp-image-177\" width=\"428\" height=\"186\" srcset=\"https:\/\/dannypayne.me\/wp-content\/uploads\/2020\/08\/2020-08-15-22_37_42-B-PXEBOOT-VMware-Workstation.jpg 382w, https:\/\/dannypayne.me\/wp-content\/uploads\/2020\/08\/2020-08-15-22_37_42-B-PXEBOOT-VMware-Workstation-300x130.jpg 300w\" sizes=\"auto, (max-width: 428px) 100vw, 428px\" \/><\/figure>\n\n\n\n<p>Finally, for the purpose of demonstration, I commented out line <strong>9<\/strong> of the <code>buildcleanup.sh<\/code> script so the password file was not removed. If we now <code>cat<\/code> the <code>\/tmp\/build\/password<\/code> file, we&#8217;ll see that it contains our root password. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wrapping up<\/h3>\n\n\n\n<p>In this post we&#8217;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. <\/p>\n\n\n\n<p>In the next post I&#8217;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. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the third post in a series on building\/setting up\/improving a PXE boot server with CentOS.<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/dannypayne.me\/?p=146\">Read more<span class=\"screen-reader-text\">CentOS kickstart: more automation!<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":179,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[12,6],"tags":[],"class_list":["post-146","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-archive","category-homelab","excerpt","zoom","full-without-featured","even","excerpt-0"],"jetpack_featured_media_url":"https:\/\/dannypayne.me\/wp-content\/uploads\/2020\/08\/2020-08-16-14_29_26-B-PXEBOOT-VMware-Workstation.jpg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/dannypayne.me\/index.php?rest_route=\/wp\/v2\/posts\/146","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dannypayne.me\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dannypayne.me\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dannypayne.me\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dannypayne.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=146"}],"version-history":[{"count":28,"href":"https:\/\/dannypayne.me\/index.php?rest_route=\/wp\/v2\/posts\/146\/revisions"}],"predecessor-version":[{"id":190,"href":"https:\/\/dannypayne.me\/index.php?rest_route=\/wp\/v2\/posts\/146\/revisions\/190"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dannypayne.me\/index.php?rest_route=\/wp\/v2\/media\/179"}],"wp:attachment":[{"href":"https:\/\/dannypayne.me\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=146"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dannypayne.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=146"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dannypayne.me\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=146"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}