Exploring alternate user creation methods
In this exercise, you’ll explore other ways to create users and add credentials to image mode hosts.
Embedding user credentials into an image
There are many ways and many reasons why handling users would happen at any particular stage of the process, during deployment or after install via network authentication. In the previous exercises, we’ve created users and added ssh keys at install time, either via a blueprint file passed to bootc-image-builder
or via kickstart to Anaconda.
In addition to adding users during the creation of a host system, via bootc-image-builder
, cloud-init
, or some other means, we can also create users during the creation of the bootc image. This can be useful in certain cases where a specific user and credential are used for initial system management connectivity or emergency users are needed in environments with limited connectivity.
These users and credentials would be tied to the image, which means controlling how secrets are used in the build are important to understand before going down this path. You will want to explore more before making this choice in your own environment.
For this example, we’re going to add an SSH key to root
in the image, something that might be used for emergency access, and can be then rotated with an update.
Using podman secrets at build time
So far, we’ve been copying ssh keys directly into files with editors, which is fine for exercises or a very small numbers of users. We will use an additional feature of podman
to inject the credentials into the Containerfile using a more modern method like an external password vault.
First, we’ll set up a drop-in file that will configure SSHd to look for user authorized keys in a path controlled by the image. This gives us a way to update credentials later. The drop-in uses the %u
username match in the search path, so a key that matches the username in /usr/ssh
would act just like the typical authorized_keys
file in their home directory. Like the sudoers
drop-in, the sshd_config.d
directory is where SSHd looks in it’s config path for additional config files.
Create the expected directories we want to see in /etc
on the host first. Since we’re adding things to /etc
that we want to control via the host, we need to be careful to avoid local changes to these drop-ins.
mkdir -p etc/ssh/sshd_config.d
Then add the additional configuration directive for SSHd to read.
nano etc/ssh/sshd_config.d/330-auth-system.conf
AuthorizedKeysFile /usr/ssh/%u.keys .ssh/authorized_keys .ssh/authorized_keys2
The podman build
command has an option to pass information into a build in a way that it doesn’t get stored in the final image. It will read a file or an environment variable, and make the contents available during the build in a file under mounted under /run/secrets
on the host. The arguments passed to podman build --secret
will determine if the source of the secret is a file or an environment variable. To pass more than one secret, you add an additional --secret
argument.
Inside the build, we can have a RUN
directive read that file and do something with it. There’s a --mount
option for RUN
that can be used for a lot of different things, but one of those options is a secrets
mount type. There are other options for the RUN
directive, but we’ll keep it as simple as we can here.
The id
is the connection between the RUN
directive in the Containerfile and the podman build
command. The id
of the secret is the filename mounted under /run/secrets
, which we then can extract the contents for our ssh key. This id
needs to match in the podman build
and in the Containerfile. We’ll highlight those in the examples below.
You can now edit the Containerfile
to match the following.
FROM registry.redhat.io/rhel9/rhel-bootc:9.5
RUN dnf install -y httpd
ADD etc/ /etc (1)
RUN mkdir -p /usr/ssh (2)
RUN --mount=type=secret,id=SSHPUBKEY cat /run/secrets/SSHPUBKEY > /usr/ssh/root.keys \ (3)
&& chmod 0600 /usr/ssh/root.keys (4)
RUN <<EOF
set -euxo pipefail
mv /var/www /usr/share/www
sed -i 's-/var/www-/usr/share/www-' /etc/httpd/conf/httpd.conf
EOF
RUN echo "Hello Red Hat Summit 2025!!" > /usr/share/www/html/index.html
RUN systemctl enable httpd.service
1 | ADD etc/ /etc → automatically picks up the drop-in for sshd since we added it to our local etc source |
2 | RUN mkdir -p /usr/ssh → create the new keys directory in /usr so it will be controlled in the image |
3 | RUN --mount=type=secret,id=SSHPUBKEY… → mounts the file located at the id , only available during this build |
4 | Fixes the permissions on the SSH key |
When you build the image, make note of the --secret
argument.
-
id
→ matches theRUN
line so we have the file in the right place for use at build -
src
→ the file that contains the secret on the host, in this case our SSH public key.
We’re also going to use a new tag for this image, like we did in the previous bootc switch
exercise.
podman build --secret id=SSHPUBKEY,src=.ssh/my-guidkey.pub --file Containerfile --tag {registry_hostname}/httpd:auth
And make sure to push it to the registry:
podman push {registry_hostname}/httpd:auth
Changing the virtual machine image
The virtual machine you have been working with during this lab should still be running. You can check this with
virsh --connect qemu:///system list
And the output should contain a virtual machine called qcow-vm
.
Now you can ssh into the virtual machine
ssh core@qcow-vm
We can change to our new image with the embedded root
credentials
sudo bootc switch {registry_hostname}/httpd:auth
layers already present: 69; layers needed: 5 (7.2 kB) Fetched layers: 7.06 KiB in 16 seconds (462 B/s) Deploying: done (4 seconds) Queued for next boot: node.545jj.gcp.redhatworkshops.io/httpd:auth Version: 9.20250415.0 Digest: sha256:45352aa6baee739183feeed562fd1cd06e40c40a224ba6d6eee9e1cb78214b2d
As usual, after the command is done you need to reboot the virtual machine
for the changes to take effect. Before doing that, please make sure you are logged in to the
virtual machine and not the hypervisor (the prompt should look like [core@localhost ~]$
):
sudo systemctl reboot
Testing the changes
You can now login to the virtual machine with the newly added root credentials:
ssh root@qcow-vm
And check once again the status of bootc (no need to use sudo
, you are root!):
bootc status
No staged image present Current booted image: node.545jj.gcp.redhatworkshops.io/httpd:auth Image version: 9.20250415.0 (2025-04-16 21:14:37.616335138 UTC) Image digest: sha256:45352aa6baee739183feeed562fd1cd06e40c40a224ba6d6eee9e1cb78214b2d Current rollback image: node.545jj.gcp.redhatworkshops.io/caddy-wp Image version: 9.20250415.0 (2025-04-16 20:42:46.356417348 UTC) Image digest: sha256:c15b09203ea36a342135cc2d1c061ea96c0b61f4e5c46fd38bc8afe3f6c787a0
Feel free to explore the virtual machine before moving on to the next section, remembering you are now root
.
You’ve completed the final exercise in the lab. You should have a good baseline for how image mode operates and how it might be of use in your environment. You can find more information about image mode in the Links section at the top of the page. Feel free to log out of the virtual machine and revisit any modules as well.