diff --git a/CMakeLists.txt b/CMakeLists.txt index 320247f1e3..76f70d015e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -337,6 +337,7 @@ cmake_dependent_option(ENABLE_OSCAP_UTIL_AS_RPM "enable the scap-as-rpm utility, cmake_dependent_option(ENABLE_OSCAP_UTIL_SSH "enables the oscap-ssh utility, this lets you scan remote machines over ssh" ON "NOT WIN32" OFF) cmake_dependent_option(ENABLE_OSCAP_UTIL_VM "enables the oscap-vm utility, this lets you scan VMs and VM storage images" ON "NOT WIN32" OFF) cmake_dependent_option(ENABLE_OSCAP_UTIL_PODMAN "enables the oscap-podman utility, this lets you scan Podman containers and container images" ON "NOT WIN32" OFF) +cmake_dependent_option(ENABLE_OSCAP_UTIL_BOOTC "enables the oscap-bootc utility, this lets you build hardened bootable container images" ON "NOT WIN32" OFF) cmake_dependent_option(ENABLE_OSCAP_UTIL_CHROOT "enables the oscap-chroot utility, this lets you scan entire chroots using offline scanning" ON "NOT WIN32" OFF) option(ENABLE_OSCAP_UTIL_AUTOTAILOR "enables the autotailor utility that is able to perform command-line tailoring" TRUE) option(ENABLE_OSCAP_REMEDIATE_SERVICE "enables the oscap-remediate service" FALSE) @@ -476,6 +477,7 @@ message(STATUS "scap-as-rpm: ${ENABLE_OSCAP_UTIL_AS_RPM}") message(STATUS "oscap-ssh: ${ENABLE_OSCAP_UTIL_SSH}") message(STATUS "oscap-vm: ${ENABLE_OSCAP_UTIL_VM}") message(STATUS "oscap-podman: ${ENABLE_OSCAP_UTIL_PODMAN}") +message(STATUS "oscap-bootc: ${ENABLE_OSCAP_UTIL_BOOTC}") message(STATUS "oscap-chroot: ${ENABLE_OSCAP_UTIL_CHROOT}") message(STATUS "autotailor: ${ENABLE_OSCAP_UTIL_AUTOTAILOR}") message(STATUS " ") diff --git a/docs/manual/manual.adoc b/docs/manual/manual.adoc index 5b96000858..9dd4e60563 100644 --- a/docs/manual/manual.adoc +++ b/docs/manual/manual.adoc @@ -2143,6 +2143,43 @@ registry.access.redhat.com/ubi8 latest 3269c37eae33 2 months ago 208 MB Note that the `oscap-podman` command requires root privileges. +=== Building hardened bootable container images using oscap-bootc + +The `oscap-bootc` tool is a convenience script that makes building hardened bootable container images easier. +This tool is designed to be used during the build of the bootable container image. + +Include `oscap-bootc` in your `Containerfile` that will be used to build your bootable container image. +The `Containerfile` first needs to install the `openscap-utils` package which ships the `oscap-bootc` tool. + +Also, SCAP content needs to be installed to the image before `oscap-bootc` will be run. +Although any SCAP content can be consumed by the tool, the SCAP source data streams shipped in `scap-security-guide` are specially cared to be compatible with bootable containers. + +Example `Containerfile`: + +---- +FROM quay.io/centos-bootc/centos-bootc:stream9 + +RUN dnf install -y openscap-utils scap-security-guide + +RUN oscap-bootc --profile stig /usr/share/xml/scap/ssg/content/ssg-cs9-ds.xml +---- + +Once you have your `Containerfile`, execute the image build: + +---- +podman build -t hardened_image . +---- + +The `oscap-bootc` tool installs and removes all packages required by the selected profile to or from the image. +Then, it runs a scan and remediation with the selected profile. +It doesn't use offline scanning. +The configuration files and other content in the image are modified by this process, depending on the used SCAP content. + +The built bootable container image can be then deployed and booted. +After booting the image, the state of the resulting system will be in line with the selected security profile. + +The `oscap-bootc` tool can't be used anywhere else than in a `Containerfile`. + === Scanning of Docker containers and images using oscap-docker The `oscap-docker` is used to scan Docker containers and images. It can diff --git a/openscap.spec b/openscap.spec index fbc844192f..4cd0d87a48 100644 --- a/openscap.spec +++ b/openscap.spec @@ -92,6 +92,7 @@ Summary: OpenSCAP Utilities Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release} Requires: rpmdevtools rpm-build Requires: %{name}-scanner%{?_isa} = %{epoch}:%{version}-%{release} +Requires: %{name}-engine-sce%{?_isa} = %{epoch}:%{version}-%{release} %description utils The %{name}-utils package contains command-line tools build on top diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 9347c29767..7b9274434e 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -139,6 +139,14 @@ if(ENABLE_OSCAP_UTIL_PODMAN) DESTINATION "${CMAKE_INSTALL_MANDIR}/man8" ) endif() +if(ENABLE_OSCAP_UTIL_BOOTC) + install(PROGRAMS "oscap-bootc" + DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + install(FILES "oscap-bootc.8" + DESTINATION "${CMAKE_INSTALL_MANDIR}/man8" + ) +endif() if(ENABLE_OSCAP_UTIL_AS_RPM) install(PROGRAMS "scap-as-rpm" DESTINATION ${CMAKE_INSTALL_BINDIR} diff --git a/utils/oscap-bootc b/utils/oscap-bootc new file mode 100755 index 0000000000..83ef333419 --- /dev/null +++ b/utils/oscap-bootc @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Red Hat Inc., Durham, North Carolina. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import argparse +import subprocess +import sys +import tempfile + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Use in your Containerfile to build hardened bootable " + "container images. Performs OpenSCAP scan and remediation of the " + "image.") + parser.add_argument( + "--profile", + help="ID of the profile to be evaluated") + parser.add_argument( + "--tailoring-file", + help="Use given XCCDF Tailoring file") + parser.add_argument( + "--tailoring-id", metavar="COMPONENT_ID", + help="Use given DS component as XCCDF Tailoring file") + parser.add_argument( + "--results-arf", + help="Write ARF (result data stream) into file") + parser.add_argument( + "--report", + help="Write HTML report into file") + parser.add_argument( + "data_stream", metavar="DATA_STREAM", + help="Path to a SCAP source data stream, eg. " + "/usr/share/xml/scap/ssg/content/ssg-rhel10-ds.xml") + # Unfortunately, we can't add "--rule", "--skip-rule", or "--reference" + # because the "oscap xccdf generate fix" submodule doesn't support these + # options. + return parser.parse_args() + + +def ensure_sce_installed(): + query_cmd = ["rpm", "-q", "openscap-engine-sce"] + query_process = subprocess.run(query_cmd, capture_output=True) + if query_process.returncode != 0: + raise RuntimeError( + "The script requires to have the openscap-engine-sce package " + "installed.") + + +def add_args(option_args_list, cmd): + for o, a in option_args_list: + if a: + cmd.append(o) + cmd.append(a) + + +def add_common_args(args, cmd): + oal = [ + ("--profile", args.profile), + ("--tailoring-file", args.tailoring_file), + ("--tailoring-id", args.tailoring_id) + ] + add_args(oal, cmd) + + +def add_eval_args(args, cmd): + oal = [ + ("--results-arf", args.results_arf), + ("--report", args.report), + ] + add_args(oal, cmd) + + +def pre_scan_fix(args): + with tempfile.NamedTemporaryFile(delete=False) as remediation_script: + gen_fix_cmd = [ + "oscap", "xccdf", "generate", "fix", "--fix-type", "bootc", + "--output", remediation_script.name] + add_common_args(args, gen_fix_cmd) + gen_fix_cmd.append(args.data_stream) + subprocess.run(gen_fix_cmd, check=True) + subprocess.run(["bash", remediation_script.name], check=True) + + +def scan_and_remediate(args): + oscap_cmd = ["oscap", "xccdf", "eval", "--progress", "--remediate"] + add_common_args(args, oscap_cmd) + add_eval_args(args, oscap_cmd) + oscap_cmd.append(args.data_stream) + env = {"OSCAP_PREFERRED_ENGINE": "SCE", "OSCAP_BOOTC_BUILD": "YES"} + try: + subprocess.run(oscap_cmd, env=env, check=True) + except subprocess.CalledProcessError as e: + if e.returncode not in [0, 2]: + print(e, file=sys.stderr) + + +def main(): + args = parse_args() + ensure_sce_installed() + pre_scan_fix(args) + scan_and_remediate(args) + + +if __name__ == "__main__": + main() diff --git a/utils/oscap-bootc.8 b/utils/oscap-bootc.8 new file mode 100644 index 0000000000..9c911807b6 --- /dev/null +++ b/utils/oscap-bootc.8 @@ -0,0 +1,54 @@ +.TH oscap-bootc "8" "November 2024" "Red Hat, Inc." "System Administration Utilities" + +.SH NAME +oscap-bootc \- Tool for building hardened bootable container images + +.SH DESCRIPTION +The oscap-bootc tool is a convenience script that makes building hardened bootable container images easier. +This tool is designed to be used during the build of the bootable container image. +Include oscap-bootc in your Containerfile that will be used to build your bootable container image. +The oscap-bootc runs oscap tool on a given container image. + +The oscap-bootc tool can't be used anywhere else than in a Containerfile. + +.SH USAGE + +oscap-bootc [OPTION...] DATASTREAM_FILE + +Usage of the tool mimics usage and options of oscap(8) tool. + +.SH OPTIONS +.TP +\fB\-\-profile PROFILE_ID\fR +.RS +ID of the profile to be evaluated. +.RE +.TP +\fB\-\-tailoring-file TAILORING_FILE\fR +.RS +Use given file for XCCDF tailoring. Select profile from tailoring file to apply using --profile. If both --tailoring-file and --tailoring-id are specified, --tailoring-file takes priority. +.RE +.TP +\fB\-\-tailoring-id COMPONENT_REF_ID\fR +.RS +Use tailoring component in input source data stream for XCCDF tailoring. The tailoring component must be specified by its Ref-ID (value of component-ref/@id attribute in input source data stream). Select profile from tailoring component to apply using --profile. If both --tailoring-file and --tailoring-id are specified, --tailoring-file takes priority. +.RE +.TP +\fB\-\-results-arf FILE\fR +.RS +Writes results to a given FILE in Asset Reporting Format. +.RE +.TP +\fB\-\-report FILE\fR +.RS +Write HTML report into FILE. +.RE + +.SH REPORTING BUGS +.nf +Please report bugs using https://github.com/OpenSCAP/openscap/issues + +.SH AUTHORS +.nf +Jan Černý +.fi