This is a draft document that was built and uploaded automatically. It may document beta software and be incomplete or even incorrect. Use this document at your own risk.

Jump to contentJump to page navigation: previous page [access key p]/next page [access key n]
SUSE Edge Documentation|How-To Guides|Building Updated SUSE Linux Micro Images with Kiwi
Applies to SUSE Edge 3.7

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.

Note
Note

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 0

Create an output directory to be shared with the Kiwi build container to save the resulting images:

# mkdir ~/output

Pull 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.d SUSE Linux Micro package repository directory from the underlying host.

  • The output ~/output directory 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
(...)
Note
Note

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.json

27.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
(...)
Note
Note

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
(...)
Warning
Warning

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:

  1. 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-builder
  2. Add OpenSCAP packages to the Kiwi definition:

    Edit ~/mydefs/SL-Micro.kiwi (or ~/mydefs/SL-Micro.kiwi.4096 if building for 4096-byte sector sizes) and add the openscap-utils, scap-security-guide, which, and biosdevname packages inside the <packages type="image"> section:

    <package name="openscap-utils"/>
    <package name="scap-security-guide"/>
    <package name="which"/>
    <package name="biosdevname"/>
    • openscap-utils: Provides the oscap command-line scanner and the autotailor profile 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.

  3. Add OpenSCAP hardening logic to config.sh:

    Append the following hardening routine to ~/mydefs/config.sh. Kiwi runs config.sh inside 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
    fi

    This script checks for the presence of the SCAP Security Guide datastream:

    • If /etc/scap-tailoring.txt is present, autotailor creates a tailored profile XML (xccdf_org.ssgproject.content_profile_general_tailored), and oscap evaluates and remediates using that tailored profile.

    • If no tailoring file is found, oscap applies the base profile (xccdf_org.ssgproject.content_profile_general) while skipping accounts_authorized_local_users to avoid locking out or deleting local accounts.

    • Temporary tailoring XML artifacts and /etc/scap-tailoring.txt are deleted at the end of the process.

  4. (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/etc

    Create ~/mydefs/root/etc/scap-tailoring.txt and 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).

      Note
      Note

      If ~/mydefs/root/etc/scap-tailoring.txt is not provided, Kiwi builds the image using the base hardening profile without tailoring.

  5. 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-image

    To build a specific profile, append -p <profile_name> (for example, -p Default-SelfInstall or -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