Chapter 24. Creating whole-disk images

The main overcloud image is a flat partition image that contains no partitioning information or bootloader. Director uses a separate kernel and ramdisk when it boots nodes and creates a basic partitioning layout when it writes the overcloud image to disk. However, you can create a whole- disk image, which includes a partitioning layout, bootloader, and hardened security.

Important

The following process uses the director image building feature. Red Hat only supports images that use the guidelines contained in this section. Custom images built outside of these specifications are not supported.

24.1. Security hardening measures

The whole disk image includes extra security hardening measures necessary for Red Hat OpenStack Platform deployments where security is an important feature.

Security recommendations for image creation

  • The /tmp directory is mounted on a separate volume or partition and has the rw, nosuid, nodev, noexec, and relatime flags.
  • The /var, /var/log and the /var/log/audit directories are mounted on separate volumes or partitions, with the rw and relatime flags.
  • The /home directory is mounted on a separate partition or volume and has the rw, nodev, and relatime flags.
  • Include the following changes to the GRUB_CMDLINE_LINUX setting:

    • To enable auditing, add the audit=1 kernel boot flag.
    • To disable the kernel support for USB using boot loader configuration, add nousb.
    • To remove the insecure boot flags, remove crashkernel=auto.
  • Blacklist insecure modules (usb-storage, cramfs, freevxfs, jffs2, hfs, hfsplus, squashfs, udf, vfat) and prevent these modules from loading.
  • Remove any insecure packages like telnet from the image because they are installed by default.

24.2. Whole disk image workflow

To build a whole disk image, complete the following workflow:

  1. Download a base Red Hat Enterprise Linux 8.4 image.
  2. Set the environment variables specific to registration.
  3. Customize the image by modifying the partition schema and the size.
  4. Create the image.
  5. Upload the image to director.

24.3. Downloading the base cloud image

Before you build a whole disk image, you must download an existing cloud image of Red Hat Enterprise Linux to use as a basis.

Procedure

  1. Navigate to the Red Hat Enterprise Linux 8.4 download page. Red Hat OpenStack Platform 16.2 is supported on Red Hat Enterprise Linux 8.4.

  2. Click Download Now next to Red Hat Enterprise Linux 8.4 KVM Guest Image.

24.4. Enabling consistent interface naming

Consistent network interface device naming is disabled in the KVM guest image by default. Use virt-customize to enable consistent naming.

Procedure

  1. Move the KVM guest image to /var/lib/libvirt/images:

    $ sudo mv <kvm_guest_image> /var/lib/libvirt/images/
  2. Start libvirtd:

    $ sudo systemctl start libvirtd
  3. Enable consistent interface naming in the KVM guest image:

    $ sudo virt-customize -a /var/lib/libvirt/images/<kvm guest image> --edit /etc/default/grub:s/net.ifnames=0/net.ifnames=1/
  4. Stop libvirtd:

    $ sudo systemctl stop libvirtd

24.5. Disk image environment variables

As a part of the disk image building process, the director requires a base image and registration details to obtain packages for the new overcloud image. Define these attributes with the following Linux environment variables.

Note

The image building process temporarily registers the image with a Red Hat subscription and unregisters the system when the image building process completes.

To build a disk image, set Linux environment variables that suit your environment and requirements:

DIB_LOCAL_IMAGE
Sets the local image that you want to use as the basis for your whole disk image.
REG_ACTIVATION_KEY
Use an activation key instead of login details as part of the registration process.
REG_AUTO_ATTACH
Defines whether to attach the most compatible subscription automatically.
REG_BASE_URL
The base URL of the content delivery server that contains packages for the image. The default Customer Portal Subscription Management process uses https://cdn.redhat.com. If you use a Red Hat Satellite 6 server, set this parameter to the base URL of your Satellite server.
REG_ENVIRONMENT
Registers to an environment within an organization.
REG_METHOD
Sets the method of registration. Use portal to register a system to the Red Hat Customer Portal. Use satellite to register a system with Red Hat Satellite 6.
REG_ORG
The organization where you want to register the images.
REG_POOL_ID
The pool ID of the product subscription information.
REG_PASSWORD
Sets the password for the user account that registers the image.
REG_RELEASE
Sets the Red Hat Enterprise Linux minor release version. You must use it with the REG_AUTO_ATTACH or the REG_POOL_ID environment variable.
REG_REPOS

A comma-separated string of repository names. Each repository in this string is enabled through subscription-manager.

Use the following repositories for a security hardened whole disk image:

  • rhel-8-for-x86_64-baseos-eus-rpms
  • rhel-8-for-x86_64-appstream-eus-rpms
  • rhel-8-for-x86_64-highavailability-eus-rpms
  • ansible-2.9-for-rhel-8-x86_64-rpms
  • fast-datapath-for-rhel-8-x86_64-rpms
  • openstack-16.2-for-rhel-8-x86_64-rpms
REG_SAT_URL
The base URL of the Satellite server to register overcloud nodes. Use the Satellite HTTP URL and not the HTTPS URL for this parameter. For example, use http://satellite.example.com and not https://satellite.example.com.
REG_SERVER_URL
Sets the host name of the subscription service to use. The default host name is for the Red Hat Customer Portal at subscription.rhn.redhat.com. If you use a Red Hat Satellite 6 server, set this parameter to the host name of your Satellite server.
REG_USER
Sets the user name for the account that registers the image.

Use the following set of example commands to export a set of environment variables and temporarily register a local QCOW2 image to the Red Hat Customer Portal:

$ export DIB_LOCAL_IMAGE=./rhel-8.4-x86_64-kvm.qcow2
$ export REG_METHOD=portal
$ export REG_USER=<your_name>
$ export REG_PASSWORD=<your_password>
$ export REG_RELEASE="8.4"
$ export REG_POOL_ID=<pool_id>
$ export REG_REPOS="rhel-8-for-x86_64-baseos-eus-rpms \
    rhel-8-for-x86_64-appstream-eus-rpms \
    rhel-8-for-x86_64-highavailability-eus-rpms \
    ansible-2.9-for-rhel-8-x86_64-rpms \
    fast-datapath-for-rhel-8-x86_64-rpms \
    openstack-16.2-for-rhel-8-x86_64-rpms"

24.6. Customizing the disk layout

The default security hardened image size is 20G and uses predefined partitioning sizes. However, you must modify the partitioning layout to accommodate overcloud container images. Complete the steps in the following sections to increase the image size to 40G. You can modify the partitioning layout and disk size to further suit your needs.

To modify the partitioning layout and disk size, perform the following steps:

  • Modify the partitioning schema using the DIB_BLOCK_DEVICE_CONFIG environment variable.
  • Modify the global size of the image by updating the DIB_IMAGE_SIZE environment variable.

24.7. Modifying the partitioning schema

You can modify the partitioning schema to alter the partitioning size, create new partitions, or remove existing partitions. Use the following environment variable to define a new partitioning schema:

$ export DIB_BLOCK_DEVICE_CONFIG='<yaml_schema_with_partitions>'

BIOS example

The following YAML structure represents the modified logical volume partitioning layout to accommodate enough space to pull overcloud container images:

export DIB_BLOCK_DEVICE_CONFIG='''
- local_loop:
    name: image0
- partitioning:
    base: image0
    label: mbr
    partitions:
      - name: root
        flags: [ boot,primary ]
        size: 40G
- lvm:
    name: lvm
    base: [ root ]
    pvs:
        - name: pv
          base: root
          options: [ "--force" ]
    vgs:
        - name: vg
          base: [ "pv" ]
          options: [ "--force" ]
    lvs:
        - name: lv_root
          base: vg
          extents: 23%VG
        - name: lv_tmp
          base: vg
          extents: 4%VG
        - name: lv_var
          base: vg
          extents: 45%VG
        - name: lv_log
          base: vg
          extents: 23%VG
        - name: lv_audit
          base: vg
          extents: 4%VG
        - name: lv_home
          base: vg
          extents: 1%VG
- mkfs:
    name: fs_root
    base: lv_root
    type: xfs
    label: "img-rootfs"
    mount:
        mount_point: /
        fstab:
            options: "rw,relatime"
            fsck-passno: 1
- mkfs:
    name: fs_tmp
    base: lv_tmp
    type: xfs
    mount:
        mount_point: /tmp
        fstab:
            options: "rw,nosuid,nodev,noexec,relatime"
            fsck-passno: 2
- mkfs:
    name: fs_var
    base: lv_var
    type: xfs
    mount:
        mount_point: /var
        fstab:
            options: "rw,relatime"
            fsck-passno: 2
- mkfs:
    name: fs_log
    base: lv_log
    type: xfs
    mount:
        mount_point: /var/log
        fstab:
            options: "rw,relatime"
            fsck-passno: 3
- mkfs:
    name: fs_audit
    base: lv_audit
    type: xfs
    mount:
        mount_point: /var/log/audit
        fstab:
            options: "rw,relatime"
            fsck-passno: 4
- mkfs:
    name: fs_home
    base: lv_home
    type: xfs
    mount:
        mount_point: /home
        fstab:
            options: "rw,nodev,relatime"
            fsck-passno: 2
'''

Use this sample YAML content as a basis for the partition schema of your image. Modify the partition sizes and layout to suit your needs.

Note

You must define the correct partition sizes for the image because you cannot resize them after the deployment.

UEFI example

The following YAML structure represents the modified logical volume partitioning layout to accommodate enough space to pull overcloud container images:

export DIB_BLOCK_DEVICE_CONFIG='''
- local_loop:
    name: image0
- partitioning:
    base: image0
    label: gpt
    partitions:
      - name: ESP
        type: 'EF00'
        size: 200MiB
      - name: BSP
        type: 'EF02'
        size: 1MiB
      - name: ROOT
        type: '8300'
        size: 100%
- mkfs:
    name: fs_esp
    base: ESP
    type: vfat
    mount:
      mount_point: /boot/efi
      fstab:
        options: "defaults"
        fsck-passno: 1
- mkfs:
    name: fs_root
    label: "img-rootfs"
    base: ROOT
    type: xfs
    mount:
      mount_point: /
      fstab:
        options: "defaults"
        fsck-passno: 1
'''

Use this sample YAML content as a basis for the partition schema of your image. Modify the partition sizes and layout to suit your environment.

Note

You must define the correct partition sizes for the image before deployment because you cannot resize them after the deployment.

24.8. Modifying the image size

The global sum of the modified partitioning schema might exceed the default disk size (20G). In this situation, you might need to modify the image size. To modify the image size, edit the configuration files that create the image.

Procedure

  1. Create a copy of the /usr/share/openstack-tripleo-common/image-yaml/overcloud-hardened-images-python3.yaml:

    # cp /usr/share/openstack-tripleo-common/image-yaml/overcloud-hardened-images-python3.yaml \
    /home/stack/overcloud-hardened-images-python3-custom.yaml
    Note

    For UEFI whole disk images, use /usr/share/openstack-tripleo-common/image-yaml/overcloud-hardened-images-uefi-python3.yaml.

  2. Edit the DIB_IMAGE_SIZE in the configuration file and adjust the values as necessary:

    ...
    
    environment:
      DIB_PYTHON_VERSION: '3'
      DIB_MODPROBE_BLACKLIST: 'usb-storage cramfs freevxfs jffs2 hfs hfsplus squashfs udf vfat bluetooth'
      DIB_BOOTLOADER_DEFAULT_CMDLINE: 'nofb nomodeset vga=normal console=tty0 console=ttyS0,115200 audit=1 nousb'
      DIB_IMAGE_SIZE: '40' 1
      COMPRESS_IMAGE: '1'
    1
    Adjust this value to the new total disk size.
  3. Optional. To configure a proxy, you must also include the http_proxy and https:_proxy environment variables:

    environment:
      http_proxy: <proxy_server>
      https_proxy: <proxy_server>
    • Replace <proxy_server> with the address of your proxy.
  4. Save the file.
Important

When you deploy the overcloud, the director creates a RAW version of the overcloud image. This means your undercloud must have enough free space to accommodate the RAW image. For example, if you set the security hardened image size to 40G, you must have 40G of space available on the undercloud hard disk.

Important

When director writes the image to the physical disk, it creates a 64MB configuration drive primary partition at the end of the disk. When you create your whole disk image, ensure that the size of the physical disk accommodates this extra partition.

24.9. Building the whole disk image

After you set the environment variables and customize the image, create the image using the openstack overcloud image build command.

Procedure

  1. Run the openstack overcloud image build command with all necessary configuration files.

    # openstack overcloud image build \
    --image-name overcloud-hardened-full \ 1
    --config-file /home/stack/overcloud-hardened-images-python3-custom.yaml \ 2
    --config-file /usr/share/openstack-tripleo-common/image-yaml/overcloud-hardened-images-rhel8.yaml 3
    1
    For UEFI whole disk images, use overcloud-hardened-uefi-full.
    2
    The overcloud-hardened-images-python3-custom.yaml file is the custom configuration file that contains the new disk size. If you are not using a different custom disk size, use the original /usr/share/openstack-tripleo-common/image-yaml/overcloud-hardened-images-python3.yaml file instead. For standard UEFI whole disk images, use overcloud-hardened-images-uefi-python3.yaml.
    3
    For UEFI whole disk images, use overcloud-hardened-images-uefi-rhel8.yaml.

    This command creates an image called overcloud-hardened-full.qcow2, which contains all the necessary security features.

24.10. Uploading the whole disk image

Upload the image to the OpenStack Image (glance) service and start using it from the Red Hat OpenStack Platform director. To upload a security hardened image, complete the following steps:

  1. Rename the newly generated image and move the image to your images directory:

    # mv overcloud-hardened-full.qcow2 ~/images/overcloud-full.qcow2
  2. Remove all the old overcloud images:

    # openstack image delete overcloud-full
    # openstack image delete overcloud-full-initrd
    # openstack image delete overcloud-full-vmlinuz
  3. Upload the new overcloud image:

    # openstack overcloud image upload --image-path /home/stack/images --whole-disk

If you want to replace an existing image with the security hardened image, use the --update-existing flag. This flag overwrites the original overcloud-full image with a new security hardened image.