99.6% Compliant RHEL 8 STIG method using Security Profile (no warranty)

Latest response

RHEL 8 STIG method with post script using RHEL 8 STIG profile for over 90% compliance

Updates in progress

NOTE: the items in the attached post script were ran manually on my initial victim system AFTER build using the security profile "DISA STIG for Red Hat Enterprise Linux 8" in an ISO build using a normal RHEL 8.4 dvd is what brought the compliance to 99.6%. with the use of the security profile mentioned below.

  • I'll make an after-script to be ran for this.
  • The kickstart file will be republished at a later time.
  • In the meantime, the postscript._.bash.txt has the mitigations that takes a system from a mere 60% compliance to 99.6%.
  • I'm also in the process of making a total STIG build without the security policy.


  • Red Hat Enterprise Linux 8

RJ's To-do list...

  • It seems many mitigations in the %post script of the kickstart get clobbered. So either make a post script, or another method.
  • make a post-install means to put the proper edits in /etc/authselect/password-auth and system-auth files because "cat << EOF > /the/file" fails because at the end, these files are generated.
  • When doing a RHEL8 kickstart use "linux inst.ks=http://ip_address/pub/ks/kickstart_file.cfg" because "linux ks http://..." fails due to changes in RHEL8. see paragraph 7.1 step 2 sub-step ii
  • More to come.


  • Using the Red Hat ISO with the Security Profile xccdf_org.ssgproject.content_profile_stig aka "DISA STIG for Red Hat Enterprise Linux 8" only results in about 60% compliance.
  • I've created the necessary post-script to bring compliance to 99.6 compliance. Please see the "Expectations" section below before adopting this).
  • I'll make another version later that does the same as this without the heavy weight of a security profile, to give the admin more choices on what to accept, not to accept based on their own specific environment operational needs.
  • There's one thing I didn't bother resolving in the DISA STIG, I'm going to open a ticket with Red Hat. The item has to do with specific files being 0755 (strip off suid an sguid bits) which I do not necessarily concur with, because the suid and sguid bits seem reasonable, at least at this review stage. However 99.6% compliance is not so terribly horrible.

Expectation Control

  • Is there a warranty for this? Absolutely not, use at your own peril. The success rate grows as you read the comments and sanely adjust appropriately for your specific environment needs.
  • Is this provided by Red Hat? No, this is the Red Hat Discussion area, and this material is a volunteer effort.
  • Important Note 1: Recommend testing in your pre-established test environment with a sane test plan prior to pushing this to production.
  • Important Note 2: If you use the kickstart, you will need to change the partitioning, I've mentioned this in the kickstart file. Why are there so many partitions? See the RHEL8 STIG for details.
  • Important Note 3: I provided a script to create a password hash from another Red Hat solution because if you use the kickstart , you will want to know the password and not have the password open in the clear.
  • Will this mean you can use this in your production with no issue? (answer, yes but be warned, you will have to probably remove specific mitigations for your specific environment)
  • There are other files such as "password-auth" and "system-auth" that are at the end of the kickstart that overwrite the original files per the STIG. I make backups of the original files you can review.
  • If you discover an rpm is causing you an issue such as usbguard, the way to address this is not in the discussion area here, but with an official bugzilla report at bugzilla.redhat.com or at minimum, a ticket with Red Hat.
  • The /etc/audit/auditd.conf file needs work namely with "/etc/audit/auditd.conf" with the directives named "space_left = 25%" and "admin_space_left" requires more research.
  • Important note 3: The kickstart assumes "sda" as a drive, if this is not you case, change it appropriately.


  • Red Hat mandates the use of specific file extensions when uploading them here
  • The provided files are below under "Attachments", please rename them appropriately.

SeLinux is on, please do not disable it.

Checking with DISA STIG scc software and Benchmark

  • The use of DISA SCAP STIG tools is a complicated matter to the uninitiated.
  • Go to the public URL https://public.cyber.mil/stigs/scap/
  • Look for "SCAP TOOLS" and type RHEL in that search box. Download the most current "SCC" file (as I type this, it reads: "SCC 5.4.1 RHEL 8 x86 64") and get it to your system. You can use wget (I did once). I can't find the signing key, you'll have to install it with rpm -ivh RPM_NAME
  • Look for "SCAP 1.2 CONTENT" and type RHEL in that search box, and look for the most current Benchmark, download it. As I type this, it is "RHEL 8 STIG Benchmark - Ver 1, Rel 2" This will change over time.
  • Unzip both of these files.
  • Install the rpm rpm -ivh scc-5.4.1.rhel8.x86_64.rpmThe RPM name is "spawarscc-5.4.1-0.x86_64" SCAP Compliance checker. THE VERSION WILL CHANGE.
  • After this succeeds, remove the not-needed worthless benchmarks and add the new one you just downloaded: rm -f /opt/scc/Resources/Content/SCAP12_Content/*xml
  • Copy the benchmark to the right location cp /var/tmp/U_RHEL_8_V1R2_STIG_SCAP_1-2_Benchmark.xml /opt/scc/Resources/Content/SCAP12_Content/
  • Or run wget https://dl.dod.cyber.mil/wp-content/uploads/stigs/zip/U_RHEL_8_V1R2_STIG_SCAP_1-2_Benchmark.zip
  • Enter the scc program with /opt/scc/cscc --config which brings you to a text-based menu, pick option 1, pick the correct new Benchmark you put in above. Clear out the others if they exist first. Take your time, read the options please. Use the appropriate options to save the new Benchmark and exit the program, and you have the option to run it if you wish. I recommend using this method below:
  • The program will annoying place the files in a not-helpful place as the user you logged in as before you became root. If you have no_root_squash set, then this will fail. I recommend making a directory to place results and using that: mkdir /opt/scc/Resources/Results - see next step.
  • Running cscc program (part of scc software above) Make the directory above, or this will fail: /opt/scc/cscc -u /opt/scc/Resources/Results/ and hit enter. This will take longer than your patience level, get a cup of coffee or something.
  • The results will land in that directory, and you can harvest the results such as a file named "/opt/scc/Resources/Results/Sessions/date-time-goes-here/Results/SCAP/blah_blah_Non-Compliance_blah_blah.html"
  • Copy that file found above and view it on a computer with a respectable web browser to see the results.
  • If you have a ton of audit issues, 1) make sure auditd is running, start it, and run the scan again ask me how I know. If the service fails, use traditional methods to resolve the service. Make sure you loaded the audit.rules.master.v3 file in the expected location too.

NOTE on usbguard issue, apparently, this is needed and not ran after build: usbguard generate-policy > /etc/usbguard/rules.conf and causes issues as seen here. BUGZILLA REPORT FILED TO REDHAT AS OF 9/7/2021 (not visible to public)

  • In principle, Bugzillas are reported by those who experience the issue, or through a ticket When finding an rpm issue for a Red-Hat-provided RPM, please submit a bugzilla or a ticket directly with Red Hat for any Red-Hat provided rpms that do not behave properly.
  • If you experience NICs not coming up at build, ensure in your kickstart you have "--onboot=on" such as my kickstart in the attached file contains.
  • The material between the beginning "%post" area to the "%end" could be used after-build. I'd test it first, and I'll probably test this at another time. If someone attempts testing that afterwards, I recommend removing the "%post" and "%end`" from the after-build-script and make sure it's removed from the kickstart.

I'm sure I'll be editing this later for hopeful sanity. I hope this material helps. I'll be happy to discuss this keeping the exceptions mentioned above in mind. I plan on making a different edition of this that does not use the provided security profile, but instead does all the mitigations at build. This will take some time, and I'll provide it later, and link to it in this discussion. I'm not a fan of something like a security profile when I can do all mitigations myself. I believe it would not take very long to do so, but it will be a later time.




Yes, I marked my response as a best response, I really want those using this to see this reminder.

The files are attached above under "Attachments". Please rename them appropriately. Generally the comments that are within a script or kickstart go unread. I very kindly ask... - if your test-use goes south, please keep in mind that I put the comments there for a reason.

The kickstart is riddled with comments, especially changing the network line, and passwords. I included a decent SHA-512 hash script I found and beat into a script from yet another Red Hat solution, that bash script is above.

I'm sure something here needs to be edited, or will need to be edited, to quote the Mandalorian, "This is the way" (namely, the need for ongoing edits), so please leave a constructive comment and we can address this.


There are two things in this post:

  • RHEL 8 script to create shadow-compliant SHA-512 hashes needed to make the kickstart your own with passwords you know.
  • The kickstart file from files above. The %post area contains the additional mitigations to bring this to 99.6% compliance along with the audit.rules file in the files above.
The script:

This is a script to make shadow-compliant SHA-512 hashes. The script works on RHEL 8. This is useful when you need to make a password hash. You'll need this if you adopt the kickstart; there's a few places where passwords need to be made, they should be your passwords.

  • This RH solution was my inspiration.
  • The script checks if it is being ran on RHEL 8, has ansible and offers options otherwise.
  • The script provides three examples, the raw SHA-512 hash, an example to use with chpasswd and lastly something to use in a kickstart.
# This was created with material from the Red Hat solution
# at URL https://access.redhat.com/solutions/221403
# if you are using RHEL 8, you need ansible to run this

# this is for rhel8, if it isn't this gets printed and exits
echo -e "\n\t This is for RHEL 8 per Red Hat solution https://access.redhat.com/solutions/221403"
} # end forrhel8 function

rpm -q redhat-release | grep -q redhat-release-8 && echo -e "\n\tRHEL 8 detected proceeding.\n" || forrhel8

# this runs if ansible is not installed
needansible() {
echo -e "\n\tThis script requires ansible to run. \n\tThese are the commands to enable ansible:\n"
echo "subscription-manager repos --enable ansible-2.9-for-rhel-8-x86_64-rpms"
echo -e "yum install ansible -y\n"
} # end needansible function

# this runs if ansible is installed
runit() {
echo -e "\nThis script creates a SHA-512 shadow-compatible hash.\n\tsee URL https://access.redhat.com/solutions/221403"

echo -e "\n\tPlease carefully enter the password you wish to use ONCE. \n\tThis ansible method will not ask for a second verification."
echo -e "\n\tNOTE: This takes a moment to process\n\tTHERE IS A DELAY AFTER YOU HIT ENTER!!"
read -p "Enter Password: " -s pw
password=$(ansible -m debug -a msg="{{ '$pw'  | password_hash('sha512') }}" localhost | awk '/msg/ {print $NF}' | sed 's/^"//' | sed 's/"$//')
echo -e "\n\n\tExample 1: This is your raw SHA-512 shadow-compliant password hash: \n$password"
string="echo 'elvis:$password' | /usr/sbin/chpasswd -e && logger 'Successfully changed password for account elvis'"
string2="rootpw --iscrypted $password"
echo -e "\n\tExample 2: Using chpasswd to change a password.\n$string"
echo -e "\n\tExample 3: For use in a kickstart.\n$string2"
echo -e "\n\tThere are three use examples above. The raw hash, an example to change a password with 'chpasswd' and an example for a kickstart.\n"
echo -e "See this for more details: URL https://access.redhat.com/solutions/221403"
} # end runit function

# this only runs if ansible installed, else it prints what is needed
rpm -q ansible > /dev/null && runit || needansible

  • The password-hash script is above for RHEL8.
  • This is the kickstart file, will be edited original post above.
Please see the postscript.bash_.txt file at the top.  I ran all the commands in that file AFTER a build described above, and got the 99.6% compliance.  This is under review and will be updated.

The kickstart will be edited, and the items in the %post area will be reviewed for what can be done at build, and what will be done after-build.  It is discovered that many edits in the %post area are clobbered by the remaining RHEL 8 install.  
  • The first block of text above is a script for RHEL8 to create a shadow-compliant SHA-512 hash for the kickstart password entries.
  • The second very large block of text above is the kickstart file. As mentioned previously, please make necessary edits to make this work for your environment.


nice job

Thanks Jan!

Bugzilla filed for the usbguard RPM (as reported by the customer, in the other discussion) and also this below...

kernel.yama.ptrace_scope /lib/sysctl.d/10-default-yama-scope.conf per xccdf_mil.disa.stig_rule_SV-230546r627750_rule RHEL-08-040282

After build and scan with DISA SCAP software shows invalid content for the file /lib/sysctl.d/10-default-yama-scope.conf which at build (with the security profile) contains "kernel.yama.ptrace_scope = 0" when it should be "kernel.yama.ptrace_scope = 1".  This was determined with the most current benchmark found at https://dl.dod.cyber.mil/wp-content/uploads/stigs/zip/U_RHEL_8_V1R2_STIG_SCAP_1-2_Benchmark.zip (the xml file used with the program that follows) https://dl.dod.cyber.mil/wp-content/uploads/stigs/zip/scc-5.4.1_rhel8_oracle-linux8_x86_64_bundle.zip

I am very interested in this project. I am working on this as well, mostly using the Red Hat Official STIG role for ansible, and a supplemental ansible script.

I can get my hosts down to four open items, with one false positive (the suid/sgid issue). The fourth item is the grub boot password. I am still working on getting a unique encrypted string for each host. I tried to run grub2-set-password on each host using ansible, but that requires the expect package to be installed on each remote host.

I have reported the SUID/SGID issue to DISA, and expect it to be fixed in the next release. The benchmark also expects uppercase for ATM/CAN/SCTP/TIPC blacklisting, when it should be lowercase. I expect this to be fixed in the next release as well.

Not being entirely pleased with the idea of installing ansible just to create a SHA512 password, I discovered the following solution using openssl 1.1.1g on RHEL 8.4:

$ plaintext='password'
$ password=$(openssl passwd -6 $plaintext)
$ echo $password

plaintext='password' password=$(openssl passwd -6 $plaintext)

Hi David,

I am going to be posting another edition of this with a total set of scripts for every STIG items, with minor exceptions:

  • Files such as /etc/pam.d/password-auth (symbolic link to /etc/authselect/password-auth) and such files where I just copy the finished file afterwards (and make a backup of the original). The system-auth and password-auth files will be re-written at the end of the kickstart, so it's best to copy them after build, after the first reboot.
  • There's some other files that are too edit-intensive that I also will be just copying over after installation.
  • Thanks for your input with openssl password creation - I'm not pleased with using an ansible method and would rather avoid that. I'll probably turn your contribution (and credit you) into something that reads input and creates the SHA-512. I shall test/eval that and include it in what I provide.
  • for the suid etc for /boot - that can be accomplished at kickstart build time with the partitions. When i kickstart systems, I use an %include with a web URL for the partition file so I don't have to clutter my kickstart with potentially dynamic partition file. My partition file has all the necessary directives. The one that I could not have in my partition file at kickstart was for tmpfs with /dev/shm - so I made a script for it.
  • I'll include all my scripts. The second round I did for this has scripts for everything and the build is NOT from the security profile anaconda build because I don't care to use the security profile, and I can STIG a system just fine without it. **This will be in a different discussion, soon, along with all scripts to achieve compliance.
  • My scripts are made such that they only put in the proper directives once in the file and only once if someone for some odd reason ran it more than once, and my scripts log pass/fail at the end to /root/runcce.log (in each script).
  • If the file/config is already good, it states "ok" and does not hit the configuration file.

Again, I'll be making a different discussion and include all the scripts necessary to STIG a system (or files) to be used without the security profile. I'll list the prerequisites, such as proper partitions and so forth.


Example fix for /etc/fstab for xccdf_mil.disa.stig_rule_SV-230510r627750_rule / RHEL-08-040022 tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec 0 0

mydate=$(date '+%Y%m%d%H%M%S')
huntvalue='tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec 0 0'
## this function should only activate if needed, else bail
execute_fx() {  # begin execute
        cp -v ${huntfile}{,.$mydate}
        b4=$(grep ^tmpfs $huntfile | grep '/dev/shm')
        egrep "^tmpfs" $huntfile | grep '/dev/shm' | grep nosuid || echo "$huntvalue" >> $huntfile
        after=$(grep ^tmpfs $huntfile | grep '/dev/shm' | grep nosuid)
        echo -e "\$b4($b4) \$after($after) $huntfile"
        echo -e "\$b4($b4) \$after($after) $huntfile" >>$log
### ## sane check goes here
} # end execute_fx

pass() {
echo -e "$ruleid $version pass" >> $log
} # end pass fx

fail() {
echo -e "$ruleid $version failed" >> $log
} # end fail fx

### check for value, run if absent, bail if ok
grep "^tmpfs" "$huntfile" | grep '/dev/shm' | grep nosuid && echo ok || execute_fx
grep "^tmpfs" "$huntfile" | grep '/dev/shm' | grep nosuid && pass || fail

I plan on mitigating the /boot options (separate topic from above) with either a kickstart with proper fsoptions cited in the kickstart. A script could be created, it would have to be verified, but the above is along those lines.



I'm glad to hear they were response to your inputs. I have a number of things I could contribute for RHEL 7 for numerous false-positives and other annoyances.

I'll be making that other post with the scripts etc soon (not today though).


One of the issues that I have noticed with the STIG benchmarks, is that they don't cover all of the items in the STIG. Presently, there are 248 benchmark items for RHEL 8. There are still another 131 items that must be validated manually. Some of these could easily be included in the benchmark, but have not yet been added.

David, this is good to know

I'll check that out


Thanks for the Write up. I'm balancing this with the Mindpoint Ansible-Lockdown code which is very good as well.

I see only 6 attachments and no kickstart.cfg. Can you post that as well?

Red Hat has an official ansible RHEL7 and RHEL8 role available through galaxy. The roles bring a RHEL8 to about 60-ish percent compliance. I wrote a supplemental ansible playbook which brings my RHEL8 minimal install to four open items.

I address some issues that I expect to be fixed in the next STIG benchmark release. The blacklist for atm, can, sctp, and tipc expect the terms to be uppercase, when it should be lowercase. I add both to modprobe.d/.

The only things open are the grub2 password, and min/max password age for interactive accounts, and the 0755 permissions for files (it should only be looking for group/world write.)

I shall certainly include the kickstart soon, I had to rebuild my virtual lab from a backup, it's back in operation.

I contributed to the Mindpoint code (with RHEL 7) a long while ago.

I plan on putting all the scripts I made for RHEL 8 for those who want to not use a security-profile during an anaconda build and still want a stig (we do things the "hard way", (joking a bit) mostly because there are a few (not many) things we don't include due to operational needs).


xccdf_mil.disa.stig_rule_SV-230257r627750_rule RHEL-08-010300

DISA has resolved this issue in the latest benchmark. Now it correctly looks for group- and world-writable files.

RJ - That password-auth warning about being overwritten by authselect, when does that overwrite happen?

Is it only at system build? At boot time? randomly throughout the day (similar to Windows group policy)?

RJ- Very interested in looking at your kickstart file. So far, have pretty much everything STIGing based on your other files. Can you drop the kickstart on here soon for reference? Thanks.

I was looking through your bash script.
For the latest rhel8 benchmark, the term ATM, CAN, SCTP, and TIPC must be lowercase or the rule will fail.

Billy, David, thanks much. I shall review & make necessary edits.

I'll work on the kickstart as well

  • However, the kickstart will be in a separate discussion because this one uses the anaconda security-profile method. My kickstart won't, yet will have compliance (there are some things that may be needed to omit based on some company's functional requirements, this varies from one environment to another).
  • My other edition of STIG hardening will include the scripts I wrote to perform necessary actions. My scripts will only perform an edit if it is not there. If it the configuration already exists, it will not take action (and will not make a double entry).
  • Some files such as /etc/ssh/sshd_config when not using the anaconda security-profile , and also files under /etc/pam.d (symbolic links leading to authconfig), I've just made the edits and overwrite the files with my mitigated editions. There's other such files such as the /etc/audit/audit.rules and /etc/audit/rules.d/audit.rules file.


You may need to adjust the system-auth and password-auth files for RHEL (8.0 and 8.1) and RHEL 8.2 and later. Of course, we should always be using the latest release of RHEL 8. :-)

Some of the DISA STIG items are not applicable for RHEL 8.2 and later. Typically, the options have moved from pam.d to faillock.conf.

rhel8.0 and rhel8.1: RHEL-08-020010 RHEL-08-020012 RHEL-08-020014 RHEL-08-020016 RHEL-08-020018 RHEL-08-020020 RHEL-08-020022 RHEL-08-020028

rhel8.2 and later: RHEL-08-020011 RHEL-08-020013 RHEL-08-020015 RHEL-08-020017 RHEL-08-020019 RHEL-08-020021 RHEL-08-020023 RHEL-08-020025 RHEL-08-020026 RHEL-08-020027