# Usar Docker Hardened Images con Red Hat OpenShift


Docker Hardened Images (DHI) se pueden desplegar en Red Hat OpenShift Container Platform, pero el modelo de seguridad de OpenShift difiere del estándar de Kubernetes de maneras que requieren una configuración específica. Debido a que OpenShift ejecuta los contenedores con un ID de usuario asignado arbitrariamente en lugar del ID por defecto de la imagen, debes ajustar la propiedad de los archivos y los permisos de grupo en tus Dockerfiles para garantizar que las rutas de escritura sigan siendo accesibles.

Esta guía explica cómo desplegar Docker Hardened Images en entornos OpenShift, cubriendo las restricciones de contexto de seguridad (Security Context Constraints o SCCs), la asignación de ID de usuario arbitrarios, los requisitos de permisos de archivos y las mejores prácticas tanto para las variantes de imágenes de desarrollo como de tiempo de ejecución.

## Cómo difiere la seguridad de OpenShift de la de Kubernetes

OpenShift extiende Kubernetes con Security Context Constraints (SCCs), las cuales controlan qué acciones puede realizar un pod y a qué recursos puede acceder. Mientras que el Kubernetes estándar utiliza los Pod Security Standards (PSS) para propósitos similares, las SCCs son más granulares y se aplican por defecto.

Las diferencias clave que afectan los despliegues de DHI son:

**ID de usuario arbitrarios.** Por defecto, OpenShift ejecuta contenedores utilizando un ID de usuario (UID) asignado arbitrariamente de un rango asignado a cada proyecto. La SCC por defecto `restricted-v2` (introducida en OpenShift 4.11) utiliza la estrategia `MustRunAsRange`, que anula la directiva `USER` en la imagen del contenedor con un UID del rango asignado al proyecto (que normalmente comienza por encima de 1000000000). Esto significa que aunque una imagen DHI especifique un usuario no root (UID 65532), OpenShift ejecutará el contenedor con un UID diferente e impredecible.

**Requisito de grupo root.** OpenShift asigna el UID arbitrario al grupo root (GID 0). El proceso del contenedor siempre se ejecuta con `gid=0(root)`. Cualquier directorio o archivo en el que el proceso necesite escribir debe pertenecer al grupo root (GID 0) con permisos de lectura/escritura de grupo. Esto se encuentra documentado en las [directrices de Red Hat para la creación de imágenes](https://docs.openshift.com/container-platform/4.14/openshift_images/create-images.html#use-uid_create-images).

> [!IMPORTANT]
> 
> Las imágenes DHI establecen la propiedad de los archivos en `nonroot:nonroot` (65532:65532) por defecto. Dado que el UID arbitrario de OpenShift NO está en el grupo `nonroot` (65532), no puede escribir en esos archivos, a pesar de que el pod sea admitido por la SCC y el contenedor se inicie. Debes cambiar la propiedad de grupo a GID 0 para cualquier ruta de escritura. Esta es la fuente más común de errores de permisos al desplegar DHI en OpenShift.

**Restricciones de capacidades.** La SCC `restricted-v2` elimina todas las capacidades de Linux por defecto y aplica `allowPrivilegeEscalation: false`, `runAsNonRoot: true` y un `seccompProfile` de tipo `RuntimeDefault`. Las imágenes de tiempo de ejecución DHI ya cumplen con estas restricciones porque se ejecutan como un usuario no root y no requieren capacidades elevadas.

## Traer imágenes DHI a OpenShift

Antes de realizar el despliegue, crea un secreto de descarga (pull secret) de imágenes para que tu clúster de OpenShift pueda autenticarse en el registro de DHI o en tu repositorio espejo en Docker Hub.

### Crear un secreto de descarga de imágenes

```console
oc create secret docker-registry dhi-pull-secret \
    --docker-server=docker.io \
    --docker-username=<your-docker-username> \
    --docker-password=<your-docker-access-token> \
    --docker-email=<your-email>
```

Si estás descargando directamente desde `dhi.io` en lugar de un repositorio espejo, establece `--docker-server=dhi.io`.

### Vincular el secreto a una cuenta de servicio

Vincula el secreto de descarga a la cuenta de servicio (service account) `default` de tu proyecto para que todos los despliegues puedan descargar imágenes DHI automáticamente:

```console
oc secrets link default dhi-pull-secret --for=pull
```

Para utilizar el secreto con una cuenta de servicio específica en su lugar:

```console
oc secrets link <service-account-name> dhi-pull-secret --for=pull
```

## Compilar imágenes compatibles con OpenShift a partir de DHI

Las imágenes de tiempo de ejecución DHI son distroless: no contienen shell, ni gestor de paquetes, ni un entorno compatible con `RUN`. Esto significa que **no puedes utilizar comandos `RUN` en la etapa de tiempo de ejecución** de tu Dockerfile. Todos los ajustes de permisos de archivos para OpenShift deben realizarse en la etapa de compilación `-dev` y los resultados deben copiarse en la etapa de tiempo de ejecución utilizando `COPY --chown`.

El patrón principal para la compatibilidad con OpenShift es:

1. Utiliza una variante DHI `-dev` como etapa de compilación (tiene una shell).
1. Compila tu aplicación y establece la propiedad de GID 0 en la etapa de compilación.
1. Copia los resultados en la imagen de tiempo de ejecución DHI utilizando `COPY --chown=<UID>:0`.

### Ejemplo: Nginx para OpenShift

```dockerfile
# Etapa de compilación: tiene una shell, puede ejecutar comandos
FROM YOUR_ORG/dhi-nginx:1.29-alpine3.23-dev AS build

# Copiar configuración personalizada y establecer propiedad del grupo root
COPY nginx.conf /tmp/nginx.conf
COPY default.conf /tmp/default.conf

# Preparar directorios de escritura con GID 0
# (Nginx necesita escribir en la caché, los logs y las ubicaciones de los archivos PID)
RUN mkdir -p /tmp/nginx-cache /tmp/nginx-run && \
    chgrp -R 0 /tmp/nginx-cache /tmp/nginx-run && \
    chmod -R g=u /tmp/nginx-cache /tmp/nginx-run

# Etapa de tiempo de ejecución: distroless, SIN shell, SIN comandos RUN
FROM YOUR_ORG/dhi-nginx:1.29-alpine3.23

COPY --from=build --chown=65532:0 /tmp/nginx.conf /etc/nginx/nginx.conf
COPY --from=build --chown=65532:0 /tmp/default.conf /etc/nginx/conf.d/default.conf
COPY --from=build --chown=65532:0 /tmp/nginx-cache /var/cache/nginx
COPY --from=build --chown=65532:0 /tmp/nginx-run /var/run
```

> [!IMPORTANT]
> 
> Utiliza siempre `--chown=<UID>:0` (usuario:grupo-root) al copiar archivos a la etapa de tiempo de ejecución. Esto garantiza que el UID arbitrario que OpenShift asigna pueda acceder a los archivos a través de la pertenencia al grupo root. Nunca utilices `RUN` en la etapa de tiempo de ejecución; las imágenes distroless DHI no tienen shell.

> [!NOTE]
> 
> El UID para las imágenes DHI varía según la imagen. La mayoría utiliza 65532 (`nonroot`), pero algunas (como la imagen de Node.js) pueden utilizar un UID diferente. Verifícalo con:
> `docker inspect dhi.io/<image>:<tag> --format '{{.Config.User}}'`

Desplegar en OpenShift:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-dhi
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-dhi
  template:
    metadata:
      labels:
        app: nginx-dhi
    spec:
      containers:
        - name: nginx
          image: YOUR_ORG/dhi-nginx:1.29-alpine3.23
          ports:
            - containerPort: 8080
          securityContext:
            allowPrivilegeEscalation: false
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
            capabilities:
              drop:
                - ALL
      imagePullSecrets:
        - name: dhi-pull-secret
```

DHI Nginx escucha en el puerto 8080 por defecto (no en el 80), lo cual es compatible con el requisito de no root. No se necesitan cambios en la SCC.

### Ejemplo: Aplicación Node.js para OpenShift

```dockerfile
# Etapa de compilación: la variante dev tiene shell y npm
FROM YOUR_ORG/dhi-node:24-alpine3.23-dev AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Establecer GID 0 en todo lo que el tiempo de ejecución necesita para escribir
RUN chgrp -R 0 /app/dist /app/node_modules && \
    chmod -R g=u /app/dist /app/node_modules

# Etapa de tiempo de ejecución: distroless, SIN shell
FROM YOUR_ORG/dhi-node:24-alpine3.23
WORKDIR /app
COPY --from=build --chown=65532:0 /app/dist ./dist
COPY --from=build --chown=65532:0 /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
```

Desplegar:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: node-app
  template:
    metadata:
      labels:
        app: node-app
    spec:
      containers:
        - name: app
          image: YOUR_ORG/dhi-node-app:latest
          ports:
            - containerPort: 3000
          securityContext:
            allowPrivilegeEscalation: false
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
            capabilities:
              drop:
                - ALL
      imagePullSecrets:
        - name: dhi-pull-secret
```

## Gestionar ID de usuario arbitrarios

La SCC `restricted-v2` de OpenShift asigna un UID aleatorio al proceso del contenedor. Este UID no existirá en `/etc/passwd` dentro de la imagen, pero el contenedor se ejecutará de todos modos; el proceso simplemente no tendrá un nombre de usuario asociado.

Esto puede causar problemas con aplicaciones que:

- Buscan el directorio de inicio o el nombre de usuario del usuario actual
- Escriben en directorios propiedad de un UID específico
- Comprueban `/etc/passwd` para el usuario en ejecución

### Añadir una entrada `passwd` para el UID arbitrario

Algunas aplicaciones (en particular aquellas que utilizan ciertas bibliotecas de Python o Java) requieren una entrada `/etc/passwd` válida para el usuario en ejecución. Puedes solucionar esto con un script de punto de entrada (entrypoint) que sirva de envoltura (wrapper).

Como este patrón requiere una shell, solo funciona con variantes DHI `-dev` o con una imagen personalizada DHI Enterprise que incluya una shell. Prepara la imagen en la etapa de compilación:

```dockerfile
FROM YOUR_ORG/dhi-python:3.13-alpine3.23-dev AS build
# ... compilar tu aplicación ...

# Hacer que /etc/passwd sea escribible por el grupo para que el punto de entrada pueda añadir información
RUN chgrp 0 /etc/passwd && chmod g=u /etc/passwd

# Crear la envoltura (wrapper) del punto de entrada
RUN printf '#!/bin/sh\n\
if ! whoami > /dev/null 2>&1; then\n\
  if [ -w /etc/passwd ]; then\n\
    echo "${USER_NAME:-appuser}:x:$(id -u):0:dynamic user:/tmp:/sbin/nologin" >> /etc/passwd\n\
  fi\n\
fi\n\
exec "$@"\n' > /entrypoint.sh && chmod +x /entrypoint.sh

# Este patrón requiere una variante -dev en tiempo de ejecución (tiene shell)
FROM YOUR_ORG/dhi-python:3.13-alpine3.23-dev
COPY --from=build --chown=65532:0 /app ./app
COPY --from=build --chown=65532:0 /entrypoint.sh /entrypoint.sh
COPY --from=build --chown=65532:0 /etc/passwd /etc/passwd
USER 65532
ENTRYPOINT ["/entrypoint.sh"]
CMD ["python", "app/main.py"]
```

> [!NOTE]
> 
> Para imágenes de tiempo de ejecución distroless (sin shell), el patrón de inyección de `passwd` no es posible. En su lugar, utiliza la SCC `nonroot` (descrita en la siguiente sección) para ejecutar el proceso con el UID incorporado de la imagen para que la entrada existente en `/etc/passwd` coincida con el proceso en ejecución. Alternativamente, OpenShift 4.x inyecta automáticamente el UID arbitrario en `/etc/passwd` en la mayoría de los casos, lo que resuelve esto para muchas aplicaciones.

## Usar la SCC nonroot para UIDs fijos

Si tu aplicación requiere ejecutarse con el UID específico definido en la imagen (normalmente 65532 para DHI), puedes utilizar la SCC `nonroot` en lugar de la `restricted-v2` por defecto. La SCC `nonroot` utiliza la estrategia `MustRunAsNonRoot`, que permite cualquier UID que no sea cero.

> [!IMPORTANT]
> 
> Para que funcione la SCC `nonroot`, la directiva `USER` de la imagen debe especificar un UID **numérico** (por ejemplo, `65532`), no una cadena de nombre de usuario como `nonroot`. OpenShift no puede verificar que un nombre de usuario se asocie a un UID distinto de cero. Verifica tu imagen DHI con:
> `docker inspect YOUR_ORG/dhi-node:24-alpine3.23 --format '{{.Config.User}}'`
> Si la salida es una cadena de texto en lugar de un número, establece `runAsUser` explícitamente en la especificación del pod (pod spec).

Crea una cuenta de servicio y concédele la SCC `nonroot`:

```console
oc create serviceaccount dhi-nonroot
oc adm policy add-scc-to-user nonroot -z dhi-nonroot
```

Haz referencia a la cuenta de servicio en tu despliegue:

```yaml
spec:
  template:
    spec:
      serviceAccountName: dhi-nonroot
      containers:
        - name: app
          image: YOUR_ORG/dhi-node:24-alpine3.23
          securityContext:
            runAsUser: 65532
            runAsNonRoot: true
            allowPrivilegeEscalation: false
            seccompProfile:
              type: RuntimeDefault
            capabilities:
              drop:
                - ALL
```

Verifica la asignación de la SCC después del despliegue:

```console
oc get pod <pod-name> -o jsonpath='{.metadata.annotations.openshift\.io/scc}'
```

Esto debería devolver `nonroot`.

Al utilizar la SCC `nonroot` con un UID fijo, el proceso se ejecuta como 65532 (coincidiendo con la propiedad de los archivos de la imagen), por lo que los ajustes de GID 0 no son estrictamente necesarios para rutas que ya pertenecen a 65532. Sin embargo, se sigue recomendando aplicar `chown <UID>:0` para la portabilidad en ambas SCCs `restricted-v2` y `nonroot`.

## Usar variantes DHI dev en OpenShift

Las variantes DHI `-dev` incluyen una shell, un gestor de paquetes y herramientas de desarrollo. Se ejecutan como root (UID 0) por defecto, lo cual entra en conflicto con la SCC `restricted-v2` de OpenShift. Existen tres enfoques:

### Opción 1: Usar variantes dev únicamente en las etapas de compilación (recomendado)

Utiliza variantes `-dev` únicamente en las etapas de compilación del Dockerfile y nunca las despliegues directamente en OpenShift:

```dockerfile
FROM YOUR_ORG/dhi-node:24-alpine3.23-dev AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Establecer la propiedad del grupo root para compatibilidad con OpenShift
RUN chgrp -R 0 /app/dist /app/node_modules && \
    chmod -R g=u /app/dist /app/node_modules

FROM YOUR_ORG/dhi-node:24-alpine3.23
WORKDIR /app
COPY --from=build --chown=65532:0 /app/dist ./dist
COPY --from=build --chown=65532:0 /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
```

La imagen final en tiempo de ejecución es no root y distroless, totalmente compatible con `restricted-v2`.

### Opción 2: Conceder la SCC `anyuid` para depuración

Si necesitas ejecutar una variante `-dev` directamente en OpenShift para depuración, concede la SCC `anyuid` a una cuenta de servicio dedicada:

```console
oc create serviceaccount dhi-debug
oc adm policy add-scc-to-user anyuid -z dhi-debug
```

Luego haz referencia a ella en tu pod:

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: dhi-debug
spec:
  serviceAccountName: dhi-debug
  containers:
    - name: debug
      image: YOUR_ORG/dhi-node:24-alpine3.23-dev
      command: ["sleep", "infinity"]
  imagePullSecrets:
    - name: dhi-pull-secret
```

> [!IMPORTANT]
> 
> La SCC `anyuid` permite la ejecución con cualquier UID, incluido root. Utiliza esto únicamente para depuración temporal; nunca en cargas de trabajo de producción.

### Opción 3: Usar `oc debug` o contenedores efímeros

Para imágenes de tiempo de ejecución distroless sin shell, utiliza herramientas de depuración nativas de OpenShift en lugar de `docker debug` (que solo funciona con Docker Engine, no con CRI-O en OpenShift).

Utiliza `oc debug` para crear una copia de un pod con una shell de depuración:

```console
# Crear un pod de depuración basado en un despliegue
oc debug deployment/nginx-dhi

# Sobrescribir la imagen para usar una variante -dev con una shell
oc debug deployment/nginx-dhi --image=YOUR_ORG/dhi-node:24-alpine3.23-dev
```

Utiliza contenedores efímeros (OpenShift 4.12+ / Kubernetes 1.25+):

```console
kubectl debug -it <pod-name> --image=YOUR_ORG/dhi-node:24-alpine3.23-dev \
    --target=app -- sh
```

Esto acopla un contenedor de depuración temporal a un pod en ejecución sin reiniciarlo, compartiendo el espacio de nombres de procesos del pod.

> [!NOTE]
> 
> `docker debug` es una característica de Docker Desktop/CLI para desarrollo local. No está disponible en clústeres de OpenShift, los cuales utilizan CRI-O como su entorno de ejecución de contenedores.

## Desplegar charts de Helm de DHI en OpenShift

DHI proporciona charts de Helm preconfigurados para aplicaciones populares. Al desplegar estos charts en OpenShift, es posible que debas ajustar la configuración del contexto de seguridad.

### Inspeccionar los valores del chart primero

Antes de realizar la instalación, comprueba qué valores de contexto de seguridad expone el chart:

```console
helm registry login dhi.io

helm show values oci://dhi.io/<chart-name> --version <version> | grep -A 20 securityContext
```

Las rutas de valores disponibles varían según el chart, así que comprueba siempre `values.yaml` antes de establecer sobrescripciones.

### Instalar con sobrescripciones para OpenShift

El siguiente ejemplo muestra un patrón de instalación típico. Ajusta las rutas de `--set` según lo que devuelva `helm show values` para tu chart específico:

```console
helm install my-release oci://dhi.io/<chart-name> \
    --version <version> \
    --set "imagePullSecrets[0].name=dhi-pull-secret" \
    -f openshift-values.yaml
```

Crea un archivo `openshift-values.yaml` con las sobrescripciones de contexto de seguridad adecuadas para tu chart:

```yaml
# Ejemplo: ajusta las claves según el resultado del comando `helm show values`
podSecurityContext:
  runAsNonRoot: true
  seccompProfile:
    type: RuntimeDefault

securityContext:
  allowPrivilegeEscalation: false
  capabilities:
    drop:
      - ALL
```

> [!NOTE]
> 
> Las rutas de valores de los charts de Helm de DHI no están estandarizadas. Por ejemplo, un chart puede utilizar `image.imagePullSecrets`, mientras que otro utiliza `global.imagePullSecrets`. Consulta siempre la documentación del chart específico o su archivo `values.yaml`.

## Verificar tu despliegue

Después de desplegar una imagen DHI en OpenShift, verifica la configuración de seguridad.

### Comprobar la SCC asignada

```console
oc get pods -o 'custom-columns=NAME:.metadata.name,SCC:.metadata.annotations.openshift\.io/scc'
```

Las imágenes DHI en tiempo de ejecución deberían mostrar `restricted-v2` (o `nonroot` si lo configuraste).

### Comprobar el UID en ejecución

```console
oc exec <pod-name> -- id
```

Con la SCC `restricted-v2`, deberías ver una salida como:

```text
uid=1000650000 gid=0(root) groups=0(root),1000650000
```

El UID pertenece al rango asignado del proyecto y el GID primario siempre es 0 (grupo root). Con la SCC `nonroot` y `runAsUser: 65532`, verías `uid=65532`.

### Confirmar que la imagen es distroless

```console
oc exec <pod-name> -- sh -c "echo hello"
```

Para imágenes DHI en tiempo de ejecución (no dev), este comando debería fallar con un error que indique que no se encontró `sh` en `$PATH`. El formato exacto del error varía según las versiones de CRI-O.

### Escanear la imagen desplegada

Utiliza Docker Scout para verificar la postura de seguridad de la imagen desplegada (ejecuta esto desde tu máquina local, no en el clúster):

```console
docker scout cves YOUR_ORG/dhi-nginx:1.29-alpine3.23
docker scout quickview YOUR_ORG/dhi-nginx:1.29-alpine3.23
```

## Problemas comunes y soluciones

**El pod falla al iniciarse con “container has runAsNonRoot and image has group or user ID set to root”.** Esto sucede al desplegar una variante DHI `-dev` con la SCC `restricted-v2` por defecto. Utiliza la variante de tiempo de ejecución en su lugar o concede la SCC `anyuid` a la cuenta de servicio.

**La aplicación no puede escribir en un directorio.** El UID arbitrario asignado por OpenShift no tiene permisos de escritura. Este es el problema más común con DHI en OpenShift. Todas las rutas de escritura deben pertenecer al GID 0 con permisos de escritura de grupo. Soluciona esto en la etapa de compilación: `chgrp -R 0 /path && chmod -R g=u /path`, luego realiza `COPY --chown=<UID>:0` a la etapa de tiempo de ejecución.

**La aplicación falla con “user not found” o “no matching entries in passwd file”.** Algunas aplicaciones requieren una entrada `/etc/passwd` válida. OpenShift 4.x inyecta automáticamente el UID arbitrario en `/etc/passwd` en la mayoría de los casos. Si tu aplicación sigue fallando, utiliza el patrón de inyección de passwd (requiere una variante `-dev`) o utiliza la SCC `nonroot` para ejecutar el proceso con el UID integrado de la imagen.

**El pod falla al vincularse al puerto 80 o 443.** Los puertos inferiores al 1024 requieren privilegios de root. Las imágenes DHI utilizan puertos sin privilegios por defecto (por ejemplo, Nginx utiliza el 8080). Configura tu Servicio de OpenShift para asociar el puerto externo al puerto sin privilegios del contenedor:

```yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-dhi
spec:
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: nginx-dhi
```

**ImagePullBackOff con “unauthorized: authentication required”.** Verifica que el secreto de descarga esté correctamente configurado y vinculado a la cuenta de servicio. Comprueba con `oc get secret dhi-pull-secret` y `oc describe sa default`.

**La compilación del Dockerfile falla con “exec: not found” en la etapa de tiempo de ejecución.** Estás utilizando `RUN` en una etapa de tiempo de ejecución distroless. Las imágenes de tiempo de ejecución DHI no tienen shell, por lo que los comandos `RUN` no se pueden ejecutar. Mueve todos los comandos `RUN` a la etapa de compilación `-dev` y utiliza `COPY --chown` para transferir los resultados.

## Resumen de compatibilidad de DHI y OpenShift

|Característica               |DHI runtime                      |DHI `-dev`          |DHI con personalización Enterprise|
|-----------------------------|---------------------------------|--------------------|---------------------------------|
|SCC por defecto (`restricted-v2`)|Sí, con permisos GID 0           |Requiere `anyuid`   |Sí, con permisos GID 0           |
|No root por defecto          |Sí (UID 65532)                  |No (root)           |Sí (UID configurable)           |
|Soporte de UID arbitrario    |Sí, con `chown <UID>:0`        |Sí                 |Sí, con `chown <UID>:0`        |
|Distroless (sin shell)        |Sí: sin `RUN` en Dockerfile     |No                  |Sí: sin `RUN` en Dockerfile     |
|Puertos sin privilegios      |Sí (superiores a 1024)                 |Configurable        |Sí (superiores a 1024)                 |
|SLSA Build Nivel 3           |Sí                              |Sí                 |Sí                              |
|Depuración en el clúster     |`oc debug` / contenedores efímeros|`oc exec` con shell|`oc debug` / contenedores efímeros|

## Siguientes pasos

- [Usar una imagen en Kubernetes](/dhi/how-to/k8s/): guía general de despliegue de DHI en Kubernetes.
- [Personalizar una imagen](/dhi/how-to/customize/): añade paquetes a las imágenes DHI utilizando la personalización Enterprise.
- [Depurar un contenedor](/dhi/troubleshoot/#general-debugging): soluciona problemas en contenedores distroless con Docker Debug (desarrollo local).
- [Gestionar SCCs](https://docs.openshift.com/container-platform/4.14/authentication/managing-security-context-constraints.html): documentación de referencia de Red Hat sobre Security Context Constraints.
- [Crear imágenes para OpenShift](https://docs.openshift.com/container-platform/4.14/openshift_images/create-images.html): directrices de Red Hat para compilar imágenes de contenedores compatibles con OpenShift.

