Skip to content

Commit c8725d7

Browse files
committed
feat: implement Rocky Linux 9 CIS
1 parent 721b9d9 commit c8725d7

309 files changed

Lines changed: 6238 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

stig/README.rst

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
Secure Technical Implementation Guide - Audit and Remediations
2+
===============================================================
3+
4+
Overview
5+
--------
6+
7+
Round about 300 unofficial audit and remediation tasks for different Secure Technical Implementation Guides (STIG).
8+
9+
Compiled STIGs:
10+
11+
.. csv-table::
12+
:header-rows: 1
13+
14+
Type, Name, Version, ``stig_profile_name:``, ``stig_profile_version:``, Tested Platforms
15+
CIS, Rocky Linux 9 Benchmark, v2.0.0, ``CIS Rocky Linux 9``, ``v2.0.0``, Rocky Linux 9
16+
17+
`Drop us a line <https://www.linuxfabrik.ch/ueber-uns/kontakt>`_ if you have successfully used any of the STIG profiles on other platforms.
18+
19+
To audit before and after applying the remediations, you might use tools like `OpenVAS <https://www.openvas.org/>`_, `Lynis <https://cisofy.com/lynis/>`_, `Nessus <https://www.tenable.com>`_ or our Python script `files/audit.py <https://git.linuxfabrik.ch/linuxfabrik-ansible/roles/stig/-/blob/master/files/audit.py>`_. Remediations are done using the `tasks/main.yml <https://git.linuxfabrik.ch/linuxfabrik-ansible/roles/stig/-/blob/master/tasks/main.yml>`_.
20+
21+
.. attention::
22+
23+
Do not attempt to use any of the Ansible tasks without first testing them in a non-operational environment. Linuxfabrik assume no responsibility whatsoever for its use by other parties, and makes no guarantees, expressed or implied, about its quality, reliability, or any other characteristic.
24+
25+
.. note::
26+
27+
* This role cannot be run with the ``--check`` parameter.
28+
* Password-less SSH access is required for the audits and remediations.
29+
* The Rocky Linux 9 profile is intended for Rocky Linux 9 systems.
30+
31+
32+
Before you begin
33+
----------------
34+
35+
While remediating, this role breaks things on productive machines when applied completely.
36+
This role **will make changes to the system that could or will break things**. Please take the time to familarise yourself with the STIG profile of your choice before applying this role to a system.
37+
38+
Compile a list of non-applicable remediations for each server.
39+
For example: If you are running an outbound proxy with Squid and would like to apply the "CIS CentOS Linux 7 v3.1.2" profile, you should exclude "2.2.12 Ensure HTTP Proxy Server is not installed".
40+
41+
This role does not create or change host firewalls.
42+
Because there are far more firewall tools on earth than just firewalld, nftables and iptables, and maybe you create your firewall rules using other techniques or roles. This topic is too complex to be configured automatically.
43+
44+
45+
Installation
46+
------------
47+
48+
Place this Ansible role in an appropriate directory:
49+
50+
.. code-block:: text
51+
52+
stig
53+
├── defaults
54+
├── files: Home of the audit.py Python script and of stig.db (SQLite database file)
55+
│ ├── audits: Contains all Audit Snippets (Bash)
56+
│ └── lib: Home of Linuxfabrik libraries
57+
├── handlers
58+
├── tasks: Contains a collection of remediation tasks used across various STIGs, for example CIS CentOS Linux 8.
59+
└── templates: Jinja templates for Ansible
60+
61+
If you want to use ``audit.py``:
62+
63+
* Install Python modules:
64+
65+
.. code-block::
66+
67+
dnf -y install python3-termcolor
68+
69+
* Copy all Python files from https://git.linuxfabrik.ch/linuxfabrik/lib into ``stig/files/lib``.
70+
71+
72+
Auditing a Machine (audit.py)
73+
-----------------------------
74+
75+
If using our Python script `files/audit.py <https://git.linuxfabrik.ch/linuxfabrik-ansible/roles/stig/-/blob/master/files/audit.py>`_, ensure that you are able to access the machine using SSH with root privileges and password-less authentication. The script checks SSH connectivity and password-less ``sudo`` before running audits.
76+
77+
For example, start an audit only with controls whose name starts with "1", but at the same time exclude all controls whose name starts with "1.3" and "1.4":
78+
79+
.. code-block:: bash
80+
81+
cd files
82+
./audit.py --profile-name="CIS Rocky Linux 9" --profile-version="v2.0.0" --hostname=192.0.2.249 --username=root --lengthy --control-name-include='^1' --control-name-exclude='^1\.3|^1\.4'
83+
84+
Example output (parts ommitted)::
85+
86+
Audit Result
87+
============
88+
89+
...
90+
91+
Summary Table
92+
-------------
93+
94+
Control ! Script ! Scoring ! Lvl ! Result
95+
------------------------------------------------------------------------+-------------------+---------+-----+-------
96+
1.1.1.1 Ensure mounting of cramfs filesystems is disabled (Automated) ! cramfs_off.sh ! Scored ! 1 ! Failed
97+
1.1.1.2 Ensure mounting of squashfs filesystems is disabled (Automated) ! squashfs_off.sh ! Scored ! 2 ! Failed
98+
1.1.1.3 Ensure mounting of udf filesystems is disabled (Automated) ! udf_off.sh ! Scored ! 1 ! Failed
99+
1.1.2 Ensure /tmp is configured (Automated) ! tmp_separate_partition.sh ! Scored ! 1 ! Passed
100+
1.1.3 Ensure noexec option set on /tmp partition (Automated) ! tmp_noexec.sh ! Scored ! 1 ! Passed
101+
1.1.4 Ensure nodev option set on /tmp partition (Automated) ! tmp_nodev.sh ! Scored ! 1 ! Passed
102+
1.1.5 Ensure nosuid option set on /tmp partition (Automated) ! tmp_nosuid.sh ! Scored ! 1 ! Passed
103+
...
104+
105+
Profile
106+
-------
107+
108+
* Benchmark: CIS Rocky Linux 9 (v2.0.0)
109+
* Host: ``192.0.2.194``
110+
* Datetime: 2021-09-28 14:22:45
111+
* Score: 128/236 points (54.2%)
112+
* Grade: F
113+
114+
For each control:
115+
116+
* If you get "Passed", the configuration is CIS-compliant for that control.
117+
* If you get "Failed", the CIS requirements are not met.
118+
* If you get "Skipped", the control is not applicable on that system.
119+
* If you get "TODO", no audit script is implemented for that control yet.
120+
* If you get "Review", we cannot detect compliance automatically; check the configuration manually.
121+
122+
The overall grade is calculated as follows:
123+
124+
.. code-block:: python
125+
126+
def get_grade(percentage):
127+
if percentage >= 97:
128+
return 'A+'
129+
if percentage >= 93:
130+
return 'A'
131+
if percentage >= 90:
132+
return 'A-'
133+
if percentage >= 87:
134+
return 'B+'
135+
if percentage >= 83:
136+
return 'B'
137+
if percentage >= 80:
138+
return 'B-'
139+
if percentage >= 77:
140+
return 'C+'
141+
if percentage >= 73:
142+
return 'C'
143+
if percentage >= 70:
144+
return 'C-'
145+
if percentage >= 67:
146+
return 'D+'
147+
if percentage >= 63:
148+
return 'D'
149+
if percentage >= 60:
150+
return 'D-'
151+
return 'F'
152+
153+
154+
Remediating a Machine
155+
---------------------
156+
157+
We have implemented more audits than remediation measures, especially in the area of application servers (for example Apache). The reason: Audits are not only easier to implement, but the configuration of an existing application server is far too specialized and complex to be done by a small, general role. Better, specialized or custom Ansible roles must be used here to deploy and maintain the server.
158+
159+
After applying remediations:
160+
161+
* Reboot. Always reboot a remediated machine to be sure for all settings to take effect.
162+
* Keep an eye on your monitoring software.
163+
* Run a second audit.
164+
* Fix further findings using other roles.
165+
166+
Variables (have a look at `defaults/main.yml <https://git.linuxfabrik.ch/linuxfabrik-ansible/roles/stig/-/blob/master/defaults/main.yml>`_ for a complete list of available variables):
167+
168+
.. code-block:: yml
169+
170+
stig:
171+
- profile_name: 'CIS Apache HTTP Server 2.4' # mandatory
172+
profile_version: 'v2.0.0' # default: "latest"
173+
also_use_controls_disabled_by_default: True # default: false
174+
control_name_include: # use regular expressions here
175+
- '^1'
176+
- '^2'
177+
control_name_exclude: # use regular expressions here
178+
- '^2\.1'
179+
- '^2\.3'
180+
181+
182+
Ansible Role Variables
183+
----------------------
184+
185+
Have a look at `defaults/main.yml <https://git.linuxfabrik.ch/linuxfabrik-ansible/roles/stig/-/blob/master/defaults/main.yml>`_ for a complete list of available variables.
186+
187+
188+
STIG "CIS Apache HTTP Server 2.4" - Details
189+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190+
191+
To audit Apache, you must install and enable Apache ``mod_info`` beforehand and make it available at ``http://localhost/server-info``, for example like this:
192+
193+
.. code-block:: text
194+
195+
<VirtualHost 127.0.0.1:80>
196+
ServerName localhost
197+
ServerAlias 127.0.0.1
198+
<IfModule info_module>
199+
<Location "/server-info">
200+
SetHandler server-info
201+
Require local
202+
</Location>
203+
</IfModule>
204+
</VirtualHost>
205+
206+
This, of course, means that any control labeled "Ensure the Info Module Is Disabled" or something similar will return "Failed".
207+
208+
Ansible can only poorly take corrective action on existing Apache servers due to the complexity of the configuration and the different operating systems, which is why only the simplest remediations are implemented. It is better to deploy an Apache via Ansible that implements Security-by-Design from the beginning.
209+
210+
Some remediations are disabled by default for various reasons - enable them only if needed:
211+
212+
* | Ensure Apache Is Installed From the Appropriate Binaries (or similar)
213+
| Reason: Should be installed by a specialized Ansible Role, which implements Security-by-Design.
214+
215+
216+
STIG "CIS Rocky Linux 9 Benchmark" - Details
217+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218+
219+
Mandatory:
220+
221+
* You have to set the ``stig__grub2_password`` variable.
222+
223+
Some remediations are disabled by default for various reasons - enable them only if needed:
224+
225+
* | Audit system file permissions (or similar)
226+
| Reason: File permissions can be reset by the package manager or even a reboot at any time, which means that auditing tends to fail. For this reason, our audit task ignores some of the known files in ``var/log``.
227+
* | Ensure audit logs are not automatically deleted (or similar)
228+
| Reason: No customer likes to have his machine stopped simply because the audit partition runs out of space, and the mass of cryptic audit logs cannot be checked anyway.
229+
* | Ensure password expiration is 365 days or less (or similar)
230+
| Reason: May lock you and Ansible out.
231+
* | Ensure rsyslog is configured to send logs to a remote log host (or similar)
232+
| Reason: This is more complex in reality than the CIS mediation suggests.
233+
* | Ensure SSH root login is disabled (or similar)
234+
| Reason: May lock you and Ansible out.
235+
* | Ensure updates, patches, and additional security software are installed (or similar)
236+
| Reason: Skipping this saves quite some time during the run. Also, there are other possible update strategies.
237+
238+
239+
stig.db
240+
-------
241+
242+
This is a SQLite file and can be viewed and edited with *DB Browser for SQLite*, for example.
243+
244+
The ``control`` table contains a list of all audit scripts (mostly shell scripts) and the corresponding remediation tasks (mostly Ansible tasks).
245+
246+
The ``profile`` table contains STIG definitions (currently some CIS benchmarks). The meaning of some of the columns:
247+
248+
* ``exec_order``: Execution order within the specific STIG profile.
249+
* ``enabled``: Specifies whether a *remediation* should be applied automatically or not. Set to "0" if this causes problems or is unnecessary.
250+
251+
Use NULL to unset any value.
252+
253+
To get a complete list of disabled remediations, execute this SQL statement on ``stig.db``:
254+
255+
.. code-block:: text
256+
257+
SELECT *
258+
FROM profile
259+
WHERE
260+
enabled = 0
261+
262+
Some audits and remediations in some STIG profiles might not be implemented for various reasons. As an example, to get a list, execute this SQL statement on ``stig.db``:
263+
264+
.. code-block:: text
265+
266+
SELECT *
267+
FROM profile
268+
WHERE
269+
profile_name = "CIS Rocky Linux 9"
270+
and control_id ISNULL
271+
272+
273+
Naming Scheme for Controls
274+
--------------------------
275+
276+
From a remediation action point of view: ``<package or device>[-<section or detail>][-<section or detail>]-<action>``
277+
278+
* package or device: for example "httpd" or "tmp"
279+
* section: for example "vhosts"
280+
* action: a remediation action that should be done. One of
281+
282+
* get: fetch some information - for audit tasks that will never have a remediation counterpart
283+
* compare: compare two or more items - for audit tasks that will never have a remediation counterpart
284+
285+
* off: disabling or configuring something to "off"
286+
* on: enabling or configuring something to "on"
287+
* disable: disabling a service
288+
* enable: enabling a service
289+
290+
* install: install a package
291+
* update: update a package or packages
292+
* remove: uninstalling a package, deleting files and directories
293+
294+
* chmod: changing permissions using chmod
295+
* chown: changing owner using chown
296+
297+
* cron: configuring cronjobs
298+
* timer: configuring systemd timer
299+
* select: set something from a list of choices
300+
* configure: more or less complex configuration tasks
301+
* setup: both installation and configuration
302+
303+
304+
Examples
305+
--------
306+
307+
Auditing a Rocky Linux 9 VM, excluding some controls:
308+
309+
.. code-block:: bash
310+
311+
cd roles/stig/files/
312+
./audit.py --lengthy --profile-name='CIS Rocky Linux 9' --profile-version='v2.0.0' --hostname=192.0.2.194 --control-name-exclude='^1\.9|^3\.4\.|^4\.1\.2\.2|^4\.2\.1\.5|^5\.2\.10|^5\.3\.1|^5\.3\.2|^5\.3\.3|^5\.4\.2|^5\.5\.1\.1'
313+
314+
Apply the remedies of "CIS Rocky Linux 9" (use this as a starting point):
315+
316+
.. code-block:: text
317+
318+
# hosts.yml
319+
cis_hosts:
320+
vars:
321+
ansible_become: True
322+
hosts:
323+
192.0.2.194:
324+
325+
.. code-block:: text
326+
327+
# host_vars/192.0.2.194.yml
328+
stig__crypto_policy: 'FIPS'
329+
stig__grub2_password: 'BlueLake23'
330+
331+
.. code-block:: text
332+
333+
# group_vars/cis_hosts.yml
334+
stig:
335+
- profile_name: 'CIS Rocky Linux 9'
336+
profile_version: 'v2.0.0' # or "latest"
337+
also_use_controls_disabled_by_default: False
338+
control_name_include: # use regular expressions here
339+
- '^1'
340+
- '^2'
341+
- '^3'
342+
- '^4'
343+
- '^5'
344+
- '^6'
345+
control_name_exclude:
346+
- '^1\.9'
347+
348+
.. code-block:: text
349+
350+
# playbook.yml
351+
- hosts:
352+
- 'cis_hosts'
353+
roles:
354+
- role: 'stig'
355+
356+
.. code-block:: bash
357+
358+
ansible-playbook --inventory=path/to/hosts.yml path/to/playbook.yml --extra-vars="ansible_ssh_user=root"

0 commit comments

Comments
 (0)