Skip to content

Creating a custom manifest

Create a custom Automotive Image Builder manifest file to build an AutoSD OS image. Use your manifest file to define the components and functionality of your image. A manifest file can be as simple as the following minimal manifest example:

Prerequisites

Minimal AIB manifest
name: minimal

content:
  rpms: []


# Set a password so that you can log in to the system. Setting a
# password is not necessary to build the minimal image, but you
# cannot log in without configuring a password.
auth:
  # "password"
  root_password: $6$xoLqEUz0cGGJRx01$H3H/bFm0myJPULNMtbSsOFd/2BnHqHkMD92Sfxd.EKM9hXTWSmELG8cf205l6dktomuTcgKGGtGDgtvHVXSWU.

For a summary of all available manifest sections, see Manifest sections at a glance. For the complete manifest schema with nesting hierarchy, see the AIB simple manifest reference.

Manipulating content and files

The content section defines everything that goes into your image, including RPM packages, files, symbolic links, directories, file permissions, and systemd service configuration.

Including RPM packages

The content.rpms list specifies RPM packages to install into the image. Packages are resolved from the default AutoSD repositories, plus any additional repositories defined in content.repos. Package names can optionally include a version constraint; otherwise the repository priorities and available versions determine which version is installed.

content:
  rpms:
    - vim-enhanced
    - wget
    - openssh-server

For a complete example, see the rpm_remote demo manifest.

Use an empty list (rpms: []) to build an image with only the base AutoSD packages and no additional RPMs, as shown in the minimal manifest.

Enabling default repositories

The content.enable_repos list activates predefined AutoSD repositories that are available but not enabled by default. The supported values are devel and debug.

content:
  enable_repos:
    - devel

Adding other RPM repositories

The content.repos list defines additional dnf repositories to use when installing packages. Each entry requires an id and a baseurl. An optional priority integer controls package resolution order when multiple repositories provide the same package (lower values take precedence; the default is 99).

The baseurl value accepts remote URLs and local paths using the file:// scheme.

content:
  repos:
    - id: my-apps
      baseurl: https://example.com/repo/$arch/
    - id: local-repo
      baseurl: file:///var/tmp/my_repo
      priority: 10
  rpms:
    - my-custom-package

For a complete example that combines local and remote repositories, see the rpm_local demo manifest.

Copying files from the host into the image at build time

You can copy files from your host machine into the image during the build process. To include artifacts or configurations in your build, use the source_path parameter within your manifest’s add_files section. The source_path option handles relative and absolute paths in specific ways.

Relative path

By default, source_path uses a relative path based on the directory that contains the manifest file. Use a relative path when you store build artifacts alongside the manifest.

Example:

If your manifest is at /home/user/my-project/simple-minimal.aib.yml and you want to include /home/user/my-project/files/my-file.conf, define your manifest as follows:

content:
  add_files:
    - path: /etc/myapp/my-file.conf
      source_path: ./files/my-file.conf

Absolute paths

If the files you want to include are stored outside the manifest’s directory, use an absolute path. Begin the path with // so that source_path recognizes it as absolute.

Example:

content:
  add_files:
    - path: /etc/myapp/my-file.conf
      source_path: //home/user/files/my-file.conf

Sideloading from an arbitrary directory

To maximize flexibility, especially in CI/CD pipelines, use a variable for the source path in your manifest and provide its value on the command line.

In your manifest, define source_path using a variable:

content:
  add_files:
    - path: /etc/myapp/my-file.conf
      source_path: //$sideload_dir/my-file.conf

Then pass the variable value with --define when running the build:

$ aib-dev build \
    --define sideload_dir=/home/user/my-project/files \
    simple-minimal.aib.yml "localhost/my-image"

The build copies /home/user/my-project/files/my-file.conf from the host into the image’s /etc/myapp/ directory.

Copying files with glob patterns

Use source_glob inside add_files to copy multiple files that match a glob pattern. The following options control glob behavior:

  • preserve_path – Preserve the relative directory structure of matched files in the destination.
  • max_files – Limit the number of files matched.
  • allow_empty – Allow the glob to match zero files without failing the build.
content:
  add_files:
    - path: /etc/myapp/conf.d/
      source_glob: configs/*.conf
      preserve_path: true

Use add_symlinks under content to create symbolic links in the image. Each entry requires a link path and a target path.

content:
  add_symlinks:
    - link: /usr/local/bin/myapp
      target: /opt/myapp/bin/myapp

Changing file permissions

Use chmod_files under content to change file permissions. Specify the mode as a string. Set recursive to true to apply permissions to all files within a directory.

The following example comes from the SELinux demo manifest:

content:
  chmod_files:
    - path: /usr/bin/server
      mode: "755"
    - path: /usr/bin/client
      mode: "755"

Changing file ownership

Use chown_files under content to change file ownership. Specify user, group, or both. Set recursive to true to apply ownership changes to all files within a directory.

content:
  chown_files:
    - path: /opt/myapp
      user: myuser
      group: mygroup
      recursive: true

Removing files

Use remove_files under content to remove files that were installed by RPM packages but are not needed in the final image.

content:
  remove_files:
    - path: /usr/share/doc/unwanted-package

Creating directories

Use make_dirs under content to create directories in the image. The following options are available:

  • mode – Set the directory permissions (for example, 0755).
  • parents – Create parent directories as needed, similar to mkdir -p.
  • exist_ok – Do not fail if the directory already exists.

The following example comes from the BlueChi demo manifest:

content:
  make_dirs:
    - path: /etc/containers/systemd/qm.container.d
      mode: 0755
      parents: true
      exist_ok: true

Container image options

When embedding container images with content.container_images, each entry supports the following properties:

  • source (required) – Defines the container image name, for example quay.io/fedora/fedora.
  • tag – Defines the tag to use in the repository. Defaults to latest.
  • digest – Specifies a specific image version by digest.
  • name – Overrides the name used for the container image when embedded. Defaults to the source value.
  • containers-transport – Specifies the containers transport from which to copy the image. Accepted values are docker and containers-storage.
  • index – When set to true, also install the related manifest-list for the image. Use the index option when building multi-architecture images that need the full manifest list rather than a single platform-specific image.

The following shows example settings:

content:
  container_images:
    - source: quay.io/myorg/myapp
      tag: "1.0"
      index: true

For complete procedures on embedding container images, see Embedding container images from a remote registry and Embedding local containerized applications.

Systemd services

Use content.systemd to control which systemd services are enabled, disabled, or masked in the image. The following options are available:

  • enabled_services – A list of systemd unit names to enable at boot.
  • disabled_services – A list of systemd unit names to disable.
  • masked_services – A list of systemd unit names to mask, preventing them from starting under any circumstances.
content:
  systemd:
    enabled_services:
      - sshd.service
      - myapp.service
    disabled_services:
      - unneeded.service
    masked_services:
      - dangerous.service

For information on controlling service start order, see Prioritizing service order. For information on monitoring services at runtime, see Monitoring and managing services.

Image and SELinux configuration

The image section controls global image properties, including total image size, sealed mode, and SELinux configuration.

Image size

Set image_size to specify the total disk image size. The value accepts SI suffixes (kB, MB, GB, TB) and IEC suffixes (KiB, MiB, GiB, TiB).

image:
  image_size: 8 GiB

Sealed images

The sealed option controls whether the image allows only the original or a re-sealed image to boot. Sealed images default to true.

image:
  sealed: false

SELinux configuration

The following SELinux options are available under the image section:

  • selinux_mode – Set to enforcing (default) or permissive.
  • selinux_policy – Specify a custom SELinux policy name.
  • selinux_booleans – Set individual SELinux boolean values.

The following example references the custom SELinux policy demo manifest at demos/custom_selinux_policy/:

image:
  selinux_mode: enforcing
  selinux_booleans:
    container_use_devices: true

Boot checks

The boot_checks key configures system boot checks that verify a successful boot. Boot checks are built on the sysboot package. When any check is defined, AIB automatically installs sysboot and enables sysboot-health.target.

You can use the following sub-keys:

  • commands – A list of custom checks. Each entry requires a name (alphanumeric characters, hyphens, and underscores) and a cmd (the command to execute). AIB creates a systemd drop-in for sysboot-check@<name>.service and enables the service instance.
  • systemd – A list of existing systemd unit names to monitor. Unit names must end with .service, .target, .mount, .socket, or .device. AIB creates a sysboot drop-in for each unit that triggers a reboot on failure.
image:
  boot_checks:
    commands:
      - name: network-ready
        cmd: /usr/bin/nmcli networking connectivity check
    systemd:
      - boot-complete.target

Partition options

The partitions key is defined under the image: section in the manifest. It controls disk partition sizing for the image. All size values accept SI suffixes (kB, MB, GB, TB) and IEC suffixes (KiB, MiB, GiB, TiB).

Root partition

Use root.grow to allow the root filesystem to expand to fill the available disk space on first boot.

image:
  partitions:
    root:
      grow: true

Boot partitions

Configure boot and EFI partition sizes using boot.size and efi.size.

image:
  partitions:
    boot:
      size: 1 GiB
    efi:
      size: 512 MiB

/var partition

The /var partition supports the following options:

  • var.size – Set an absolute size for the /var partition.
  • var.relative_size – Set the size as a fraction (0 to 1) of the total image size.
  • var.external – Mark /var as an external mount point rather than an inline partition.
  • var.uuid – Set a specific UUID for the /var partition.
image:
  partitions:
    var:
      size: 2 GiB

/var/qm partition

When QM is enabled, the /var/qm partition accepts the same options as the /var partition (size, relative_size, external, uuid).

image:
  partitions:
    var_qm:
      size: 1 GiB

Kernel options

The kernel key is a top-level key in the manifest. It configures kernel-related build options. The following options are available:

  • cmdline – A list of extra kernel command-line parameters appended at boot.
  • kernel_package – Specify a custom kernel package name to install instead of the default.
  • kernel_version – Pin a specific kernel version string.
  • debug_logging – Enable verbose kernel boot logging.
  • loglevel – Set the kernel log level (integer).
  • remove_modules – A list of kernel module names to remove from the image, reducing image size.
kernel:
  cmdline:
    - "console=ttyS0,115200n8"
  loglevel: 7

For a complete procedure on building an image with a custom kernel, see Building an AutoSD image that includes a custom kernel.

Authentication and users

The auth section configures user accounts, groups, SSH access, and the root password.

Root access

The following options control root account access:

  • root_password – A hashed root password string (use mkpasswd or openssl passwd -6 to generate the hash).
  • root_ssh_keys – A list of SSH public keys authorized for root login.
auth:
  root_password: "$6$rounds=..."
  root_ssh_keys:
    - "ssh-ed25519 AAAA... admin@host"

SSH daemon configuration

The sshd_config section sets options in the SSH daemon configuration:

auth:
  sshd_config:
    PasswordAuthentication: true
    PermitRootLogin: true

PermitRootLogin accepts a boolean (true or false) or one of the strings "prohibit-password" or "forced-commands-only".

Groups

Define additional groups with optional GID values:

auth:
  groups:
    guest:
      gid: 2000
    developers:
      gid: 3000

Users

Define additional user accounts under auth.users. Each user entry accepts the following optional properties:

  • uid – User ID number.
  • gid – Primary group ID number.
  • groups – A list of supplementary group names.
  • description – User account description or full name.
  • home – Path to the home directory.
  • shell – Login shell path.
  • password – Encrypted password string, as returned by crypt(3).
  • key – A single SSH public key for ~/.ssh/authorized_keys.
  • keys – A list of SSH public keys for ~/.ssh/authorized_keys.
  • force_password_reset – When set to true, force the user to change their password on first login.
  • expiredate – The date on which the user account is disabled, represented as a number of days since January 1, 1970.

The following example comes from the users demo manifest at demos/users/users.aib.yml:

auth:
  users:
    guest:
      password: "$6$rounds=..."
      gid: 2000
      uid: 2000
      home: /var/guest
    foo:
      gid: 2042
      uid: 2042
      shell: /sbin/nologin

The following example creates a temporary account with a fixed expiration date and a required password change on first login:

auth:
  users:
    contractor:
      password: "$6$rounds=..."
      uid: 3000
      gid: 3000
      force_password_reset: true
      expiredate: 21550

Network configuration

The network section configures network connectivity for the image. Automotive Image Builder supports two modes: dynamic (default) and static.

Dynamic networking

Dynamic networking uses NetworkManager to obtain an IP address automatically. No additional configuration is required because dynamic mode is the default.

network:
  dynamic: {}

Static networking

Static networking configures a fixed IP address. The following options are available:

  • ip – The static IP address.
  • ip_prefixlen – The subnet prefix length (for example, 24).
  • gateway – The default gateway address.
  • dns – The DNS server address.
  • iface – The network interface name (optional).
  • load_module – A kernel module to load for the network interface (optional).

The following example comes from the networking demo manifest at demos/networking/networking.aib.yml:

network:
  static:
    ip: "169.254.6.21"
    ip_prefixlen: 24
    gateway: "169.254.6.2"
    dns: "169.254.6.3"

Other image options

The hostname and ostree_ref keys are defined under the image: section. The version key is a top-level key.

Hostname

Set the network hostname for the image:

image:
  hostname: my-vehicle-ecu

OSTree ref

Override the default OSTree ref name. The default value follows the pattern $distro_name/$arch/$target-$name:

image:
  ostree_ref: "autosd10/x86_64/qemu-custom"

Version

Set the image version string. Automotive Image Builder uses the value in the OSTree commit metadata and writes it to /etc/build-info as IMAGE_VERSION:

version: "1.0.0"

Next steps

Learn about configuring options and continue to customize your manifest by embedding RPM application packages and containerized applications.


© Red Hat