Create RHEL / CentOS 8 custom AMI for AWS using Image Builder

You can download this article in PDF format to support us through the following link.

Download the guide as a PDF

turn off


In this guide, we will discuss how to use Image Builder to create a custom RHEL 8 / CentOS 8 AMI for AWS. For newcomers to Image Builder, it is a tool for creating custom system images of Red Hat Enterprise Linux, including system images that are ready to be deployed on cloud platforms.

The image generator automatically processes the server setting details for each image output, so it is faster than the manual image creation method. Command line tool composer Available, as well as the graphical user interface in the Cockpit Web console.

Image generator block

  • blueprint – Define a customized system image by listing the software packages and customizations that will be included in the system. The blueprint is presented to the user in plain text format (Tom’s minimum language (TOML)).
  • write – The combination is a separate build of a system image based on a specific version of a specific blueprint.
  • customized – These are system specifications, not packaging. This includes users, groups and SSH keys.

Image Builder output format

The image generator allows you to construct images in multiple output formats. See the table below.

Description CLI name file extension
QEMU QCOW2 picture qcow2 .qcow2
Ext4 file system image ext4-filesystem .img
Raw partition disk image partitioned-disk .img
Start ISO in real time live-iso .iso
TAR file tar .tar
Amazon Machine Image Disk ami .ami
Azure Disk Image vhd .vhd
VMware virtual machine disk vmdk .vmdk
Open stack openstack .qcow2

Step 1: Install the Image Builder software package

Before using Image Builder, you need to install the following software packages.

                        sudo yum -y install vim lorax-composer composer-cli cockpit-composer bash-completion

Enable Image Builder to start after each restart:

                        sudo systemctl enable --now lorax-composer.socket

To access the UI through Cockpit, enable it:

                        sudo systemctl enable --now cockpit.socket
sudo firewall-cmd --add-service=cockpit && sudo firewall-cmd --add-service=cockpit --permanent

Load the shell configuration script so that the auto-complete function of the composer-cli command can start working immediately without restarting:

                        source  /etc/bash_completion.d/composer-cli

Step 2: Create a blueprint for Image Builder

We will use the command line interface to do this. However, the same operation can be performed from the Cockpit Web console. To use this interface, run composer Commands with appropriate options and parameters.

This is the workflow image generator:

  1. Export (save) blueprint definitions to plain text files
  2. Edit this file in a text editor
  3. Import (push) the blueprint text file into Image Builder
  4. Run compose to build the image based on the blueprint
  5. Export image files to download

Add your $ USER to the welder group.

                        sudo usermod -aG weldr $USER
newgrp weldr

Create Image Builder blueprint:

                        $ vim rhel8-base.toml

Mine has been modified as follows:

                        name = "rhel-8-base"
description = "A RHEL 8 Base Image"
version = "0.0.1"
groups = []

name = "vim"
version = "*"

name = "openssh-server"
version = "*"

name = "rsync"
version = "*"

name = "tmux"
version = "*"

name = "git"
version = "*"

name = "tree"
version = "*"

name = "bash-completion"
version = "*"

name = "lvm2"
version = "*"

name = "wget"
version = "*"

name = "firewalld"
version = "*"

name = "python3"
version = "*"

name = "python3-pip"
version = "*"

name = "telnet"
version = "*"

append = "net.ifnames=0"

name = "rheladmin"
description = " RHEL Admin User"
password = "hashed-user-password"
key = "your-ssh-pub-key"
home = "/home/rheladmin/"
shell = "/usr/bin/bash"
groups = ["users", "wheel"]

Replace Hash user password Hash with the actual password. To generate a hash, use the following command:

                        python3 -c 'import crypt,getpass;pw=getpass.getpass();print(crypt.crypt(pw) if (pw==getpass.getpass("Confirm: ")) else exit())'

Check document All entries and customized pages.

Push the blueprint back into Image Builder:

                        $ composer-cli blueprints push rhel8-base.toml

List the available image generators:

                        $ composer-cli  blueprints list


Step 3: Use Image Builder to create a system image

Through Start Option to build an image for your CentOS / RHEL machine.

                        $ composer-cli compose start BLUEPRINT-NAME IMAGE-TYPE

To view the available image types, run:

                        $ composer-cli compose types


Now, I will start writing with the blueprint and output type created.

                        $ composer-cli compose start rhel-8-base ami
Compose 036fb329-0443-48ad-9444-a1c70caa4b36 added to the queue

To check the status of writing:

                        $ composer-cli compose status
036fb329-0443-48ad-9444-a1c70caa4b36 RUNNING  Sat Apr  4 15:41:12 2020 rhel-8-base     0.0.1 ami            

$ composer-cli compose status
036fb329-0443-48ad-9444-a1c70caa4b36 FINISHED Sat Apr  4 15:46:52 2020 rhel-8-base     0.0.1 ami              4668260352  

After writing, download the generated image file:

                        $ composer-cli compose image UUID

-- Example ---
$ composer-cli compose image 036fb329-0443-48ad-9444-a1c70caa4b36
036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami: 4452.00 MB    

Step 4: Upload the AMI image to AWS

Install Python 3 and pip tools:

                        sudo yum -y install python3 python3-pip

Use pip to install the AWS command line tool:

                        sudo pip3 install awscli

Configure the AWS command line client based on your AWS access details:

                        $ aws configure
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]:
Default output format [None]:

Configure the AWS command line client to use your bucket:

                        $ BUCKET=ami-image-bucket
$ aws s3 mb s3://$BUCKET

Confirm the bucket creation:

                        $ aws s3 ls 
2020-04-04 15:49:47 ami-image-bucket

Create the vmimport S3 role in IAM and grant it access to S3:

                        printf '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals":{ "sts:Externalid": "vmimport" } } } ] }' > trust-policy.json

printf '{ "Version":"2012-10-17", "Statement":[ { "Effect":"Allow", "Action":[ "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket" ], "Resource":[ "arn:aws:s3:::%s", "arn:aws:s3:::%s/*" ] }, { "Effect":"Allow", "Action":[ "ec2:ModifySnapshotAttribute", "ec2:CopySnapshot", "ec2:RegisterImage", "ec2:Describe*" ], "Resource":"*" } ] }' $BUCKET $BUCKET > role-policy.json

aws iam create-role --role-name vmimport --assume-role-policy-document file://trust-policy.json

aws iam put-role-policy --role-name vmimport --policy-name vmimport --policy-document file://role-policy.json

Upload the AMI image to AWS:

                        $ BUCKET=ami-image-bucket
$ AMI=036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami
$ aws s3 cp $AMI s3://$BUCKET
upload: ./036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami to s3://ami-image-bucket/036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami

After the upload to S3 is complete, import the image as a snapshot into EC2:

                        printf '{ "Description": "my-image", "Format": "raw", "UserBucket": { "S3Bucket": "%s", "S3Key": "%s" } }' $BUCKET $AMI > containers.json

aws ec2 import-snapshot --disk-container file://containers.json

Sample output:

    "ImportTaskId": "import-snap-0617ccf6944d82089",
    "SnapshotTaskDetail": {
        "DiskImageSize": 0.0,
        "Format": "RAW",
        "Progress": "3",
        "Status": "active",
        "StatusMessage": "pending",
        "UserBucket": {
            "S3Bucket": "ami-image-bucket",
            "S3Key": "036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami"


Confirm the import process:

                        $ aws ec2 describe-import-snapshot-tasks --filters Name=task-state,Values=active
    "ImportSnapshotTasks": [
            "ImportTaskId": "import-snap-0617ccf6944d82089",
            "SnapshotTaskDetail": {
                "DiskImageSize": 4668260352.0,
                "Format": "RAW",
                "Progress": "94",
                "SnapshotId": "snap-0fd61ffa2f2cd4ad0",
                "Status": "active",
                "StatusMessage": "Preparing snapshot",
                "UserBucket": {
                    "S3Bucket": "ami-image-bucket",
                    "S3Key": "036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami"
            "Tags": []

Log in to AWS and confirm the existence of the snapshot.

Click “Snapshot” on EC2 and select Create an image :

Name the Image and set the virtualization type, disk size and description, etc.

Once created, the image will be available in the “AMI” section.


Similar guidelines:

Use Kickstart to automate RHEL and CentOS installation on KVM

Using Packer and Ansible to build an AWS EC2 machine image (AMI)

You can download this article in PDF format to support us through the following link.

Download the guide as a PDF

turn off


Related Posts