-
Notifications
You must be signed in to change notification settings - Fork 379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce ability to generate kickstarts #2136
Conversation
This fix type will be used to generate RHEL kickstarts to support unattended installation of hardened RHEL systems.
If a like starts with packages, services or post, it will be added to the respective Kickstart section.
You can't scan the machine that you will install using the generated kickstart (to scan it it would already have to be installed). Therefore it doesn't make sense to generate kickstarts for results. For simplicity we will disable this feature.
This header will put some common options that are sensible for every RHEL kickstart. The purpose to make the installation easier and set sensible defaults. The code has been taken from ComplianceAsCode/content RHEL 9 CIS Kickstart.
We will run an oscap scan in the post phase, therefore we need to install openscap and scap-security-guide to be able to run the oscap scan.
Instead of hard-coded "xccdf-file.xml" we will show the real input SCAP file name in the kenerated remediations.
This will give us the correct file name for most situations.
I don't see it currently in the code, but note that an Anaconda kickstart can have multiple This would allow us to use further options to Similarly,
and I imagine we'd definitely want Also, what about the |
"# --device device to be activated and / or configured with the network command\n" | ||
"# --bootproto method to obtain networking configuration for device (default dhcp)\n" | ||
"# --noipv6 disable IPv6 on this device\n" | ||
"network --onboot yes --device eth0 --bootproto dhcp --noipv6\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just
network --onboot yes --bootproto dhcp
should be enough. The rest is autodetected by Anaconda.
"# Configure firewall settings for the system (optional)\n" | ||
"# --enabled reject incoming connections that are not in response to outbound requests\n" | ||
"# --ssh allow sshd service through the firewall\n" | ||
"firewall --enabled --ssh\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure we can remove this - our testing runs without the firewall
command as Anaconda by default installs firewalld
, and installing the openssh-server
package adds port 22 to it seamlessly.
Do we really want a very verbose kickstart file as an output, giving the user many options to customize it (url/cdrom/harddrive), explaining every option? Why not just point to https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html (or the RHEL version of it, ie. https://docs.redhat.com/en-us/documentation/red_hat_enterprise_linux/8/pdf/system_design_guide/Red_Hat_Enterprise_Linux-8-System_Design_Guide-en-US.pdf - APPENDIX J ) and let the user figure out what they need for their specific setup ? |
@comps great ideas! thanks a lot! |
char *basename = oscap_basename(dup); | ||
free(dup); | ||
char *oscap_command = oscap_sprintf( | ||
"oscap xccdf eval --remediate --profile '%s' /usr/share/xml/scap/ssg/content/%s\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will work sometimes, but sometimes it won't work. How do we ensure that the file is the same as the file that the user provided to oscap
when generating the kickstart? And even a bigger problem, what if the user used a tailoring when generating the kickstart?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is why we need to at least fix this: #771.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing! I didn't know that we have issue for that. Great news is that the issue is already "accidentally" fixed in this PR! The headers now contain actual file path of the file used as input to the oscap xccdf generate fix
command.
The knowledge of the actual input file path is also reused in this place. Here, I take its base name and concatenate it with the well-known scap-security-guide directory path. This way I achieved that it will work sometimes. The sometimes specifically means that 1. user uses a data stream from the scap-security-guide package to generate the KS and 2. the version of the scap-security-guide package used to generate the KS is the same that will be installed on the installed system and 3. user doesn't use tailoring when generating the KS. If any of the three conditions isn't true then it won't work or will give surprising results. I think that's insufficient therefore I opened this comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have this proposal how to solve this problem. We will document that the recommended workflow is to serve the SCAP source data stream and the optional XCCDF tailoring file on a web server. Then, the generated kickstart will contain a command to download these files from the server. We will not install scap-security-guide package during the installation. This way it will make sure that the same files are used for both kickstart generation before installation and remediation during installation. The generated kickstart can contain placeholders for the content URI and comments highlighting it. Also, we can have a CLI option that would get propagated to the generated kickstart. The key thing would be to have the workflow well documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another proposal has been suggested by @dahaic : The kickstart would explicitly request the specific version of scap-security-guide RPM package to be installed. The package would be fetch from CDN. This way we would ensure that the same data stream is used for the remediation as is used for the kickstart generation. The tailoring file could be inserted in a form of base64 blob or in a form of autotailor command.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- It'd be nice to actually have just a full path here for the content. We don't care much about non-packaged DSes. It's up to the advanced customer to figure out how they want to fetch, store and use it (we can give an example in the docs, though).
- If we can somehow embed tailoring (when
--tailoring
option is provided along withgenerate fix
) and generate proper KS that would use it without requiring the user to serve it separately — it would be very nice, but let's not concentrate on it before everything else is complete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we could be able to bring tailoring into the remediation generator context it will help us to also generate self-contained tailored Blueprints.
The generator will consume `logvol` commands and put them into the output kickstart files. This will be used in rules for partitions, for example in the `partition_for_var` rule.
"# Initialize (format) all disks (optional)\n" | ||
"zerombr\n" | ||
"\n" | ||
"# The following partition layout scheme assumes disk of size 20GB or larger\n" | ||
"# Modify size of partitions appropriately to reflect actual machine's hardware\n" | ||
"#\n" | ||
"# Remove Linux partitions from the system prior to creating new ones (optional)\n" | ||
"# --linux erase all Linux partitions\n" | ||
"# --initlabel initialize the disk label to the default based on the underlying architecture\n" | ||
"clearpart --linux --initlabel\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would replace this with
zerombr
clearpart --all --initlabel
reqpart
since zerombr
+ clearpart --linux
doesn't make sense, ... and since we definitely want reqpart
which adds EFI partition(s) on x86_64, and PReP boot partition on IBM POWER.
Note that reqpart
also has --add-boot
, which would nicely add /boot
for us, but then we couldn't specify --fsoptions
for it, so we can't really use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great idea ! thanks
So far, these large blobs have been only copy-pasted from the kickstarts that we have in upstream without any thinking. It's definitely something that we should investigate and change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default options for /boot
are OK, oscap will remediate them in post section.
- network device should be autodetected by Anaconda - firewalld is added seamlessly to the port 22 - combination zerombr + clearpart --linux doesn't make sense
We will have a dedicated post section for compliance hardening. This section will fail if oscap command fails. It helps us prevent partially or wrongly hardened systems.
The intention is to be able to perform the installation fully automatically without manual intervention during the installation process. We will add sensible default values to the kickstart so that Anaconda won't ask for setting these options.
We will add a fallback partition layout for profiles that don't specify partitioning layout, for example RHEL 9 PCI-DSS profile. We need to specify at least some layout in the kickstart to make the installation fully automated.
I have changed the %post section to fail if the oscap remediation fails. I have added default values that ensure fully automated installation. The default values include also partition defaults which will be added to the kickstart if the SCAP profile doesn't specify any partition requirement, which means automated installation for these profiles as well. |
You might want to read my post more carefully - I mentioned that Also, for profiles without partitions, maybe const char *fallback_partition = (
"# Create partition layout scheme\n"
"zerombr\n"
"clearpart --all --initlabel\n"
"autopart --type=lvm\n"
); |
If I got
@comps ? |
The important thing here is to distinguish between a kickstart that works and kickstart that enables a fully automated installation. Without the options I added today, the kickstart works (it worked even yesterday), but the installation isn't fully automated, because the user needs to configure the options in the Anaconda during installation. For example, if you remove the "lang" keyword from the kickstart, the Anaconda will ask you which language you want to use during the installation and you have to click and choose one to proceed. But if there are all the options I added, the installation doesn't require any user interaction in the whole process and goes fully automatically. |
To simplify the code, we can use the "autopart" command.
I have used the autopart |
Right, but that doesn't do $ bash -c 'ls /nonexistent'; echo $?
ls: cannot access '/nonexistent': No such file or directory
2
So my version should still work. Yours works too, but I don't think it would gain us anything.
Hmm, interesting, because for me, it works fully automatically even without them. I guess it doesn't ultimately matter, but you could replace the options with
to force automated install, but either way works. |
Okay, in that case your solution is fine. But then there's assumption that
will be the last 2 commands in |
A kickstart will typically have more I guess we can change it to [ $? -eq 0 -o $? -eq 2 ] || exit 1 for extra safety in case someone adds more code to our |
Options for bootloader sometimes aren't in the form 'option=value' and so they sometimes don't contain '='. This commit clarifies the documentation about the bootloader command with regards to this fact. Also, it adds a simple test for this command.
* Concatenate 2 strings * Convenience wrapper over strncat.
If a line in kickstart remediation starts with `%post`, that line and all following lines until a line starting with `%end` are considered a block. Blocks are propagated to the output without any processing.
9b6eb9a
to
fcf313a
Compare
If an user doesn't provide `--profile`, the default XCCDF profile is used which is the standard behavior of all oscap xccdf modules. However, the generated remediation doesn't reflect that. This commit fixes it, namely the generated "oscap" commands.
I have add exit 1, add ability to consume custom %pre and %post sections, add ability to disable kdump and solved the situation when --profile isn't provided. Then, I have improved the user manual changes. |
/packit build |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, there is nothing I would like to change immediately, although we might have some adjustments after getting some feedback from stakeholders (and more experiments with CI etc). I consider it good enough for the first implementation.
Thank you!
This PR introduces ability to generate kickstarts from SCAP content using:
The kickstart will be generated from kickstart snippets in XCCDF rules in the input SCAP content.
The kickstart snippets need to be stored in
<fix>
elements withsystem
attribute set tourn:xccdf:fix:script:kickstart
.For more details, please read commit messages of each commit.
Rationale:
We'd like to provide a lightweight system hardening for Anaconda, that is not dependent on UI and does not require user intervention. This should be pretty much similar to Image Builder's experience for users that can not use it for some reason.
How to test:
ks.cfg
:virt-manager
, click on Create a new virtual machine. ChooseNetwork Install
.http://DOWNLOAD_HOSTNAME/released/RHEL-9/9.4.0/BaseOS/x86_64/os/
Under the installation URL field, click on
URL options
and insert thereinst.ks=http://192.168.124.1:8000/ks.cfg
. Complete next steps in the wizard.Review hints:
Start by reading the proposed user manual text in the PR.