diff --git a/defaults/main.yml b/defaults/main.yml index fbe81eb..7081649 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -583,10 +583,11 @@ rhel9cis_selinux_pol: targeted rhel9cis_selinux_enforce: enforcing ## Control 1.4.1 -# This variable will store the hashed GRUB bootloader password to be stored in '/boot/grub2/user.cfg' file. The default value -# must be changed to a value that may be generated with this command 'grub2-mkpasswd-pbkdf2' and must comply with -# this format: 'grub.pbkdf2.sha512...' -rhel9cis_bootloader_password_hash: 'grub.pbkdf2.sha512.changethispassword' # pragma: allowlist secret +# This variable will store the GRUB bootloader password to be stored in '/boot/grub2/user.cfg' file. The default value must be changed. +rhel9cis_bootloader_password: password # pragma: allowlist secret + +# Set this value to anything secure to have predictable hashes, which will prevent unnecessary changes +rhel9cis_bootloader_salt: '' ## Control 1.4.1 # This variable governs whether a bootloader password should be set in '/boot/grub2/user.cfg' file. diff --git a/filter_plugins/grub_hash.py b/filter_plugins/grub_hash.py new file mode 100644 index 0000000..245756b --- /dev/null +++ b/filter_plugins/grub_hash.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025, Jeffrey van Pelt +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import annotations + +DOCUMENTATION = r""" +name: grub_hash +short_description: Generate a GRUB2 password hash +version_added: 1.0.0 +author: Jeffrey van Pelt (@Thulium-Drake) +description: + - Generate a GRUB2 password hash from the input +options: + _input: + description: The desired password for the GRUB bootloader + type: string + required: true + salt: + description: The salt used to generate the hash + type: string + required: false + rounds: + description: The amount of rounds to run the PBKDF2 function + type: int + required: false +""" + +EXAMPLES = r""" +- name: 'Generate hash with defaults' + ansible.builtin.debug: + msg: "{{ 'mango123!' | grub_hash }}" + +- name: 'Generate hash with custom rounds and salt' + ansible.builtin.debug: + msg: "{{ 'mango123!' | grub_hash(rounds=10001, salt='andpepper') }}" + # Produces: grub.pbkdf2.sha512.10001.616E64706570706572.4C6AEA2A811B4059D4F47AEA36B77DB185B41E9F08ECC3C4C694427DB876C21B24E6CBA0319053E4F1431CDEE83076398C73B9AA8F50A7355E446229BC69A97C +""" + +RETURN = r""" +_value: + description: A GRUB2 password hash + type: string +""" + +from ansible.errors import AnsibleFilterError +import os +import base64 +from passlib.hash import grub_pbkdf2_sha512 + +def grub_hash(password, rounds=10000, salt=None): + if salt is None: + # Generate 64-byte salt if not provided + salt = os.urandom(64) + + # Check if the salt, when not generated, is a valid bytes value and attempt to convert if needed + if not isinstance(salt, bytes): + try: + salt = salt.encode("utf-8") + except AttributeError: + raise TypeError("Salt must be a string, not int.") + + # Configure hash generator + pbkdf2_generator = grub_pbkdf2_sha512.using(rounds=rounds, salt=salt) + return pbkdf2_generator.hash(password) + +class FilterModule(object): + def filters(self): + return { + 'grub_hash': grub_hash + } diff --git a/tasks/main.yml b/tasks/main.yml index 4d1887d..f98978d 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -43,14 +43,14 @@ fail_msg: "Crypto policy is not a permitted version" success_msg: "Crypto policy is a permitted version" -- name: "Check rhel9cis_bootloader_password_hash variable has been changed" +- name: "Check rhel9cis_bootloader_password variable has been changed" when: - rhel9cis_set_boot_pass - rhel9cis_rule_1_4_1 tags: always ansible.builtin.assert: - that: rhel9cis_bootloader_password_hash.find('grub.pbkdf2.sha512') != -1 and rhel9cis_bootloader_password_hash != 'grub.pbkdf2.sha512.changethispassword' # pragma: allowlist secret - msg: "This role will not be able to run single user password commands as rhel9cis_bootloader_password_hash variable has not been set correctly" + that: rhel9cis_bootloader_password != 'password' # pragma: allowlist secret + msg: "This role will not be able to run single user password commands as rhel9cis_bootloader_password variable has not been set correctly" - name: "Check crypto-policy module input" when: diff --git a/tasks/section_1/cis_1.4.x.yml b/tasks/section_1/cis_1.4.x.yml index 5969dff..57bd35a 100644 --- a/tasks/section_1/cis_1.4.x.yml +++ b/tasks/section_1/cis_1.4.x.yml @@ -13,7 +13,7 @@ - NIST800-53R5_AC-3 ansible.builtin.copy: dest: /boot/grub2/user.cfg - content: "GRUB2_PASSWORD={{ rhel9cis_bootloader_password_hash }}" # noqa template-instead-of-copy + content: "GRUB2_PASSWORD={{ rhel9cis_bootloader_password_hash | default(rhel9cis_bootloader_password | grub_hash(salt=rhel9cis_bootloader_salt)) }}" # noqa template-instead-of-copy owner: root group: root mode: 'go-rwx'