Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions rhel-stig/Dockerfile.rhel9
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
FROM quay.io/kairos/kairos-init:v0.8.5 AS kairos-init
FROM registry.access.redhat.com/ubi9-init:9.4-6

ARG USERNAME
ARG PASSWORD
ARG KAIROS_VERSION=v4.0.3

RUN dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm -y
# subscription-manager runs inside the UBI container (host OS does not need to be RHEL). Remove rhsm-host so it does not try to use host entitlements.
# Uses BuildKit secrets (--secret id=rhsm_username,src=... --secret id=rhsm_password,src=...) - credentials never stored in image
RUN --mount=type=secret,id=rhsm_username \
--mount=type=secret,id=rhsm_password \
sh -c 'rm /etc/rhsm-host && subscription-manager register --username "$(cat /run/secrets/rhsm_username)" --password "$(cat /run/secrets/rhsm_password)" \
&& yum repolist \
&& subscription-manager attach --auto \
&& subscription-manager repos --enable rhel-9-for-x86_64-appstream-rpms \
&& yum repolist'
# Credentials come from a BuildKit secret (never in image layers, build args, or docker history).
# The YAML file is parsed with sed — no python3 required.
RUN --mount=type=secret,id=rhsm-credentials \
set -e; \
_c=/run/secrets/rhsm-credentials; \
_u=$(sed -n 's/^username:[[:space:]]*"\([^"]*\)".*/\1/p; s/^username:[[:space:]]*'"'"'\([^'"'"']*\)'"'"'.*/\1/p; s/^username:[[:space:]]*\([^"'"'"'#[:space:]][^#[:space:]]*\).*/\1/p' "$_c" | head -1); \
_p=$(sed -n 's/^password:[[:space:]]*"\([^"]*\)".*/\1/p; s/^password:[[:space:]]*'"'"'\([^'"'"']*\)'"'"'.*/\1/p; s/^password:[[:space:]]*\([^"'"'"'#[:space:]][^#[:space:]]*\).*/\1/p' "$_c" | head -1); \
[ -n "$_u" ] || { echo "ERROR: could not parse 'username' from rhsm-credentials.yaml" >&2; exit 1; }; \
[ -n "$_p" ] || { echo "ERROR: could not parse 'password' from rhsm-credentials.yaml" >&2; exit 1; }; \
rm -f /etc/rhsm-host; \
subscription-manager register --username "$_u" --password "$_p" \
&& yum repolist \
&& subscription-manager attach --auto \
&& subscription-manager repos --enable rhel-9-for-x86_64-appstream-rpms \
&& yum repolist

# Let Kairos install packages first (provides network config, luet packages, etc.)
RUN --mount=type=bind,from=kairos-init,src=/kairos-init,dst=/kairos-init \
Expand Down
29 changes: 15 additions & 14 deletions rhel-stig/Dockerfile.rhel9-fips
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
FROM quay.io/kairos/kairos-init:v0.8.5 AS kairos-init
FROM registry.access.redhat.com/ubi9-init:9.4-6

ARG USERNAME
ARG PASSWORD
ARG KAIROS_VERSION=v4.0.3

# Don't get asked while running apt commands
ENV DEBIAN_FRONTEND=noninteractive

RUN dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm -y
# subscription-manager runs inside the UBI container (host OS does not need to be RHEL). Remove rhsm-host so it does not try to use host entitlements.
# Uses BuildKit secrets (--secret id=rhsm_username,src=... --secret id=rhsm_password,src=...) - credentials never stored in image
RUN --mount=type=secret,id=rhsm_username \
--mount=type=secret,id=rhsm_password \
sh -c 'rm /etc/rhsm-host && subscription-manager register --username "$(cat /run/secrets/rhsm_username)" --password "$(cat /run/secrets/rhsm_password)" \
&& yum repolist \
&& subscription-manager attach --auto \
&& subscription-manager repos --enable rhel-9-for-x86_64-appstream-rpms \
&& yum repolist'
# Credentials come from a BuildKit secret (never in image layers, build args, or docker history).
# The YAML file is parsed with sed — no python3 required.
RUN --mount=type=secret,id=rhsm-credentials \
set -e; \
_c=/run/secrets/rhsm-credentials; \
_u=$(sed -n 's/^username:[[:space:]]*"\([^"]*\)".*/\1/p; s/^username:[[:space:]]*'"'"'\([^'"'"']*\)'"'"'.*/\1/p; s/^username:[[:space:]]*\([^"'"'"'#[:space:]][^#[:space:]]*\).*/\1/p' "$_c" | head -1); \
_p=$(sed -n 's/^password:[[:space:]]*"\([^"]*\)".*/\1/p; s/^password:[[:space:]]*'"'"'\([^'"'"']*\)'"'"'.*/\1/p; s/^password:[[:space:]]*\([^"'"'"'#[:space:]][^#[:space:]]*\).*/\1/p' "$_c" | head -1); \
[ -n "$_u" ] || { echo "ERROR: could not parse 'username' from rhsm-credentials.yaml" >&2; exit 1; }; \
[ -n "$_p" ] || { echo "ERROR: could not parse 'password' from rhsm-credentials.yaml" >&2; exit 1; }; \
rm -f /etc/rhsm-host; \
subscription-manager register --username "$_u" --password "$_p" \
&& yum repolist \
&& subscription-manager attach --auto \
&& subscription-manager repos --enable rhel-9-for-x86_64-appstream-rpms \
&& yum repolist
RUN echo "install_weak_deps=False" >> /etc/dnf/dnf.conf

COPY overlay/rhel9/ /
Expand Down
32 changes: 26 additions & 6 deletions rhel-stig/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,55 @@ RHEL 9 STIG (Security Technical Implementation Guide) compliance is required for

### Prerequisites

- Red Hat subscription credentials (username and password)
- Red Hat subscription credentials (username and password), stored in a **YAML file** (not on the shell — avoids history and process listings)
- Docker installed and running (BuildKit enabled; the build script sets `DOCKER_BUILDKIT=1`)
- Access to Red Hat repositories (RHEL 9 packages required)

**Building on non-RHEL hosts (Ubuntu, etc.):** subscription-manager runs inside the UBI container, so the host OS does not need to be RHEL. The build works on any Docker host.

### RHSM credentials file

Same idea as `ubuntu-fips/*/pro-attach-config.yaml`: edit `rhel-stig/rhsm-credentials.yaml` in the repo (placeholders until you set real values). Restrict permissions on the machine where you build:

```bash
cd rhel-stig
# Edit username / password in rhsm-credentials.yaml, then:
chmod 600 rhsm-credentials.yaml
```

Do not commit real RHSM credentials; only placeholder values belong in version control.

| Environment variable | Default | Meaning |
| -------------------- | ------- | ------- |
| `RHSM_CREDENTIALS_FILE` | `rhel-stig/rhsm-credentials.yaml` next to `build.sh.rhel9` | Path to YAML with `username` and `password` keys |

### Building Non-FIPS STIG Image

```bash
bash build.sh.rhel9 <username> <password> [<base image name>] [false]
bash build.sh.rhel9 [BASE_IMAGE] [false]
```

Example:

```bash
bash build.sh.rhel9 myuser@example.com mypassword rhel9-byoi-stig false
cd rhel-stig
bash build.sh.rhel9 rhel9-byoi-stig false
```

### Building FIPS STIG Image

```bash
bash build.sh.rhel9 <username> <password> [<base image name>] [true]
bash build.sh.rhel9 [BASE_IMAGE] [true]
```

Example:

```bash
bash build.sh.rhel9 myuser@example.com mypassword rhel9-byoi-stig-fips true
cd rhel-stig
bash build.sh.rhel9 rhel9-byoi-stig-fips true
```

**Note**: Red Hat subscription credentials are required to build these images as RHEL 9 STIG packages are only available through Red Hat repositories. Credentials are passed via Docker BuildKit secrets (not build args) and are never stored in image layers. Requires Docker BuildKit (default in Docker 23+; set `DOCKER_BUILDKIT=1` for older versions).
**Note**: Red Hat subscription credentials are required to build these images as RHEL 9 STIG packages are only available through Red Hat repositories. The whole YAML file is passed to Docker as a BuildKit secret (same pattern as `ubuntu-fips/pro-attach-config.yaml`) — credentials are parsed inside the Dockerfile with `sed` and never appear in image layers, build args, or `docker history`. Requires Docker BuildKit (default in Docker 23+; set `DOCKER_BUILDKIT=1` for older versions).

## Using the Base Image

Expand Down
56 changes: 41 additions & 15 deletions rhel-stig/build.sh.rhel9
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,53 @@

# Run from rhel-stig/ so static/ and stig-remediate.sh are in build context
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
cd "$SCRIPT_DIR" || exit 1

USERNAME=$1
PASSWORD=$2
BASE_IMAGE="${3:-rhel9-byoi-stig}"
FIPS_ENABLED="${4:-false}"
usage() {
echo "Usage: bash build.sh.rhel9 [BASE_IMAGE] [FIPS_ENABLED]" >&2
echo "" >&2
echo " Credentials are read from a YAML file (not from argv — avoids shell history)." >&2
echo " Set RHSM_CREDENTIALS_FILE or edit ./rhsm-credentials.yaml next to this script." >&2
echo "" >&2
echo " BASE_IMAGE default: rhel9-byoi-stig" >&2
echo " FIPS_ENABLED true | false (default: false)" >&2
exit 1
}

# BuildKit required for --secret (credentials never stored in image layers)
export DOCKER_BUILDKIT=1
if [ "$#" -gt 2 ]; then
usage
fi

BASE_IMAGE="${1:-rhel9-byoi-stig}"
FIPS_ENABLED="${2:-false}"

if [ "$FIPS_ENABLED" != "true" ] && [ "$FIPS_ENABLED" != "false" ]; then
echo "error: FIPS_ENABLED (2nd argument) must be true or false, got: $FIPS_ENABLED" >&2
echo "note: Username/password on the command line is no longer supported; use rhsm-credentials.yaml" >&2
exit 1
fi

# Use BuildKit secrets - credentials passed via temp files, never in image layers or build args
tmpdir=$(mktemp -d)
trap "rm -rf $tmpdir" EXIT
echo -n "$USERNAME" > "$tmpdir/rhsm_username"
echo -n "$PASSWORD" > "$tmpdir/rhsm_password"
chmod 600 "$tmpdir"/*
CRED_FILE="${RHSM_CREDENTIALS_FILE:-$SCRIPT_DIR/rhsm-credentials.yaml}"
if [ ! -f "$CRED_FILE" ]; then
echo "error: RHSM credentials file not found: $CRED_FILE" >&2
echo " Create or fix $CRED_FILE (see rhsm-credentials.yaml) or set RHSM_CREDENTIALS_FILE" >&2
exit 1
fi

if grep -q 'REPLACE_' "$CRED_FILE"; then
echo "error: $CRED_FILE still contains placeholder values; edit the file with real credentials" >&2
exit 1
fi

# BuildKit required for --secret (credentials never stored in image layers or build args).
# The whole YAML file is passed as a single secret — same pattern as ubuntu-fips/pro-attach-config.yaml.
# Parsing happens inside the Dockerfile with sed, so python3 is not required here.
export DOCKER_BUILDKIT=1

if [ "$FIPS_ENABLED" = "true" ]; then
echo "Building RHEL 9 STIG FIPS image..."
docker build --secret id=rhsm_username,src="$tmpdir/rhsm_username" --secret id=rhsm_password,src="$tmpdir/rhsm_password" -t "$BASE_IMAGE" -f Dockerfile.rhel9-fips .
docker build --secret id=rhsm-credentials,src="$CRED_FILE" -t "$BASE_IMAGE" -f Dockerfile.rhel9-fips .
else
echo "Building RHEL 9 STIG image..."
docker build --secret id=rhsm_username,src="$tmpdir/rhsm_username" --secret id=rhsm_password,src="$tmpdir/rhsm_password" -t "$BASE_IMAGE" -f Dockerfile.rhel9 .
docker build --secret id=rhsm-credentials,src="$CRED_FILE" -t "$BASE_IMAGE" -f Dockerfile.rhel9 .
fi
8 changes: 8 additions & 0 deletions rhel-stig/rhsm-credentials.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Red Hat subscription-manager credentials (same as access.redhat.com).
# Replace placeholders before building — same pattern as ubuntu-fips/*/pro-attach-config.yaml.
# Do not commit real credentials; keep file mode restrictive: chmod 600 rhsm-credentials.yaml
#
# Build from rhel-stig/: bash build.sh.rhel9

username: "REPLACE_WITH_RHSM_USERNAME" # TODO: Set this to your RHSM username
password: "REPLACE_WITH_RHSM_PASSWORD" # TODO: Set this to your RHSM password