27 Building Updated SUSE Linux Micro Images with Kiwi #
This section explains how to generate updated SUSE Linux Micro images to be used with Edge Image Builder, with Cluster API (CAPI) + Metal3, or to write the disk image directly to a block device. This process is useful in situations where the latest patches are required to be included in the initial system boot images (to minimise patch transfer post-installation), or for scenarios where CAPI is used, where it’s preferred to reinstall the operating system with a new image rather than upgrading the hosts in place.
This process makes use of Kiwi to run the image build. SUSE Edge ships with a containerized version that simplifies the overall process with a helper utility baked in, allowing to specify the target profile required. The profile defines the type of output image that is required, with the common ones listed below:
"Base" - A SUSE Linux Micro disk image with a reduced package set (it includes podman).
"Base-SelfInstall" - A SelfInstall image based on the "Base" above.
"Base-RT" - Same as "Base" above but using a real-time (rt) kernel instead.
"Base-RT-SelfInstall" - A SelfInstall image based on the "Base-RT" above
"Default" - A SUSE Linux Micro disk image based on the "Base" above but with a few more tools, including the virtualization stack, Cockpit and salt-minion.
"Default-SelfInstall" - A SelfInstall image based on the "Default" above
See SUSE Linux Micro 6.2 documentation for more details.
This process works for both AMD64/Intel 64 and AArch64 architectures but it is necessary to use a build host with the same architecture of the images being built. In other words, to build an AArch64 image, it is required to use an AArch64 build host, and vice-versa for AMD64/Intel 64 - cross-builds are not supported at this time.
27.1 Prerequisites #
Kiwi image builder requires the following:
A SUSE Linux Micro 6.2 host ("build system") with the same architecture of the image being built.
The build system needs to be already registered via
SUSEConnect(the registration is used to pull the latest packages from the SUSE repositories)An internet connection that can be used to pull the required packages. If connected via proxy, the build host needs to be pre-configured.
SELinux needs to be disabled on the build host (as SELinux labelling takes place in the container and it can conflict with the host policy)
At least 10GB free disk space to accommodate the container image, the build root, and the resulting output image(s)
27.2 Getting Started #
Due to certain limitations, it is currently required to disable SELinux. Connect to the SUSE Linux Micro 6.2 image build host and ensure SELinux is disabled:
# setenforce 0Create an output directory to be shared with the Kiwi build container to save the resulting images:
# mkdir ~/outputPull the latest Kiwi builder image from the SUSE Registry:
# podman pull registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1
(...)27.3 Building the Default Image #
This is the default behavior of the Kiwi image container if no arguments are provided during the container image run. The following command runs podman with two directories mapped to the container:
The
/etc/zypp/repos.dSUSE Linux Micro package repository directory from the underlying host.The output
~/outputdirectory created above.
The Kiwi image container requires to run the build-image helper script as:
# podman run --privileged -v /etc/zypp/repos.d:/micro-sdk/repos/ -v ~/output:/tmp/output \
-it registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1 build-image
(...)It’s expected that if you’re running this script for the first time that it will fail shortly after starting with "ERROR: Early loop device test failed, please retry the container run.", this is a symptom of loop devices being created on the underlying host system that are not immediately visible inside of the container image. Simply re-run the command again and it should proceed without issue.
After a few minutes the images can be found in the local output directory:
(...)
INFO: Image build successful, generated images are available in the 'output' directory.
# ls -1 output/
SLE-Micro.x86_64-6.2.changes
SLE-Micro.x86_64-6.2.packages
SLE-Micro.x86_64-6.2.raw
SLE-Micro.x86_64-6.2.verified
build
kiwi.result
kiwi.result.json27.4 Building images with other profiles #
In order to build different image profiles, the "-p" command option in the Kiwi container image helper script is used. For example, to build the "Default-SelfInstall" ISO image:
# podman run --privileged -v /etc/zypp/repos.d:/micro-sdk/repos/ -v ~/output:/tmp/output \
-it registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1 build-image -p Default-SelfInstall
(...)To avoid data loss, Kiwi will refuse to run if there are images in the output directory. It is required to remove the contents of the output directory before proceeding with rm -f output/*.
Alternatively, to build a SelfInstall ISO image with the RealTime kernel ("kernel-rt"):
# podman run --privileged -v /etc/zypp/repos.d:/micro-sdk/repos/ -v ~/output:/tmp/output \
-it registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1 build-image -p Base-RT-SelfInstall
(...)27.5 Building images with large sector sizes #
Some hardware requires an image with a large sector size, i.e. 4096 bytes rather than the standard 512 bytes. The containerized Kiwi builder supports the ability to generate images with large block size by specifying the "-b" parameter. For example, to build a "Default-SelfInstall" image with a large sector size:
# podman run --privileged -v /etc/zypp/repos.d:/micro-sdk/repos/ -v ~/output:/tmp/output \
-it registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1 build-image -p Default-SelfInstall -b
(...)27.6 Using a custom Kiwi image definition file #
For advanced use-cases a custom Kiwi image definition file (SL-Micro.kiwi) can be used along with any necessary post-build scripts. This requires overriding the default definitions pre-packaged by the SUSE Edge team.
Create a new directory and map it into the container image where the helper script is looking (/micro-sdk/defs):
# mkdir ~/mydefs/
# cp /path/to/SL-Micro.kiwi ~/mydefs/
# cp /path/to/config.sh ~/mydefs/
# podman run --privileged -v /etc/zypp/repos.d:/micro-sdk/repos/ -v ~/output:/tmp/output -v ~/mydefs/:/micro-sdk/defs/ \
-it registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1 build-image
(...)This is only required for advanced use-cases and may cause supportability issues. Please contact your SUSE representative for further advice and guidance.
To get the default Kiwi image definition files included in the container, the following commands can be used:
$ podman create --name kiwi-builder registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1
$ podman cp kiwi-builder:/micro-sdk/defs/SL-Micro.kiwi .
$ podman cp kiwi-builder:/micro-sdk/defs/SL-Micro.kiwi.4096 .
$ podman rm kiwi-builder
$ ls ./SL-Micro.*
(...)27.7 Building an OpenSCAP hardened image #
You can build a security-hardened image using OpenSCAP and the SCAP Security Guide (SSG) directly during the Kiwi build process. This ensures that the generated SUSE Linux Micro system boots with security compliance already applied and remediated.
Standard compliance baselines can sometimes conflict with edge or Kubernetes requirements, such as disabling IPv4/IPv6 forwarding or running firewall services that interfere with container network interfaces (CNIs). To prevent disruption, you can optionally provide a tailoring file to unselect specific rules or customize configuration parameters.
To build an OpenSCAP-hardened image with optional tailoring:
Extract the default Kiwi definition files:
Create a working directory and copy the default definition files and scripts from the Kiwi builder container:
# mkdir ~/mydefs # podman create --name kiwi-builder registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1 # podman cp kiwi-builder:/micro-sdk/defs/. ~/mydefs/ # podman rm kiwi-builderAdd OpenSCAP packages to the Kiwi definition:
Edit
~/mydefs/SL-Micro.kiwi(or~/mydefs/SL-Micro.kiwi.4096if building for 4096-byte sector sizes) and add theopenscap-utils,scap-security-guide,which, andbiosdevnamepackages inside the<packages type="image">section:<package name="openscap-utils"/> <package name="scap-security-guide"/> <package name="which"/> <package name="biosdevname"/>openscap-utils: Provides theoscapcommand-line scanner and theautotailorprofile customization tool.scap-security-guide: Provides the security policy datastreams (including/usr/share/xml/scap/ssg/content/ssg-slmicro6-ds.xml).which: Required by remediation scripts when applying the profile.biosdevname: Required by network remediation rules when applying the profile.
Add OpenSCAP hardening logic to
config.sh:Append the following hardening routine to
~/mydefs/config.sh. Kiwi runsconfig.shinside the chrooted target system before creating the final image:#====================================== # Apply OpenSCAP Hardening with Tailoring #====================================== if [ -f /usr/share/xml/scap/ssg/content/ssg-slmicro6-ds.xml ]; then echo "** Preparing OpenSCAP Hardening..." DATASTREAM="/usr/share/xml/scap/ssg/content/ssg-slmicro6-ds.xml" BASE_PROFILE="xccdf_org.ssgproject.content_profile_general" PROFILE_ID="${BASE_PROFILE}" TAILORING_FLAGS="" TAILORING_ARG="" # Check if tailoring configurations exist (copied in from host's micro-sdk/defs/root/etc/) if [ -f /etc/scap-tailoring.txt ]; then echo "** Tailoring configuration found at /etc/scap-tailoring.txt" # Read the lines, ignore comments and empty lines TAILORING_FLAGS=$(grep -v '^#' /etc/scap-tailoring.txt | grep -v '^$' | tr '\n' ' ') if [ -n "${TAILORING_FLAGS}" ]; then echo "** Generating tailored profile using autotailor..." PROFILE_ID="xccdf_org.ssgproject.content_profile_general_tailored" # We temporarily disable exit-on-error for autotailor / xmllint set +e # Run autotailor to generate tailoring XML autotailor ${TAILORING_FLAGS} \ --output /tmp/ssg-slmicro6-tailored-ds.xml \ --new-profile-id "${PROFILE_ID}" \ "${DATASTREAM}" "${BASE_PROFILE}" # Format and check tailoring XML (workaround for older OpenSCAP versions) if [ -f /tmp/ssg-slmicro6-tailored-ds.xml ]; then xmllint --format /tmp/ssg-slmicro6-tailored-ds.xml > /tmp/ssg-slmicro6-tailored-ds-formatted.xml TAILORING_ARG="--tailoring-file /tmp/ssg-slmicro6-tailored-ds-formatted.xml" else echo "WARNING: autotailor failed to generate tailoring file. Falling back to base profile." PROFILE_ID="${BASE_PROFILE}" TAILORING_ARG="" fi set -e fi fi echo "** Applying OpenSCAP Hardening Profile: ${PROFILE_ID}..." set +e if [ -n "${TAILORING_ARG}" ]; then oscap xccdf eval --remediate \ --profile "${PROFILE_ID}" \ ${TAILORING_ARG} \ "${DATASTREAM}" else # Fallback to standard command skipping the dangerous authorized local users rule oscap xccdf eval --remediate \ --profile "${PROFILE_ID}" \ --skip-rule xccdf_org.ssgproject.content_rule_accounts_authorized_local_users \ "${DATASTREAM}" fi set -e echo "** OpenSCAP Hardening completed." # Clean up temporary tailoring files rm -f /tmp/ssg-slmicro6-tailored-ds.xml /tmp/ssg-slmicro6-tailored-ds-formatted.xml rm -f /etc/scap-tailoring.txt fiThis script checks for the presence of the SCAP Security Guide datastream:
If
/etc/scap-tailoring.txtis present,autotailorcreates a tailored profile XML (xccdf_org.ssgproject.content_profile_general_tailored), andoscapevaluates and remediates using that tailored profile.If no tailoring file is found,
oscapapplies the base profile (xccdf_org.ssgproject.content_profile_general) while skippingaccounts_authorized_local_usersto avoid locking out or deleting local accounts.Temporary tailoring XML artifacts and
/etc/scap-tailoring.txtare deleted at the end of the process.
(Optional) Provide a tailoring configuration:
Kiwi copies any files in a
root/subdirectory in the definitions directory into the root (/) of the image filesystem.Create the overlay directory:
# mkdir -p ~/mydefs/root/etcCreate
~/mydefs/root/etc/scap-tailoring.txtand specify any rules to unselect or variables to customize. For example:--unselect banner_etc_issue --unselect banner_etc_issue_net --unselect grub2_ipv6_disable_argument --unselect grub2_password --unselect kernel_module_sctp_disabled --unselect kernel_module_vfat_disabled --unselect package_dhcp_client_removed --unselect package_firewalld_installed --unselect package_rpcbind_removed --unselect service_firewalld_enabled --unselect sshd_enable_warning_banner --unselect sysctl_net_ipv4_ip_forward --unselect sysctl_net_ipv6_conf_all_forwarding --unselect xccdf_org.ssgproject.content_rule_accounts_authorized_local_users -v sysctl_net_ipv4_conf_all_forwarding_value=1 -v sysctl_net_ipv4_conf_all_rp_filter_value=2 -v sysctl_net_ipv4_conf_default_rp_filter_value=2 -v sysctl_net_ipv6_conf_all_accept_ra_value=2 -v sysctl_net_ipv6_conf_all_forwarding_value=1 -v sysctl_net_ipv6_conf_default_accept_ra_value=2--unselect: Deselects rules that may conflict with edge or Kubernetes cluster networking (such as keeping IP forwarding enabled, keeping DHCP, or avoiding firewall service conflicts).-v: Overrides default profile variables (such as enabling packet forwarding).NoteIf
~/mydefs/root/etc/scap-tailoring.txtis not provided, Kiwi builds the image using the base hardening profile without tailoring.
Build the hardened image:
Ensure the output directory is clean:
# rm -f ~/output/*Run the Kiwi builder container with the custom definition directory mapped to
/micro-sdk/defs/:# podman run --privileged -v /etc/zypp/repos.d:/micro-sdk/repos/ -v ~/output:/tmp/output -v ~/mydefs/:/micro-sdk/defs/ \ -it registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1 build-imageTo build a specific profile, append
-p <profile_name>(for example,-p Default-SelfInstallor-p Base):# podman run --privileged -v /etc/zypp/repos.d:/micro-sdk/repos/ -v ~/output:/tmp/output -v ~/mydefs/:/micro-sdk/defs/ \ -it registry.suse.com/edge/3.7/kiwi-builder:10.2.29.1 build-image -p Default-SelfInstall