diff --git a/rhel-stig/Dockerfile.rhel9 b/rhel-stig/Dockerfile.rhel9 index 49163684..9364782e 100644 --- a/rhel-stig/Dockerfile.rhel9 +++ b/rhel-stig/Dockerfile.rhel9 @@ -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 \ diff --git a/rhel-stig/Dockerfile.rhel9-fips b/rhel-stig/Dockerfile.rhel9-fips index 864c99fe..6a8b3a2a 100644 --- a/rhel-stig/Dockerfile.rhel9-fips +++ b/rhel-stig/Dockerfile.rhel9-fips @@ -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/ / diff --git a/rhel-stig/README.md b/rhel-stig/README.md index a47f7af9..af551dde 100644 --- a/rhel-stig/README.md +++ b/rhel-stig/README.md @@ -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 [] [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 [] [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 diff --git a/rhel-stig/build.sh.rhel9 b/rhel-stig/build.sh.rhel9 index eddeff84..8f698a2f 100755 --- a/rhel-stig/build.sh.rhel9 +++ b/rhel-stig/build.sh.rhel9 @@ -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 diff --git a/rhel-stig/rhsm-credentials.yaml b/rhel-stig/rhsm-credentials.yaml new file mode 100644 index 00000000..74f42986 --- /dev/null +++ b/rhel-stig/rhsm-credentials.yaml @@ -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