OpenShift Container Image Builds with Red Hat Subscription

# OpenShift Container Image Builds with Red Hat Subscription Entitlements

When OpenShift nodes are registered with an active Red Hat subscription, that entitlement is automatically inherited by builds running on those nodes — you get access to RHEL repositories "for free" inside your Dockerfiles. However, when nodes are **not** registered, carry an unsuitable subscription, or you need to target a specific entitlement regardless of node state, you must supply the credentials yourself as a build secret.

This post walks through the manual approach: downloading entitlement certificates from the Red Hat Customer Portal and wiring them into an OpenShift `BuildConfig`.

---

## Why You Might Need to Override Node Entitlements

- Nodes are unregistered (e.g. cloud-provisioned RHCOS that relies on a separate activation key)
- The node subscription does not include the repositories your image needs
- You want builds to be portable across clusters regardless of node subscription state
- CI/CD environments where node entitlements are managed separately from application builds

---

## Step 1 — Download Entitlement Keys

Log in to [https://access.redhat.com](https://access.redhat.com) and navigate to **Subscriptions → Systems** (or **Activation Keys**). Download the entitlement certificate bundle for your subscription. You will end up with a pair of PEM files that must be kept **separate**:

| File | Purpose |
|------|---------|
| `<UUID>.pem` | Public entitlement certificate |
| `<UUID>-key.pem` | Private entitlement key |

Keeping them as two distinct files is a hard requirement of the OpenShift entitled-builds mechanism — see the [official docs](https://docs.openshift.com/container-platform/4.4/builds/running-entitled-builds.html).

---

## Step 2 — Create the Entitlement Secret

Create an OpenShift `Secret` from the two PEM files. Replace the UUID with the actual filename prefix you downloaded:

```bash
oc create secret generic etc-pki-entitlement \
  --from-file /tmp/2dacb97f-7fbc-4405-ad87-4f4aab216db2.pem \
  --from-file /tmp/2dacb97f-7fbc-4405-ad87-4f4aab216db2-key.pem
```

This secret will be injected into the build pod at `/etc/pki/entitlement` so that `yum`/`dnf` can authenticate against Red Hat CDN repositories.

---

## Step 3 — Create the Initial BuildConfig

Use `oc new-build` to scaffold your `BuildConfig` using a Docker strategy pointed at your source repository. The `--allow-missing-images` flag prevents the command from failing if the base image is not yet cached locally:

```bash
oc new-build openjdk-ubi-subscribed \
  --strategy=docker \
  --code=https://gitlab.com/example/repo.git \
  --name=myimage-ocp4 \
  --to=docker-registry.example.com/myimage/ocp4:testing \
  --to-docker=true \
  --allow-missing-images
```

> **Note:** The first positional argument (`openjdk-ubi-subscribed`) is a base `ImageStream` name that will be used as the `FROM` image. Adjust this to whatever base image stream exists in your cluster.

---

## Step 4 — Edit the BuildConfig to Wire In the Secret

Run `oc edit bc/myimage-ocp4` (or `oc edit bc/openjdk-ubi-subscribed` if that is the generated name) and patch the YAML to add:

1. **The entitlement secret as a source secret** — mounted into the build pod
2. **`imageOptimizationPolicy: SkipLayers`** — recommended for entitled builds to avoid layer caching issues that can strip out the injected certificates

```yaml
spec:
  source:
    git:
      uri: https://gitlab.com/example/repo.git
    secrets:
      - destinationDir: etc-pki-entitlement
        secret:
          name: etc-pki-entitlement
  strategy:
    dockerStrategy:
      imageOptimizationPolicy: SkipLayers
```

The `destinationDir` value tells the build where to mount the secret files inside the build context, making them available to the Docker daemon as `/etc/pki/entitlement`.

---

## Step 5 — Add Registry Credentials and a Custom CA

If you are pushing to a private registry (here, `docker-registry.example.com`) or pulling from one that uses an internal CA, you need two additional secrets.

**Push credentials** (docker-registry secret):

```bash
oc create secret docker-registry priv-registry-creds \
  --docker-server=docker-registry.example.com \
  --docker-username=unused \
  --docker-password=<your-token-or-password>
```

**Internal CA bundle** (for TLS verification of the registry):

```bash
oc create secret generic rh-it-ca --from-file=ca.crt=/tmp/ca.crt
```

Then link both secrets to the `BuildConfig`:

```bash
# CA cert used when the build clones source or contacts the registry
oc set build-secret --source myimage-ocp4 rh-it-ca

# Credentials used when pushing the finished image
oc set build-secret --push myimage-ocp4 priv-registry-creds
```

---

## Step 6 — Trigger a Build and Verify

```bash
oc start-build myimage-ocp4 --follow
```

Watch the logs for `yum install` or `dnf install` calls succeeding. If they fail with `401 Unauthorized` from CDN, the entitlement PEM files are either expired or not correctly split into the two separate files. Re-download from [access.redhat.com](https://access.redhat.com) and recreate the secret.

---

## Full BuildConfig Reference (annotated)

```yaml
apiVersion: build.openshift.io/v1
kind: BuildConfig
metadata:
  name: myimage-ocp4
spec:
  source:
    git:
      uri: https://gitlab.com/example/repo.git
    secrets:
      - destinationDir: etc-pki-entitlement   # injected into build context
        secret:
          name: etc-pki-entitlement
  strategy:
    dockerStrategy:
      imageOptimizationPolicy: SkipLayers     # prevents cert stripping in layers
  output:
    to:
      kind: DockerImage
      name: docker-registry.exammple.com/myimage/ocp4:testing
    pushSecret:
      name: priv-registry-creds
```

---

## Key Takeaways

- **Node subscription = automatic**: if your RHCOS nodes are registered, builds inherit the entitlement transparently.
- **Manual override = two PEM files**: public cert (`<UUID>.pem`) and private key (`<UUID>-key.pem`) must be kept separate and loaded as a `Secret`.
- **`SkipLayers`** prevents intermediate layer caching from stripping the injected entitlement files before `yum`/`dnf` runs.
- Always pair an entitlement secret with the correct **push secret** and **CA bundle** for private registries.

## Disclaimer

This blog post was generated by AI based on some old notes of mine I found. I hope he's got things right because I have no time now to test it. But let me know if something doesn't work right.

Comments

Popular Posts