Script to implement FIPS (script updated 10/17/2018)
I made a script to implement FIPS 140-2 compliance based on what I found at https://access.redhat.com/solutions/137833. I suspect Red-Hatter Ryan Sawhill put that solution together.
- I have initially used
uname -rto detect the version of Linux (i.e. 7). - I did not use /etc/redhat-release as part of a conditional test because I have seen too many admins in various environments malign/edit /etc/redhat-release file for a number of reasons, so I personally can not trust the integrity of that file, and shall opt for a less-fragile method
- Hoever, I may transition this to an rpm check for
redhat-release-serverhowever, we use this script for both rhel 7.x workstation & server. - I am going to test a method for CentOS as well.
I realize the script can certainly be improved on.
Also, if anyone believes this script misses anything, I welcome feedback
Thanks Dusan Baljevic for finding errant typos and testing on UEFI systems (8/24/2018)
Regards,
-RJ
#!/bin/bash
#
# 10/17/2018 changed uname directives to use "uname -r" which works better in some environments. Additionally ensured quotes were paired (some were not in echo statements)
#
# this script was posted originally at https://access.redhat.com/discussions/3487481 and the most current edition is most likely (maybe) posted there... maybe.
# updated 8/24/2018 (thanks for those who provided inputs for update)
#
# Purpose, implement FIPS 140-2 compliance using the below article as a reference
# See Red Hat Article https://access.redhat.com/solutions/137833
## -- I suspect Red-Hatter Ryan Sawhill https://access.redhat.com/user/2025843 put that solution together (Thanks Ryan).
# see original article, consider "yum install dracut-fips-aesni"
# --> And special thanks to Dusan Baljevic who identified typos and tested this on UEFI
# NOTE: You can create a Red Hat Login for free if you are a developer,
# - Go to access.redhat.com make an account and then sign into
# - developers.redhat.com with the same credentials and then check your email and accept the Developer's agreement.
# Risks... 1) Make sure ${mygrub} (defined in script) is backed up as expected and the directives are in place prior to reboot
# Risks... 2) Make sure /etc/default/grub is backed up as expected and the proper directives are in place prior to reboot
# Risks... 3) Check AFTER the next kernel upgrade to make sure the ${mygrub} (defined in script) is properly populated with directives
# Risks... 4) Be warned that some server roles either do not work with FIPS enabled (like a Satellite Server) or of other issues, and you've done your research
# Risks... 5) There are more risks, use of this script is at your own risk and without any warranty
# Risks... 6) The above list of risks is -not- exhaustive and you might have other issues, use at your own risk.
# Recommend using either tmux or screen session if you are using a remote session, in case your client gets disconnected.
#
##### Where I found most of the directives... some was through my own pain with the cross of having to do stig compliance.
rhsolution="https://access.redhat.com/solutions/137833"
manualreview="Please manually perform the steps found at $rhsolution"
####### check if root is running this script, and bail if not root
# be root or exit
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit
fi
### bail if command sysctl crypto.fips_enable returns with "1" with the variable $answer below
configured="The sysctl crypto.fips_enabled command has detected fips is already configured, Bailing...."
notconfigured="fips not currently activated, so proceeding with script."
## Dusan's good suggestion...
answer=`sysctl crypto.fips_enabled`
yes='crypto.fips_enabled = 1'
if [ "$answer" == "$yes" ] ; then
echo -e "\n\t $configured \n"
exit 1
else
echo -e "\n\t $notconfigured \n"
fi
##### uefi check, bail if uefi (I do not have a configured uefi system to test this on)
######- Added 7/5/2018, do not proceed if this is a UEFI system... until we can test it reliably
[ -d /sys/firmware/efi ] && fw="UEFI" || fw="BIOS"
echo -e "$fw"
if [ "$fw" == "UEFI" ] ; then
echo -e "\n\tUEFI detected, this is a ($fw) system.\n\setting \$fw variable to ($fw)..."
mygrub='/boot/efi/EFI/redhat/grub.cfg'
### Thanks Dusan Baljevic for testing this.
### exit 1
else
echo -e "\n\t($fw) system detected, proceeding...\n"
mygrub='/boot/grub2/grub.cfg'
fi
##### rhel6 check really don't run this on a rhel6 box... and bail if it is rhel 6
myrhel6check=`uname -r | egrep 'el6'`
if [ "$myrhel6check" != "" ] ; then
echo -e "\n\tThis system is not RHEL 7, and Red Hat 6 is detected, \n\tThis script is intended for RHEL 7 systems only, bailing!!!\n"
exit 1
else
echo -e "\n\tRHEL 7 detectd, proceeding\n"
fi
##### rhel5 check really don't run this on a rhel5 box... and bail if it is rhel5
myrhel5check=`uname -r | egrep el5`
if [ "$myrhel5check" != "" ] ; then
echo -e "\n\tThis system is not RHEL 7, and Red Hat 5 is detected, \n\tThis script is intended for RHEL 7 systems only, bailing!!!\n"
exit 1
else
echo -e "\n\tNot RHEL 5, so proceeding...\n"
fi
##### only run if this returns el7 in the grep
# overkill? you bet, don't run unless this is rhel7
myrhel7check=`uname -r | grep el7`
if [ "$myrhel7check" != "" ] ; then
echo "RHEL 7 detected, Proceeding"
else
echo -e "\n\tThis system is not rhel7, \n\tBailing..."
echo exit 1
fi
######- add a second to $mydate variable
sleep 1
mydate=`date '+%Y%m%d_%H_%M_%S'`;echo $mydate
##### make backup copy $mygrub defined earlier
cp -v ${mygrub}{,.$mydate}
##### check fips in grub, if it's there, bail, if not proceed
myfipscheckingrub=`grep fips $mygrub | grep linux16 | egrep -v \# | head -1`
if [ "$myfipscheckingrub" != "" ] ; then
echo -e "FIPS directives detected in ($mygrub), \n\t\t($myfipscheckingrub)\n\tSo, recommend AGAINST running this script\n\t$manualreview"
exit 1
else
echo -e "\n\tFIPS directives not detected in ($mygrub)\n\tproceeding..."
fi
##### fips should not be in /etc/default/grub, if so, bail
etcdefgrub='/etc/default/grub'
myfipschecketcdefgrub=`grep fips $etcdefgrub | grep -v \#`
if [ "$myfipschecketcdefgrub" != "" ] ; then
echo -e "FIPS directives detected in ($etcdefgrub), \n\t\t($myfipschecketcdefgrub)\n\tSo, recommend AGAINST running this script\n\t$manualreview"
echo exit 1
else
echo -e "\n\tFIPS directives not detected in ($etcdefgrub)\n\tproceeding..."
fi
##### verify that this system is actually in the same kernel as we're going to install this in..., or bail
# if they don't match, the script bails.
mydefkern=`grubby --default-kernel | sed 's/.*vmlinuz\-//g'| awk '{print $1}'`
myuname=`uname -r`
if [ "$mydefkern" != "$myuname" ] ; then
echo -e "\n\tKernel Mismatch between running and installed kernel...\n\tThe default kernel is: $mydefkern\n\tThe running kernel is $myuname\n\n\tPlease reboot this system and then re-run this script\n\tBailing...\n"
exit 1
else
echo "Default Kernel ($mydefkern) and Current Running Kernel ($myuname) match, proceeding"
fi
##### overkill, yes
# yes, there's an number of checks above, but I'm still persisting with this, just in case someone runs this script twice.
# it will never reach this if it fails any of the previous checks, but I'll leave it.
##### a file named "/root/fipsinstalled" is created at the end of this script. So I'll check for it at the beginning so that this script is only ran once.
if [ -f /root/fipsinstalled ] ; then
sysctl crypto.fips_enabled
echo -e "\tThis script was ran previously,\n\t nothing to do, \n\texiting..."
exit 1
else
echo "continuing" >/dev/null
echo proceeding...
fi
############################################################################################
############################################################################################
############################################################################################
##### this is where the script actually begins to make modifications.
# -- everything before was either a check, or a backup of a config
# Only install dracut-fips if it is not installed (that's the "||" below)
rpm -q dracut-fips > /dev/null || yum -y install dracut-fips
##### warn people not to bail at this point, pause 4 seconds so they might see it if they're watching the screen.
echo -e "\n\n\n\tWARNING!!!: \n\tWARNING!!!DO NOT INTERRUPT THIS SCRIPT OR IT CAN CAUSE \n\tTHE SYSTEM TO BECOME UNBOOTABLE!!!!\n\tPlease be patient it will take some time...\n\tWARNING!!!\n\tWARNING\n\n\n"
sleep 4
##### next disable prelinking
rpm -q prelink >/dev/null && grep PRELINKING /etc/sysconfig/prelink
##### slightly lesser known use of sed, it only flips PRELINKING to "no"
# this flips "yes" to "no" in the prelink config file, next kills prelinking
rpm -q prelink >/dev/null && sed -i '/^PRELINKING/s,yes,no,' /etc/sysconfig/prelink
rpm -q prelink >/dev/null && prelink -uav 2>/tmp/err
/bin/cp -v /etc/aide.conf{,.undofips}
rpm -q prelink >/dev/null && sed -i 's/^NORMAL.*/NORMAL = FIPSR+sha512/' /etc/aide.conf
##### update the $mydate variable which is used to copy off backups of various configs throughout the rest of this script.
mydate=`date '+%Y%m%d_%H_%M_%S'`;echo $mydate
###-----###
# back up existing initramfs
mv -v /boot/initramfs-$(uname -r).img{,.$mydate}
##### warn people not to bail at this point, pause 4 seconds so they might see it if they're watching the screen.
##### really, don't interrupt this portion.
echo -e "\n\n\n\tWARNING!!!: \n\tWARNING!!!DO NOT INTERRUPT THIS SCRIPT OR IT CAN CAUSE \n\tTHE SYSTEM TO BECOME UNBOOTABLE!!!!\n\tPlease be patient it will take some time...\n\tWARNING!!!\n\tWARNING!!!\n\n\n"
# this pauses as before so the person running this script gets a chance to see the above, it also is to allow the $mydate variable below to get a new value
sleep 3
# run dracut
dracut
mydate=`date '+%Y%m%d_%H_%M_%S'`
###-----###
###### The Red Hat solution I cited earlier in the comments, this is where this came from
# this section below updates /boot/grub/grub.cfg with fips and the uuid of the boot device
# first back it up
/bin/cp ${mygrub}{,.$mydate}
grubby --update-kernel=$(grubby --default-kernel) --args=fips=1
###### this displays the kernel lines in grub with fips
grep fips ${mygrub} | grep linux16
###### that Red Hat solution I cited earlier in the comments, this is where this came from
# set the uuid variable to be used later
uuid=$(findmnt -no uuid /boot)
echo -e "\n\t Just for reference, the /boot uuid is: ($uuid)\n"
###### that Red Hat solution I cited earlier in the comments, this is where this came from
# update the boot uuid for fips in ${mygrub}
# the 2nd line is to satisfy the disa stig checker which checks every single menu entry linux16 line. without it, the check fails.
[[ -n $uuid ]] && grubby --update-kernel=$(grubby --default-kernel) --args=boot=UUID=${uuid}
sed -i "/linux16 \/vmlinuz-0-rescue/ s/$/ fips=1 boot=UUID=${uuid}/" ${mygrub}
###### that Red Hat solution I cited earlier in the comments, this is where this came from
# update /etc/default/grub for subsequent kernel updates. this APPENDS to the end of the line.
sed -i "/^GRUB_CMDLINE_LINUX/ s/\"$/ fips=1 boot=UUID=${uuid}\"/" /etc/default/grub
grep -q GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub || echo 'GRUB_CMDLINE_LINUX_DEFAULT="fips=1"' >> /etc/default.grub
echo -e "\n\tThe next line shows the new grub line with fips in the two locations below:\n"
grep $uuid ${mygrub} | grep linux16
echo;grep $uuid /etc/default/grub
### warning ### warning ###
### Note, if you do not change Ciphers and MACs prior to reboot, you will NOT be able to ssh to the system. That could be a problem depending on the distance or difficulty of getting a console or physical access to fix after reboot. Be warned.
###
mydate=`date '+%Y%m%d_%H_%M_%S'`;echo $mydate
cp -v /etc/ssh/sshd_config{,.$mydate}
# without this, no ssh, really, ask me how I know
sed -i 's/^Cipher.*/Ciphers aes128-ctr,aes192-ctr,aes256-ctr/' /etc/ssh/sshd_config
sed -i 's/^MACs.*/MACs hmac-sha2-256,hmac-sha2-512/' /etc/ssh/sshd_config
# bread crumbs
touch /root/fipsinstalled
chattr +i /root/fipsinstalled
###### the command to check this after reboot is: sysctl crypto.fips_enabled
echo -e "\n\tScript has completed. \n\tSystem must be rebooted for fips to be enabled. \n\tPlease check the following 2 files for sane entries:\n\t/etc/default/grub \n\t${mygrub}. \n\n\tAlso, --AFTER--REBOOT--as-root-- run sysctl crypto.fips_enabled and the output must be \n\t'crypto.fips_enabled = 1' \n"
##### without this, the disa provided stig checker fails fips compliance, you're welcome
echo 'GRUB_CMDLINE_LINUX_DEFAULT="fips=1"' >> /etc/default/grub
rpm -q prelink > /dev/null && rpm -e prelink > /dev/null
##### Same with this...
/bin/chmod 0600 /etc/ssh/ssh_host*key
Numerous updates 8/23/2018
| sha256sum | File name |
|---|---|
| 08383d4290d10bb55feac1deaacf3a3ab929445d3c1f7023df5548a9a93ea4f9 | enablefips_20180823.bash |
| 06f59213eafa2d09a55f49e55156dac32e0e99f70bd7edda8a154280b6ef4d76 | enablefips_20180823.bash.tar |
| a1525a33ec30f64ad1eb397fdc42ab3a55c253a26e317a7a9ecc8ed843668300 | enablefips_20180824.bash |
| 9277aa4e4ab00c9581fd9c9b22691298ed9ed97285626139add034e9c8c3a7ae | enablefips_20180824.bash_.tar |
Attachments
Responses
Hi,
Your script worked well on RHEL 7.5 VM (VMware). The only issue was a slight typing error:
...
Script has completed.
System must be rebooted for fips to be enabled.
Please check the following 2 files for sane entries:
/etc/default/grub
/boot/grub2/grub.conf.
With GRUB2, the config is grub.cfg, not grub.conf.
This was the check on my test system:
# diff /etc/default/grub /etc/default/grub.20180702_10_00_29
6c6
< GRUB_CMDLINE_LINUX="nofb splash=quiet crashkernel=auto rd.lvm.lv=os/root rd.lvm.lv=os/swap rd.lvm.lv=os/usr rhgb quiet audit=1 net.ifnames=0 biosdevname=0" fips=1 boot=UUID=34ddebd6-f281-401b-9ad8-e009b08337f1
---
> GRUB_CMDLINE_LINUX="nofb splash=quiet crashkernel=auto rd.lvm.lv=os/root rd.lvm.lv=os/swap rd.lvm.lv=os/usr rhgb quiet audit=1 net.ifnames=0 biosdevname=0"
# diff /boot/grub2/grub.cfg /boot/grub2/grub.cfg.20180702_10_00_29
114c114
< linux16 /vmlinuz-3.10.0-862.3.2.el7.x86_64 root=/dev/mapper/os-root ro nofb splash=quiet crashkernel=auto rd.lvm.lv=os/root rd.lvm.lv=os/swap rd.lvm.lv=os/usr rhgb quiet audit=1 net.ifnames=0 biosdevname=0 LANG=en_US.UTF-8 fips=1 boot=UUID=34ddebd6-f281-401b-9ad8-e009b08337f1
---
> linux16 /vmlinuz-3.10.0-862.3.2.el7.x86_64 root=/dev/mapper/os-root ro nofb splash=quiet crashkernel=auto rd.lvm.lv=os/root rd.lvm.lv=os/swap rd.lvm.lv=os/usr rhgb quiet audit=1 net.ifnames=0 biosdevname=0 LANG=en_US.UTF-8
# diff /etc/ssh/sshd_config /etc/ssh/sshd_config.20180702_10_00_29
146c146
< MACs hmac-sha2-256,hmac-sha2-512
---
> MACs hmac-sha1,umac-64@openssh.com,hmac-ripemd160
# sysctl crypto.fips_enabled
crypto.fips_enabled = 1
Best wishes,
Dusan Baljevic (amateur radio VK2COT)
Something I forgot to mention...
It would be good to be careful about proceeding in each step if it fails.
For example, abort if the dracut-fips cannot be installed (for whatever reason):
yum -y install dracut-fips || exit
If it is run on a system which already has it, it will proceed safely:
# yum -y install dracut-fips || exit
Loaded plugins: langpacks, product-id, rhnplugin, search-disabled-repos, subscription-manager
This system is receiving updates from RHN Classic or Red Hat Satellite.
Package dracut-fips-033-535.el7.x86_64 already installed and latest version
Nothing to do
Also, I would prefer to check if FIPS was already installed without relying on a template file /root/fipsinstalled. Something like this:
if [ "$(sysctl crypto.fips_enabled | awk -F= '{print $2}' | sed -e 's/^[[:space:]]*//')" == 1 ]; then
echo -e "\tThis script was ran previously,\n\t nothing to do, \n\texiting..."
exit 1
fi
Regards,
Dusan Baljevic (amateur radio VK2COT)
... And on physical servers (in this case HP blade), the config file is:
/boot/efi/EFI/redhat/grub.cfg
... so it would be good to preserve the original version before installation. Something like:
/boot/efi/EFI/redhat/grub.cfg.20180702_14_24_02
Regards,
Dusan Baljevic (amateur radio VK2COT)
Hi,
Good point about EFI. I only mentioned it for physical servers because that is what I could test :)
In regards how to check it, here are some possibilities:
Verify if directory /sys/firmware/efi exists.
Verify results of command:
efibootmgr
It is nice to see friendly co-operation in the forum.
Regards,
Dusan Baljevic (amateur radio VK2COT)
Hi RJ,
Very good effort on your side.
I just ran the updated script on one of my RHEL 7.5 VMs and it worked, with two small errors:
a) It complained about prelink missing, but kept on trying to use it or refer to it five times.
b) There is a slight typing error on line 98. The variable is not "$etcdefgub" but should be "$etcdefgrub".
if [ "$myfipschecketcdefgrub" != "" ] ; then
95 echo -e "FIPS directives detected in ($etcdefgrub), \n\t\t($myfipschecketcdefgrub)\n\tSo, recommend AGAINST running this script\n\t$manualreview"
96 echo exit 1
97 else
98 echo -e "\n\tFIPS directives not detected in ($etcdefgub)\n\tproceeding..."
99 fi
As a consequence, one gets ambiguous result of the run:
...
FIPS directives not detected in (/boot/grub2/grub.cfg)
proceeding...
FIPS directives not detected in ()
proceeding...
...
I hope you do not mind me being pedantic :)
Regards,
Dusan Baljevic (amateur radio VK2COT)
Hi R. Hinton,
Good work, as always.
I ran the script on RHEL 7.5 HP Blade:
dmidecode | awk '/Product Name|UEFI/ {print}' | sed -e 's/^[[:space:]]*//g' && sysctl crypto.fips_enabled
UEFI is supported
Product Name: ProLiant BL460c Gen9
UEFI: No
crypto.fips_enabled = 0
In the first attempt, the script failed due to the following:
fips not currently activated, so proceeding with script.
UEFI
This system is a UEFI system and this script requires further testing before production with UEFI.
Perform yourown tests implementing FIPS on this (UEFI) system.
Bailing...
After I removed the "exit 1" on line 55, it worked:
if [ "$fw" == "UEFI" ] ; then
echo -e "\n\tThis system is a UEFI system and this script requires further testing before production with UEFI.\n\tPerform yourown tests implementing FIPS on this ($fw) system.\n\tBailing..."
mygrub='/boot/efi/EFI/redhat/grub.cfg'
exit 1
A few suggestions:
a) Typing error:
"yourown" should probably be "your own"
b) At least on my UEFI server, both of these files exist:
ls -als /boot/efi/EFI/redhat/grub.cfg /boot/grub2/grub.cfg
16 -rwx------ 1 root root 10008 Aug 24 13:28 /boot/efi/EFI/redhat/grub.cfg
8 -rw-r--r-- 1 root root 6619 Aug 24 13:28 /boot/grub2/grub.cfg
c) There is no "/boot/grub2/grub.conf" in my UEFI server. Instead, there is "/boot/grub2/grub.cfg".
Therefore, this line might need to be changed:
echo -e "\n\tScript has completed. \n\tSystem must be rebooted for fips to be enabled. \n\tPlease check the following 2 files for sane entries:\n\t/etc/default/grub \n\t/boot/grub2/grub.conf. \n\n\tAlso, --AFTER--REBOOT--as-root-- run sysctl crypto.fips_enabled and the output must be \n\t'crypto.fips_enabled = 1' \n"
d) Maybe you could also add the option to remove FIPS. Something like options to the script.
This worked for me:
yum -y remove dracut-fips\*
dracut --force
grubby --update-kernel=ALL --remove-args=fips=1
sed -i 's/ fips=1//' /etc/default/grub
chattr -i /root/fipsinstalled && rm /root/fipsinstalled
Final result after running your script shows success:
dmidecode | awk '/Product Name|UEFI/ {print}' | sed -e 's/^[[:space:]]*//g' && sysctl crypto.fips_enabled
UEFI is supported
Product Name: ProLiant BL460c Gen9
UEFI: No
crypto.fips_enabled = 1
Regards,
Dusan Baljevic (Amateur Radio Vk2COT)
Hi RJ,
In my free time, I added support for uninstalling FIPS.
Maybe you find it useful in the final version :)
#!/bin/bash
# this script was posted originally at https://access.redhat.com/discussions/3487481 and the most current edition is most likely (maybe) posted there... maybe.
# updated 9/18/2018 (thanks for those who provided inputs for update)
#
# Purpose, implement FIPS 140-2 compliance using the below article as a reference
# See Red Hat Article https://access.redhat.com/solutions/137833
## -- I suspect Red-Hatter Ryan Sawhill https://access.redhat.com/user/2025843 put that solution together (Thanks Ryan).
# see original article, consider "yum install dracut-fips-aesni"
# --> And special thanks to Dusan Baljevic who identified typos and tested this on UEFI
# NOTE: You can create a Red Hat Login for free if you are a developer,
# - Go to access.redhat.com make an account and then sign into
# - developers.redhat.com with the same credentials and then check your email and accept the Developer's agreement.
# Risks... 1) Make sure ${mygrub} (defined in script) is backed up as expected and the directives are in place prior to reboot
# Risks... 2) Make sure /etc/default/grub is backed up as expected and the proper directives are in place prior to reboot
# Risks... 3) Check AFTER the next kernel upgrade to make sure the ${mygrub} (defined in script) is properly populated with directives
# Risks... 4) Be warned that some server roles either do not work with FIPS enabled (like a Satellite Server) or of other issues, and you've done your research
# Risks... 5) There are more risks, use of this script is at your own risk and without any warranty
# Risks... 6) The above list of risks is -not- exhaustive and you might have other issues, use at your own risk.
# Recommend using either tmux or screen session if you are using a remote session, in case your client gets disconnected.
#
# Set PATH varaible to secure directories
#
PATH=/sbin:/bin:/usr/bin:/usr/sbin; export PATH
# Variables
sshdconf="/etc/ssh/sshd_config"
defgrub="/etc/default/grub"
aideconf="/etc/aide.conf"
# Default options
#
opt1=""
opt2=""
##### rectives... some was through my own pain with the cross of having to do stig compliance.
rhsolution="https://access.redhat.com/solutions/137833"
manualreview="Please manually perform the steps found at $rhsolution"
####### check if root is running this script, and bail if not root
# be root or exit
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit
fi
### bail if command sysctl crypto.fips_enable returns with "1" with the variable $answer below
configured="The sysctl crypto.fips_enabled command has detected fips is already configured, Bailing...."
notconfigured="fips not currently activated"
## Dusan's good suggestion...
answer=`sysctl crypto.fips_enabled`
yes='crypto.fips_enabled = 1'
if [ "$answer" == "$yes" ] ; then
echo -e "\n\t $configured \n"
exit 1
fi
# Usage reminder
#
usage() {
cat <<EOF
USAGE: \$0 [-i|-d|-h]
-d Deinstall FIPS
-h Help Menu
-i Implement FIPS
EOF
}
# Process command-line arguments
#
while getopts "dhi" o; do
case "${o}" in
i) opt1="INSTALL" ;;
d) opt2="DEINSTALL" ;;
h) usage ;;
*) echo "ERROR: Wrong command-line arguments"
usage
exit 1 ;;
esac
done
shift $((OPTIND-1))
selectedoption="${opt1:-$opt2}"
case "$selectedoption" in
INSTALL) ;;
DEINSTALL) if [ "$answer" == "$yes" ] ; then
yum -y remove dracut-fips\*
dracut --force
grubby --update-kernel=ALL --remove-args=fips=1
chattr -i /root/fipsinstalled && rm /root/fipsinstalled
echo "Check MACs and Ciphers in $sshdconf"
exit 0
else
echo -e "\n\t $notconfigured - no action required\n"
fi
;;
*) exit 1 ;;
esac
##### uefi check, bail if uefi (I do not have a configured uefi system to test this on)
######- Added 7/5/2018, do not proceed if this is a UEFI system... until we can test it reliably
[ -d /sys/firmware/efi ] && fw="UEFI" || fw="BIOS"
echo -e "$fw"
if [ "$fw" == "UEFI" ] ; then
echo -e "\n\tUEFI detected, this is a ($fw) system.\n\setting \$fw variable to ($fw)..."
mygrub='/boot/efi/EFI/redhat/grub.cfg'
### Thanks Dusan Baljevic for testing this.
### exit 1
else
echo -e "\n\t($fw) system detected, proceeding...\n"
mygrub='/boot/grub2/grub.cfg'
fi
##### rhel6 check really don't run this on a rhel6 box... and bail if it is rhel 6
myrhel6check=`uname -a | egrep el6`
if [ "$myrhel6check" != "" ] ; then
echo -e "\n\tThis system is not RHEL 7, and Red Hat 6 is detected, \n\tThis script is intended for RHEL 7 systems only, bailing!!!\n
exit 1
else
echo -e "\n\tRHEL 7 detectd, proceeding\n"
fi
##### rhel5 check really don't run this on a rhel5 box... and bail if it is rhel5
myrhel5check=`uname -a | egrep el5`
if [ "$myrhel5check" != "" ] ; then
echo -e "\n\tThis system is not RHEL 7, and Red Hat 5 is detected, \n\tThis script is intended for RHEL 7 systems only, bailing!!!\n
exit 1
else
echo -e "\n\tNot RHEL 5, so proceeding...\n"
fi
##### only run if this returns el7 in the grep
# overkill? you bet, don't run unless this is rhel7
myrhel7check=`uname -a | grep el7`
if [ "$myrhel7check" != "" ] ; then
echo "RHEL 7 detected, Proceeding"
else
echo -e "\n\tThis system is not rhel7, \n\tBailing..."
echo exit 1
fi
######- add a second to $mydate variable
sleep 1
mydate=`date '+%Y%m%d_%H_%M_%S'`;echo $mydate
##### make backup copy $mygrub defined earlier
cp -v ${mygrub}{,.$mydate}
##### check fips in grub, if it's there, bail, if not proceed
myfipscheckingrub=`grep fips $mygrub | grep linux16 | egrep -v \# | head -1`
if [ "$myfipscheckingrub" != "" ] ; then
echo -e "FIPS directives detected in ($mygrub), \n\t\t($myfipscheckingrub)\n\tSo, recommend AGAINST running this script\n\t$manualreview"
exit 1
else
echo -e "\n\tFIPS directives not detected in ($mygrub)\n\tproceeding..."
fi
##### fips should not be in /etc/default/grub, if so, bail
etcdefgrub='/etc/default/grub'
myfipschecketcdefgrub=`grep fips $etcdefgrub | grep -v \#`
if [ "$myfipschecketcdefgrub" != "" ] ; then
echo -e "FIPS directives detected in ($etcdefgrub), \n\t\t($myfipschecketcdefgrub)\n\tSo, recommend AGAINST running this script\n\t$manualreview"
echo exit 1
else
echo -e "\n\tFIPS directives not detected in ($etcdefgrub)\n\tproceeding..."
fi
##### verify that this system is actually in the same kernel as we're going to install this in..., or bail
# if they don't match, the script bails.
mydefkern=`grubby --default-kernel | sed 's/.*vmlinuz\-//g'| awk '{print $1}'`
myuname=`uname -r`
if [ "$mydefkern" != "$myuname" ] ; then
echo -e "\n\tKernel Mismatch between running and installed kernel...\n\tThe default kernel is: $mydefkern\n\tThe running kernel is $myuname\n\n\tPlease reboot this system and then re-run this script\n\tBailing...\n"
exit 1
else
echo "Default Kernel ($mydefkern) and Current Running Kernel ($myuname) match, proceeding"
fi
##### overkill, yes
# yes, there's an number of checks above, but I'm still persisting with this, just in case someone runs this script twice.
# it will never reach this if it fails any of the previous checks, but I'll leave it.
##### a file named "/root/fipsinstalled" is created at the end of this script. So I'll check for it at the beginning so that this script is only ran once.
if [ -f /root/fipsinstalled ] ; then
sysctl crypto.fips_enabled
echo -e "\tThis script was ran previously,\n\t nothing to do, \n\texiting..."
exit 1
else
echo "continuing" >/dev/null
echo proceeding...
fi
############################################################################################
############################################################################################
############################################################################################
##### this is where the script actually begins to make modifications.
# -- everything before was either a check, or a backup of a config
# Only install dracut-fips if it is not installed (that's the "||" below)
rpm -q dracut-fips > /dev/null || yum -y install dracut-fips
##### warn people not to bail at this point, pause 4 seconds so they might see it if they're watching the screen.
echo -e "\n\n\n\tWARNING!!!: \n\tWARNING!!!DO NOT INTERRUPT THIS SCRIPT OR IT CAN CAUSE \n\tTHE SYSTEM TO BECOME UNBOOTABLE!!!!\n\tPlease be patient it will take some time...\n\tWARNING!!!\n\tWARNING\n\n\n"
sleep 4
##### next disable prelinking
rpm -q prelink >/dev/null && grep PRELINKING /etc/sysconfig/prelink
##### slightly lesser known use of sed, it only flips PRELINKING to "no"
# this flips "yes" to "no" in the prelink config file, next kills prelinking
rpm -q prelink >/dev/null && sed -i '/^PRELINKING/s,yes,no,' /etc/sysconfig/prelink
rpm -q prelink >/dev/null && prelink -uav 2>/tmp/err
/bin/cp -v ${aideconf}{,.undofips}
rpm -q prelink >/dev/null && sed -i 's/^NORMAL.*/NORMAL = FIPSR+sha512/' $aideconf
##### update the $mydate variable which is used to copy off backups of various configs throughout the rest of this script.
mydate=`date '+%Y%m%d_%H_%M_%S'`;echo $mydate
###-----###
# back up existing initramfs
mv -v /boot/initramfs-$(uname -r).img{,.$mydate}
##### warn people not to bail at this point, pause 4 seconds so they might see it if they're watching the screen.
##### really, don't interrupt this portion.
echo -e "\n\n\n\tWARNING!!!: \n\tWARNING!!!DO NOT INTERRUPT THIS SCRIPT OR IT CAN CAUSE \n\tTHE SYSTEM TO BECOME UNBOOTABLE!!!!\n\tPlease be patient it will take some time...\n\tWARNING!!!\n\tWARNING!!!\n\n\n"
# this pauses as before so the person running this script gets a chance to see the above, it also is to allow the $mydate variable below to get a new value
sleep 3
# run dracut
dracut
mydate=`date '+%Y%m%d_%H_%M_%S'`
###-----###
###### The Red Hat solution I cited earlier in the comments, this is where this came from
# this section below updates /boot/grub/grub.cfg with fips and the uuid of the boot device
# first back it up
/bin/cp ${mygrub}{,.$mydate}
grubby --update-kernel=$(grubby --default-kernel) --args=fips=1
###### this displays the kernel lines in grub with fips
grep fips ${mygrub} | grep linux16
###### that Red Hat solution I cited earlier in the comments, this is where this came from
# set the uuid variable to be used later
uuid=$(findmnt -no uuid /boot)
echo -e "\n\t Just for reference, the /boot uuid is: ($uuid)\n"
###### that Red Hat solution I cited earlier in the comments, this is where this came from
# update the boot uuid for fips in ${mygrub}
# the 2nd line is to satisfy the disa stig checker which checks every single menu entry linux16 line. without it, the check fails.
[[ -n $uuid ]] && grubby --update-kernel=$(grubby --default-kernel) --args=boot=UUID=${uuid}
sed -i "/linux16 \/vmlinuz-0-rescue/ s/$/ fips=1 boot=UUID=${uuid}/" ${mygrub}
###### that Red Hat solution I cited earlier in the comments, this is where this came from
# update /etc/default/grub for subsequent kernel updates. this APPENDS to the end of the line.
sed -i "/^GRUB_CMDLINE_LINUX/ s/\"$/ fips=1 boot=UUID=${uuid}\"/" $defgrub
grep -q GRUB_CMDLINE_LINUX_DEFAULT $defgrub || echo 'GRUB_CMDLINE_LINUX_DEFAULT="fips=1"' >>$defgrub
echo -e "\n\tThe next line shows the new grub line with fips in the two locations below:\n"
grep $uuid ${mygrub} | grep linux16
echo;grep $uuid $defgrub
### warning ### warning ###
### Note, if you do not change Ciphers and MACs prior to reboot, you will NOT be able to ssh to the system. That could be a problem depending on the distance or difficulty of getting a console or physical access to fix after reboot. Be warned.
###
mydate=`date '+%Y%m%d_%H_%M_%S'`;echo $mydate
cp -v ${sshdconf}{,.$mydate}
# without this, no ssh, really, ask me how I know
sed -i 's/^Cipher.*/Ciphers aes128-ctr,aes192-ctr,aes256-ctr/' $sshdconf
sed -i 's/^MACs.*/MACs hmac-sha2-256,hmac-sha2-512/' $sshdconf
# bread crumbs
touch /root/fipsinstalled
chattr +i /root/fipsinstalled
###### the command to check this after reboot is: sysctl crypto.fips_enabled
echo -e "\n\tScript has completed. \n\tSystem must be rebooted for fips to be enabled. \n\tPlease check the following 2 files for sane entries:\n\t${defgrub} \n\t${mygrub}. \n\n\tAlso, --AFTER--REBOOT--as-root-- run sysctl crypto.fips_enabled and the output must be \n\t'crypto.fips_enabled = 1' \n"
##### without this, the disa provided stig checker fails fips compliance, you're welcome
echo 'GRUB_CMDLINE_LINUX_DEFAULT="fips=1"' >> $defgrub
rpm -q prelink > /dev/null && rpm -e prelink > /dev/null
##### Same with this...
/bin/chmod 0600 /etc/ssh/ssh_host*key
Regards,
Dusan Baljevic (Amateur radio VK2COT)
Just a heads up that anyone trying to use this on AWS, it will not work. In AWS there is not a dedicated /boot partition. AWS uses /boot and /root as the same thing. I made a few changes to the script to get it to work. I think you could add a check to see if a /boot and /root partition exist and if they do do what you currently have written, otherwise the changes would be:
# set the uuid variable to be used later
uuid=$(findmnt -no uuid /root)
echo -e "\n\t Just for reference, the /root uuid is: ($uuid)\n"
(changed /boot to /root)
# update /etc/default/grub for subsequent kernel updates. this APPENDS to the end of the line.
sed -i "/^GRUB_CMDLINE_LINUX/ s/\"$/ fips=1 root=UUID=${uuid}\"/" $defgrub
(changed boot= to root=)
Note this will probably fail on a DISA stig check as the checker looks for literally 'boot' in the lines but it would just be a false positive.
RJ,
You are right, there has to be a better way of determining if a instance is hosted in AWS rather than the no /boot entry.
The proper way to search would be to do a:
cat /sys/hypervisor/uuid
AWS hosted things will have that file and it will start with ec2(then have a string) e.g. ec242583-2ceb-df5b-c9be-d47ceba67912 (no, that is not a real UUID but it is the correct format)
The other option is to do:
sudo cat /sys/devices/virtual/dmi/id/product_uuid
That will also return a string that starts with EC2 e.g. EC258316-3CDB-DG7C-C9BC-E04CEBA37537 (no, that is not a real UUID but it is the correct format)
RJ,
The first line, cat /sys/hypervisor/uuid, is probably the best check as thats something that AWS puts into their instances. If you run that on any instance not on AWS you will get 'No such file or directory' the second check is just another failsafe. Since you have a few different bail out statements, I think it wouldn't be bad to have 2 checks for AWS.
Here is also a link to an AWS articles that says how to check if an instance is EC2 hosted. It says basically the same thing I listed: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html
Hi,
I can confirm that Tyler's suggestion is fine.
From one instance just checked by my friend:
$ sudo cat /sys/hypervisor/uuid
ec24635b-1f10-733b-bea6-6221ce4e9e60
$ sudo cat /sys/devices/virtual/dmi/id/product_uuid
EC24635B-1F10-733B-BEA6-6221CE4E9E60
And indeed, there is no /boot file system. By default, the EC2 instances only have one file system:
/dev/xvda1 /
Regards,
Dusan Baljevic (Amateur Radio VK2COT)
Welcome! Check out the Getting Started with Red Hat page for quick tours and guides for common tasks.
