Migrate from HTTP plug-in registry to OCI container delivery

Migrate from the deprecated HTTP plug-in registry to OCI container image delivery by switching Helm values and updating your Kubernetes secret configuration.

Before you begin

Before you begin, ensure you have:

  • Registry credentials for registry.redhat.io or your mirror registry. You can create a service account at the This content is not included.Red Hat registry service accounts page.
  • Your Helm release name and namespace
  • OpenShift CLI (oc) and Helm CLI installed
  • Existing Ansible automation portal installation with HTTP plug-in registry (tarball mode)
  • For air-gapped environments: access to your mirror registry from the OpenShift cluster

For detailed prerequisites on creating and configuring registry credentials, see Create the registry authentication secret.

About this task

The HTTP plug-in registry delivery method is deprecated and will be removed in a future release of Ansible Automation Platform. OCI container delivery is the recommended approach for new installations and production deployments.

Important:

Back up your current Helm values before you upgrade. Upgrades without -f backup-values.yaml can reset custom OAuth, RBAC, and certificate settings. The migration process exports your values, edits only the plug-in delivery method, and reapplies all custom configuration.

Procedure

  1. Export your current Helm release values:
    $ helm get values <release-name> -n <namespace> > backup-values.yaml

    Replace <release-name> with your Helm release name (for example, redhat-rhaap-portal) and <namespace> with your OpenShift namespace (for example, default).

  2. Create the auth.json file and the OCI registry authentication secret.

    The install-dynamic-plugins init container uses the authentication secret directly and does not use cluster pull secrets or imagePullSecrets. Follow these steps:

    1. Create the base64-encoded credentials. Use the -w0 flag to produce single-line output (required):
      $ AUTHB64=$(printf '%s' '<username>:<password>' | base64 -w0)

      Use your Red Hat service account username and password for registry.redhat.io, or your mirror registry credentials for air-gapped deployments.

    2. Create the auth.json file:
      $ cat > auth.json <<EOF
      {
        "auths": {
          "registry.redhat.io": {
            "auth": "${AUTHB64}"
          }
        }
      }
      EOF

      For mirror registries, replace registry.redhat.io with your mirror registry host (for example, yb-artifactory or mirror.example.com:5000).

    3. Create the Kubernetes secret. The secret name must include your Helm release name:
      $ oc create secret generic <release-name>-dynamic-plugins-registry-auth \
        --from-file=auth.json=./auth.json -n <namespace>

      For example, if your release is redhat-rhaap-portal, the secret name is redhat-rhaap-portal-dynamic-plugins-registry-auth.

    4. Verify the secret was created correctly:
      $ oc get secret <release-name>-dynamic-plugins-registry-auth \
        -o jsonpath='{.data.auth\.json}' -n <namespace> | base64 -d

      The output should display valid JSON with your credentials intact.

  3. Edit backup-values.yaml to enable OCI delivery.

    Keep all existing custom configuration (OAuth, RBAC, certificate settings, etc.). Add or modify only the plug-in delivery settings:

    redhat-developer-hub:
      global:
        pluginMode: oci
        imageTagInfo: "<plugin-version>"

    Replace <plugin-version> with the version from your current Helm release (for example, 2.2). To find the current version, run:

    $ helm get values <release-name> -n <namespace> | grep imageTagInfo
  4. Upgrade the Helm release:
    $ helm upgrade <release-name> openshift-helm-charts/redhat-rhaap-portal \
      -n <namespace> -f backup-values.yaml

    If you also need to specify a chart version, add --version <chart-version>.

  5. Verify the OCI plug-in installation by checking the init container logs.

    After the Helm upgrade completes, the pod will restart. Check the install-dynamic-plugins init container logs to confirm successful OCI pulls:

    $ oc logs <pod-name> -c install-dynamic-plugins -n <namespace>

    Successful output includes messages like:

    ======= Installing dynamic plugin oci://registry.redhat.io/ansible-automation-platform/automation-portal:<plugin-version>!ansible-backstage-plugin-catalog-backend-module-rhaap
    ...
    -> Successfully installed dynamic plugin oci://registry.redhat.io/ansible-automation-platform/automation-portal:<plugin-version>!ansible-backstage-plugin-catalog-backend-module-rhaap

    The version in the log must match your imageTagInfo value. If you see authentication errors or "No such image" messages, see Troubleshoot the migration.

  6. Optional: After you confirm the upgrade is successful, remove the deprecated plug-in registry resources:
    $ oc delete deployment,service,buildconfig,imagestream plugin-registry -n <namespace>

    This cleans up the in-cluster HTTP service that hosted the tarball files. Deletion is safe once OCI pulls are confirmed in the pod logs.

Results

You have successfully migrated from HTTP plug-in registry to OCI container delivery. Ansible automation portal now pulls plug-ins from the OCI registry instead of the deprecated tarball service.

Migrate in air-gapped and disconnected environments

For air-gapped or disconnected clusters, mirror the OCI images to your internal registry and configure the Helm chart to use your mirror.

For air-gapped or partially disconnected clusters, you must mirror the OCI images to your internal registry and configure the Helm chart to use your mirror instead of registry.redhat.io.

Mirroring Ansible plug-in images

The Ansible plug-in OCI artifacts must be mirrored to your internal registry. Mirror the images from a host with access to registry.redhat.io:

$ podman pull registry.redhat.io/ansible-automation-platform/automation-portal:<plugin-version>
$ podman tag registry.redhat.io/ansible-automation-platform/automation-portal:<plugin-version> \
  <your-mirror-registry>/ansible-automation-platform/automation-portal:<plugin-version>
$ podman push <your-mirror-registry>/ansible-automation-platform/automation-portal:<plugin-version>

When mirroring, you must preserve the original repository path. For example, mirror registry.redhat.io/ansible-automation-platform/automation-portal:2.2 to <your-mirror-registry>/ansible-automation-platform/automation-portal:2.2.

Configuring Helm values for mirror registry

Edit your backup-values.yaml to point to your mirror registry:

redhat-developer-hub:
  global:
    pluginMode: oci
    imageTagInfo: "<plugin-version>"
    imageRegistry: "<your-mirror-registry-host>"
    catalogIndex:
      image:
        registry: "<your-mirror-registry-host>"
  upstream:
    backstage:
      image:
        repository: rhdh/rhdh-hub-rhel9
        tag: "<platform-version>"
    postgresql:
      image:
        repository: rhel9/postgresql-15
        tag: "latest"

Key points:

  • imageRegistry must be the registry host only (for example, yb-artifactory or mirror.example.com:5000). Do not include a repository path.
  • catalogIndex.image.registry must be set separately — it is not auto-derived from imageRegistry. This is required for RHDH 1.9+.
  • If your mirror uses a non-standard repository path for the Ansible plug-in image, use ociPluginImage instead to specify the full path:
    redhat-developer-hub:
      global:
        imageRegistry: "<your-mirror-registry-host>"
        ociPluginImage: "<your-mirror-registry-host>/custom-path/automation-portal"

Using custom CA certificates for private registries

If your mirror registry uses a self-signed or internal CA certificate, the install-dynamic-plugins init container will fail with an x509: certificate signed by unknown authority error. You must mount your CA certificate into the init container.

The recommended approach is to create a ConfigMap and mount it at the per-registry trust path. For complete instructions, see the RHDH documentation on installing plug-ins from OCI registries by using custom certificates.

Troubleshoot the migration

Diagnose and resolve common errors during the migration from HTTP plug-in registry to OCI container delivery.

Authentication failures

Symptom: Init container logs show authentication required or unauthorized: access denied.

Cause: The <release-name>-dynamic-plugins-registry-auth secret is missing, malformed, or has incorrect credentials.

Resolution:

  1. Verify the secret exists:
    $ oc get secret <release-name>-dynamic-plugins-registry-auth -n <namespace>
  2. Check the secret contents:
    $ oc get secret <release-name>-dynamic-plugins-registry-auth \
      -o jsonpath='{.data.auth\.json}' -n <namespace> | base64 -d

    The output should be valid JSON with your credentials.

  3. Ensure the secret name matches your Helm release name exactly. For example, if your release is redhat-rhaap-portal, the secret must be redhat-rhaap-portal-dynamic-plugins-registry-auth.
  4. Recreate the secret with correct credentials if needed:
    $ oc delete secret <release-name>-dynamic-plugins-registry-auth -n <namespace>
    $ oc create secret generic <release-name>-dynamic-plugins-registry-auth \
      --from-file=auth.json=./auth.json -n <namespace>

Duplicate registry path in OCI URLs

Symptom: Init container logs or Helm values show duplicate paths, for example: oci://yb-artifactory/ansible-automation-platform/ansible-automation-platform/automation-portal:2.2.

Cause: The imageRegistry value includes a repository path instead of being the registry host only.

Resolution: Edit your backup-values.yaml and set imageRegistry to the registry host only, without the repository path:

# Incorrect (includes repository path):
imageRegistry: "yb-artifactory/ansible-automation-platform"

# Correct (host only):
imageRegistry: "yb-artifactory"

Then re-run helm upgrade with the corrected values file.

x509 certificate errors for private registries

Symptom: Init container logs show x509: certificate signed by unknown authority or x509: certificate has expired.

Cause: Your mirror registry uses a self-signed or internal CA certificate that the skopeo utility cannot verify.

Resolution: Mount your CA certificate into the init container at the per-registry trust path. Obtain your CA certificate bundle (including the full chain), create a ConfigMap, and update your Helm values to mount it. For detailed instructions, see the RHDH documentation: Content from redhat-developer.github.io is not included.Install plugins from OCI registries by using custom certificates.

No such image error

Symptom: Init container logs show Error: no such image or manifest not found.

Cause: The OCI image does not exist in the specified registry, or the imageTagInfo version does not match what is available.

Resolution:

  1. Verify the imageTagInfo value in your Helm release matches an available version. Check the This content is not included.Ansible automation portal lifecycle page.
  2. If using a mirror registry, ensure the image was mirrored to the correct path. Run:
    $ podman search <your-mirror-registry>/ansible-automation-platform/automation-portal
  3. Confirm that imageRegistry is set correctly and does not include a duplicate repository path (see the Duplicate registry path section above).

Integrity check errors

Symptom: Init container logs show integrity check failed or digest mismatch.

Cause: The OCI image in your registry does not match the expected digest, or the image was corrupted during mirroring.

Resolution:

  1. Re-mirror the image from registry.redhat.io using skopeo copy instead of podman tag/push. The skopeo copy command preserves the original manifest digest:
    $ skopeo copy \
      docker://registry.redhat.io/ansible-automation-platform/automation-portal:<plugin-version> \
      docker://<your-mirror-registry>/ansible-automation-platform/automation-portal:<plugin-version>
  2. If the error persists, verify the image in your mirror registry:
    $ skopeo inspect docker://<your-mirror-registry>/ansible-automation-platform/automation-portal:<plugin-version>
  3. Ensure you are not using a stale local image cache. Delete and re-pull if needed.

Accessing init container logs

To view the logs of the install-dynamic-plugins init container:

$ oc get pods -n <namespace> -l app.kubernetes.io/component=backstage
$ oc logs <pod-name> -c install-dynamic-plugins -n <namespace>

If the pod has already completed (e.g., if the init container succeeded), you can view the previous logs:

$ oc logs <pod-name> -c install-dynamic-plugins --previous -n <namespace>

If the pod is still running, stream logs in real time:

$ oc logs -f <pod-name> -c install-dynamic-plugins -n <namespace>