Appendix A: RHEL Developer Environment Setup
Choose one of the three options below to prepare your developer environment. Option 1 is the fastest path.
Option 1: RHDP Pre-Provisioned Environment (Recommended)
The Red Hat Demo Platform (RHDP) provides a ready-to-use RHEL 9 desktop with Podman and container tools pre-installed. This is the fastest way to get started.
Deploy the Environment
-
Click the link below to open the RHDP catalog:
-
Log in with your Red Hat credentials (SSO for associates, user account for partners)
-
Click Order and wait for the environment to provision (typically 5-10 minutes)
-
Once ready, you will receive connection details (SSH or web console access)
After Provisioning
The RHDP RHEL 9 Desktop environment comes with Podman and core container tools pre-installed. Depending on the environment version, you may still need to run the automation script (Option 2) or selected manual steps (Option 3) to complete the Hummingbird-specific configuration such as registry setup, JDK 21, Quarkus CLI, and Podman Desktop.
Verify your environment is ready:
podman --version
buildah --version
skopeo --version
java --version
quarkus --version
cosign version
syft version
grype version
podman info --format '{{.Host.Security.Rootless}}'
If any of the above commands fail, use Option 2 (script) or Option 3 (manual steps) below to complete the setup.
Option 2: Automation Script
Run a single script to install and configure everything automatically. This works on RHEL 9.5, RHEL 10.0, or Fedora 43.
You can either download the script and run it, or copy-paste the inline version below.
Download and Run
curl -LO https://raw.githubusercontent.com/rhpds/zero-cve-hummingbird-showroom/main/content/modules/ROOT/assets/attachments/setup-rhel-developer.sh
chmod +x setup-rhel-developer.sh
./setup-rhel-developer.sh
After the script completes, reload your shell so the Quarkus CLI is on your PATH:
source ~/.bashrc
Or download directly: setup-rhel-developer.sh
Or Copy-Paste Inline
bash << 'SETUP_SCRIPT'
#!/bin/bash
set -euo pipefail
echo "=== Hummingbird Workshop: RHEL Developer Environment Setup ==="
echo ""
# --- System Update ---
echo "[1/13] Updating system packages..."
sudo dnf update -y
# --- Core Container Tools ---
echo "[2/13] Installing Podman, Buildah, Skopeo, and container-tools..."
sudo dnf install -y podman buildah skopeo container-tools
# --- JDK 21 ---
echo "[3/13] Installing OpenJDK 21..."
sudo dnf install -y java-21-openjdk-devel
# --- Quarkus CLI via JBang ---
echo "[4/13] Installing Quarkus CLI (via JBang)..."
curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/
curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio
export PATH="$HOME/.jbang/bin:$PATH"
if ! grep -q '.jbang/bin' ~/.bashrc 2>/dev/null; then
echo 'export PATH="$HOME/.jbang/bin:$PATH"' >> ~/.bashrc
fi
# --- Rootless Podman: subuid/subgid ---
echo "[5/13] Configuring rootless Podman (subuid/subgid)..."
if ! grep -q "^$(whoami):" /etc/subuid; then
echo "$(whoami):100000:65536" | sudo tee -a /etc/subuid
fi
if ! grep -q "^$(whoami):" /etc/subgid; then
echo "$(whoami):100000:65536" | sudo tee -a /etc/subgid
fi
# --- User Lingering ---
echo "[6/13] Enabling user lingering..."
sudo loginctl enable-linger $(whoami)
# --- Podman Socket ---
echo "[7/13] Enabling Podman socket..."
systemctl --user enable --now podman.socket
# --- Registry Configuration ---
echo "[8/13] Configuring container registries..."
mkdir -p ~/.config/containers
cat > ~/.config/containers/registries.conf << 'EOF'
unqualified-search-registries = ["registry.access.redhat.com", "quay.io", "docker.io"]
[[registry]]
location = "registry.access.redhat.com"
insecure = false
blocked = false
[[registry]]
location = "registry.redhat.io"
insecure = false
blocked = false
[[registry]]
location = "quay.io"
insecure = false
blocked = false
[[registry]]
location = "quay.io/hummingbird-hatchling"
insecure = false
blocked = false
EOF
# --- Storage Configuration ---
echo "[9/13] Configuring container storage..."
cat > ~/.config/containers/storage.conf << 'EOF'
[storage]
driver = "overlay"
[storage.options]
mount_program = "/usr/bin/fuse-overlayfs"
[storage.options.overlay]
mountopt = "nodev,metacopy=on"
EOF
# --- Security Tools: Cosign ---
echo "[10/13] Installing Cosign (image signing)..."
COSIGN_VERSION=v2.4.1
curl -sLO https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64
sudo install -m 755 cosign-linux-amd64 /usr/local/bin/cosign
rm -f cosign-linux-amd64
# --- Security Tools: Syft ---
echo "[11/13] Installing Syft (SBOM generation)..."
SYFT_VERSION=v1.17.0
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sudo sh -s -- -b /usr/local/bin ${SYFT_VERSION}
# --- Security Tools: Grype ---
echo "[12/13] Installing Grype (vulnerability scanning)..."
GRYPE_VERSION=v0.88.0
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sudo sh -s -- -b /usr/local/bin ${GRYPE_VERSION}
# --- Podman Desktop ---
echo "[13/13] Installing Podman Desktop..."
RHEL_MAJOR=$(rpm -E '%{rhel}' 2>/dev/null || echo "9")
ARCH=$(uname -m)
LAUNCH_CMD="podman-desktop"
if [[ "${RHEL_MAJOR}" -ge 10 ]]; then
# RHEL 10+: official Red Hat build via extensions repo
sudo subscription-manager repos --enable "rhel-${RHEL_MAJOR}-for-${ARCH}-extensions-rpms" 2>/dev/null || true
if sudo dnf install -y rh-podman-desktop 2>/dev/null; then
echo "Podman Desktop (Red Hat build) installed via dnf."
else
flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install --user -y flathub io.podman_desktop.PodmanDesktop
LAUNCH_CMD="flatpak run io.podman_desktop.PodmanDesktop"
echo "Podman Desktop installed via Flatpak."
fi
else
# RHEL 9: Flatpak from Flathub (official recommendation for Linux)
flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo
if flatpak install --user -y flathub io.podman_desktop.PodmanDesktop 2>/dev/null; then
LAUNCH_CMD="flatpak run io.podman_desktop.PodmanDesktop"
echo "Podman Desktop installed via Flatpak."
else
echo "Warning: Podman Desktop could not be installed automatically."
echo "Install manually from https://podman-desktop.io/downloads"
LAUNCH_CMD="# see https://podman-desktop.io/downloads"
fi
fi
echo ""
echo "=== Setup Complete ==="
echo "Podman: $(podman --version)"
echo "Buildah: $(buildah --version)"
echo "Skopeo: $(skopeo --version)"
echo "Java: $(java --version 2>&1 | head -1)"
echo "Quarkus CLI: $(quarkus --version)"
echo "Cosign: $(cosign version 2>&1 | head -1)"
echo "Syft: $(syft version 2>&1 | head -1)"
echo "Grype: $(grype version 2>&1 | head -1)"
echo "Rootless: $(podman info --format '{{.Host.Security.Rootless}}')"
echo "Storage: $(podman info --format '{{.Store.GraphDriverName}}')"
echo ""
echo "You can now launch Podman Desktop with: ${LAUNCH_CMD} &"
echo ""
echo "IMPORTANT: Run 'source ~/.bashrc' to make the Quarkus CLI available."
echo ""
echo "Proceed to Module 1 to start the workshop labs."
SETUP_SCRIPT
Once the script completes, reload your shell so the Quarkus CLI is on your PATH:
source ~/.bashrc
Verify the setup:
quarkus --version
cosign version
syft version
grype version
podman pull quay.io/hummingbird/openjdk:21-runtime
podman pull registry.access.redhat.com/ubi9/openjdk-21:latest
podman images | grep -E "hummingbird|ubi9"
Option 3: Manual Steps
Follow the detailed steps below if you prefer to configure each component individually, or if you need to troubleshoot a specific part of the setup.
System Update and Core Tool Installation
Step 1: System Update
sudo dnf update -y
Complete!
|
If a kernel update is installed, you may need to reboot your system before proceeding. Check with:
|
Step 2: Install Core Container Tools
Install Podman, Buildah, and Skopeo - the foundational tools for container workflows.
sudo dnf install -y podman buildah skopeo container-tools
-
Podman: Daemonless container engine for running and managing containers
-
Buildah: Specialized tool for building container images
-
Skopeo: Utility for inspecting, copying, and managing container images across registries
JDK 21 and Quarkus CLI
The workshop uses Quarkus as its primary application framework. The Quarkus CLI scaffolds projects in a single command.
Step 4: Install OpenJDK 21
sudo dnf install -y java-21-openjdk-devel
Verify the installation:
java --version
openjdk 21.0.6 2025-01-21 LTS OpenJDK Runtime Environment (Red_Hat-21.0.6.0.7-1) (build 21.0.6+7-LTS) OpenJDK 64-Bit Server VM (Red_Hat-21.0.6.0.7-1) (build 21.0.6+7-LTS, mixed mode, sharing)
|
The exact version may differ. Any OpenJDK 21.x release will work for this workshop. |
Step 5: Install Quarkus CLI via JBang
JBang is a lightweight launcher for JVM-based tools. The Quarkus CLI uses it for installation and version management.
curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/
curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio
Add JBang to your PATH for this session and persist it:
export PATH="$HOME/.jbang/bin:$PATH"
echo 'export PATH="$HOME/.jbang/bin:$PATH"' >> ~/.bashrc
Verify the Quarkus CLI:
quarkus --version
3.17.0
|
The Quarkus CLI version may be newer than shown. Any 3.x release is compatible with this workshop. |
Rootless Podman Configuration
Rootless containers run without requiring root privileges, enhancing security. Let’s configure the necessary user namespaces.
Step 6: Configure Rootless Podman
Configure user namespaces and subuid/subgid mappings:
# Check if subuid/subgid are already configured
grep "^$(whoami):" /etc/subuid /etc/subgid
# If empty, configure them (100000 subordinate UIDs/GIDs starting at 100000)
if ! grep -q "^$(whoami):" /etc/subuid; then
echo "$(whoami):100000:65536" | sudo tee -a /etc/subuid
fi
if ! grep -q "^$(whoami):" /etc/subgid; then
echo "$(whoami):100000:65536" | sudo tee -a /etc/subgid
fi
Configures 65,536 subordinate UIDs and GIDs for your user, allowing Podman to map container user namespaces to your regular user account.
Step 7: Enable User Lingering
Enable lingering to allow your user systemd services to run even when you’re not logged in:
sudo loginctl enable-linger $(whoami)
This is essential for the Podman socket to remain active for Podman Desktop integration.
Step 8: Start Podman Socket
Enable and start the Podman socket for API access (used by Podman Desktop):
systemctl --user enable --now podman.socket
systemctl --user status podman.socket
● podman.socket - Podman API Socket
Loaded: loaded (/usr/lib/systemd/user/podman.socket; enabled)
Active: active (listening)
Press q to exit the status view.
Step 9: Verify Rootless Configuration
podman info --format '{{.Host.Security.Rootless}}'
true
podman run --rm quay.io/hummingbird/openjdk:21-runtime java --version
openjdk 21.0.6 2025-01-21 LTS ...
|
If you see permission errors, verify your subuid/subgid configuration and ensure you’ve logged out and back in after making changes to |
Registry Configuration
Configure authentication and trust for the registries hosting Hummingbird and UBI images.
Step 10: Configure Registry Authentication
On RHEL and Fedora systems, container registries are configured in /etc/containers/registries.conf (system-wide) or ~/.config/containers/registries.conf (user-specific). For this workshop, we’ll use user-specific configuration.
mkdir -p ~/.config/containers
cat > ~/.config/containers/registries.conf << 'EOF'
# Registry configuration for Hummingbird and UBI images
# Search registries for unqualified image names
unqualified-search-registries = ["registry.access.redhat.com", "quay.io", "docker.io"]
# Red Hat Registry (UBI images)
[[registry]]
location = "registry.access.redhat.com"
insecure = false
blocked = false
# Red Hat Certified Registry (subscription required for some images)
[[registry]]
location = "registry.redhat.io"
insecure = false
blocked = false
# Quay.io (Hummingbird images)
[[registry]]
location = "quay.io"
insecure = false
blocked = false
# Hummingbird-specific namespace
[[registry]]
location = "quay.io/hummingbird-hatchling"
insecure = false
blocked = false
EOF
-
unqualified-search-registries: When you run
podman pull nodejs, Podman searches these registries in order -
registry.access.redhat.com: Public Red Hat registry (no authentication required for UBI images)
-
registry.redhat.io: Authenticated Red Hat registry (requires Red Hat subscription for some images)
-
quay.io: Public container registry hosting Hummingbird images
|
Red Hat Subscription Note: UBI (Universal Base Images) from |
Step 11: Test Registry Access
Pull a sample Hummingbird image to verify registry connectivity:
podman pull quay.io/hummingbird/openjdk:21-runtime
Trying to pull quay.io/hummingbird-hatchling/openjdk:21-runtime... Getting image source signatures Copying blob sha256:abc123... Copying blob sha256:def456... Copying config sha256:789... Writing manifest to image destination Storing signatures
Verify the image is available locally:
podman images | grep hummingbird
quay.io/hummingbird-hatchling/openjdk 21-runtime abc123def456 2 days ago 253 MB
Step 12: Test UBI Registry Access
podman pull registry.access.redhat.com/ubi9/openjdk-21:latest
Trying to pull registry.access.redhat.com/ubi9/openjdk-21:latest... Getting image source signatures Copying blob sha256:xyz789... Writing manifest to image destination Storing signatures
|
RHEL vs Fedora Registry Behavior:
To view your active configuration:
|
Step 13: Configure Storage (Optional but Recommended)
Optimize storage configuration for better performance on RHEL/Fedora:
cat > ~/.config/containers/storage.conf << 'EOF'
[storage]
driver = "overlay"
[storage.options]
mount_program = "/usr/bin/fuse-overlayfs"
[storage.options.overlay]
mountopt = "nodev,metacopy=on"
EOF
-
overlay driver: Modern, efficient layered filesystem (default on RHEL 9+)
-
fuse-overlayfs: Allows rootless users to use overlay mounts without privileges
-
metacopy=on: Performance optimization for metadata operations
|
On RHEL 9+ and recent Fedora versions, the overlay driver with fuse-overlayfs is already the default for rootless Podman. This configuration explicitly sets it for consistency across environments. |
Security Tools Installation
Install tools for container image signing, SBOM generation, and vulnerability scanning. These are used extensively in Module 1 labs.
Step 14: Install Cosign (Image Signing)
Cosign is used to sign and verify container images:
COSIGN_VERSION=v2.4.1
curl -LO https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64
sudo install -m 755 cosign-linux-amd64 /usr/local/bin/cosign
rm cosign-linux-amd64
cosign version
cosign version {cosign-version}
|
Cosign in Production:
|
Step 15: Install Syft (SBOM Generation)
Syft generates Software Bill of Materials (SBOMs) from container images:
SYFT_VERSION=v1.17.0
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sudo sh -s -- -b /usr/local/bin ${SYFT_VERSION}
syft version
syft version 1.17.0
|
What is an SBOM? A Software Bill of Materials (SBOM) is a complete inventory of all packages, libraries, and dependencies in your container image. SBOMs are essential for:
|
Step 16: Install Grype (Vulnerability Scanning)
Grype scans container images for known CVEs:
GRYPE_VERSION=v0.88.0
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sudo sh -s -- -b /usr/local/bin ${GRYPE_VERSION}
grype version
grype version 0.88.0
|
Grype downloads a vulnerability database on first run. This may take a few minutes initially. The database is cached locally and updated periodically. |
Podman Desktop Installation
The installation method differs between RHEL 9 and RHEL 10.
Step 17a: Install Podman Desktop on RHEL 9 (Flatpak)
On RHEL 9, Flatpak from Flathub is the official recommended installation method.
flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install --user -y flathub io.podman_desktop.PodmanDesktop
|
The |
Step 17b: Install Podman Desktop on RHEL 10 (dnf)
On RHEL 10, the official Red Hat build is available via the extensions repository.
sudo subscription-manager repos --enable "rhel-10-for-$(uname -m)-extensions-rpms"
sudo dnf install -y rh-podman-desktop
|
If the extensions repository is not available in your subscription, fall back to Flatpak as shown in Step 17a above. |
Step 18: Launch Podman Desktop
RHEL 9 (Flatpak):
flatpak run io.podman_desktop.PodmanDesktop &
RHEL 10 (dnf):
podman-desktop &
-
Podman Desktop will detect your Podman installation automatically
-
Verify the connection shows as "Running" in the main dashboard
-
The status indicator in the bottom-left should show Podman version 5.7.1
|
If Podman Desktop doesn’t detect your Podman socket, check that |
Podman Desktop Quick Reference
Main Navigation (Left Sidebar):
-
Dashboard: Overview of running containers and resources
-
Images: Browse, pull, and manage container images
-
Containers: View and manage running/stopped containers
-
Pods: Manage groups of containers (Kubernetes-style pods)
-
Volumes: Persistent storage management
-
Extensions: Add functionality (Kind, OpenShift Local, etc.)
-
Settings: Configure registries, Podman machine, preferences
Hummingbird No-Shell Design:
Hummingbird images intentionally omit shells (/bin/sh, /bin/bash) to minimize attack surface. You cannot exec into them interactively. To debug a running Hummingbird container, use the sidecar pattern:
podman run -it --rm \
--pid=container:<container-name> \
--net=container:<container-name> \
registry.access.redhat.com/ubi9/ubi:latest \
/bin/bash
This gives you a shell with access to the target container’s PID and network namespaces while the Hummingbird container itself remains hardened.
Podman Desktop Documentation: * Official Podman Desktop Docs * Podman Desktop GitHub
Troubleshooting
Issue: Podman socket not starting
systemctl --user restart podman.socket
systemctl --user status podman.socket
journalctl --user -u podman.socket -n 50
Issue: Registry authentication failures
podman login quay.io
podman login registry.access.redhat.com
Issue: Permission errors with rootless Podman
grep "^$(whoami):" /etc/subuid /etc/subgid
loginctl terminate-user $(whoami)
# Log back in
Issue: Podman Desktop not detecting Podman
Ensure the Podman socket is active and listening:
systemctl --user status podman.socket
ls -la /run/user/$(id -u)/podman/podman.sock
Issue: Quarkus CLI not found after installation
Ensure JBang’s bin directory is on your PATH:
export PATH="$HOME/.jbang/bin:$PATH"
quarkus --version
If JBang itself isn’t installed, re-run the installation:
curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/
curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio