Migra de OpenShift a GKE Enterprise: migra las restricciones del contexto de seguridad de OpenShift a GKE Enterprise

Last reviewed 2022-01-24 UTC

Con este documento, podrás planificar la migración de políticas de seguridad desde las restricciones del contexto de seguridad (SCC) de OpenShift definidas en un clúster de OpenShift de origen a un clúster de GKE de destino. La implementación usa las restricciones del Controlador de políticas para definir las políticas migradas en el clúster de destino.

En el documento, se supone que estás familiarizado con Migra contenedores a Google Cloud: migra de OpenShift a GKE Enterprise. Se supone que estás familiarizado con OpenShift y las restricciones del contexto de seguridad y que tienes acceso a un clúster de OpenShift de origen y un clúster de GKE de destino.

Este documento pertenece a una serie de varias partes sobre la migración a Google Cloud. Para obtener una descripción general de la serie, consulta Migración a Google Cloud: Elige la ruta de migración.

Este documento es parte de una serie en la que se analiza la migración de contenedores a Google Cloud:

Este documento es útil si planeas migrar SCC de OpenShift a GKE Enterprise. Este documento también es útil si estás evaluando la posibilidad de migrar y deseas explorar cómo podría ser.

Este documento se basa en los conceptos que se describen en Migración a Google Cloud: Comienza ahora, Migra contenedores a Google Cloud: migra Kubernetes a GKE, Migra contenedores a Google Cloud: migra de OpenShift a GKE y Prácticas recomendadas para herramientas de redes de GKE. Incluye vínculos a los documentos cuando corresponda.

SCC de OpenShift

Las SCC son recursos específicos de OpenShift que se usan para definir políticas en Pods que especifican las acciones que un Pod puede realizar y a qué recursos puede acceder en los nodos. Cuando realizas una solicitud a la API para crear un Pod, las SCC evalúan las solicitudes de Pods en términos de privilegios de proceso frente a un conjunto de políticas que se definen a través de SCC. Las SCC evalúan las solicitudes para permitir o no la ejecución de los Pods según las políticas configuradas. Para obtener más información sobre las SCC de OpenShift, consulta Administra restricciones del contexto de seguridad.

SCC predeterminadas de OpenShift

Los clústeres 4.x de OpenShift contienen un conjunto de SCC predeterminadas que se describen en la entrada de blog Administra SCC en OpenShift de Red Hat.

Sincronización de configuración y Policy Controller

En esta sección, se describe el Sincronizador de configuración y el Controlador de políticas. Además, se proporcionan vínculos a la documentación relevante y orientación para configurar Policy Controller para que realice las tareas de migración que se describen más adelante en este documento.

Sincronizador de configuración

El Sincronizador de configuración te permite usar un repositorio común que cumpla con Git para definir de forma centralizada la configuración de cualquier recurso que se aplique a cualquier clúster de Kubernetes administrado por GKE Enterprise. Aplica esa configuración a varios clústeres.

Policy Controller

Policy Controller es un controlador de admisión dinámico de Kubernetes que verifica, audita y aplica el cumplimiento de tus clústeres con políticas definidas de forma central. Policy Controller se basa en el proyecto de código abierto Open Policy Agent (OPA) Gatekeeper.

Configuración del Sincronizador de configuración y el Policy Controller

Para prepararte para implementar las políticas de seguridad que duplican las SCC de OpenShift, habilita los componentes del Sincronizador de configuración y de Policy Controller para cada uno de los clústeres de destino. En esta sección, se describe cómo configurar estos componentes. En la sección Migra las SCC de OpenShift que aparece más adelante en este documento, se describe cómo usar las plantillas de restricciones del Controlador de políticas para implementar las políticas de seguridad.

Cuando configuras el Controlador de políticas, se recomienda colocar los espacios de nombres relacionados con el sistema que no ejecuten los Pods de la aplicación en el campo Espacios de nombres exentos. Eximir los espacios de nombres relacionados con el sistema te ayuda a evitar el riesgo de bloquear cualquier Pod del sistema que requiera privilegios elevados. Los espacios de nombres relacionados con el sistema en un clúster de GKE pueden incluir lo siguiente:

  • kube-system
  • kube-public
  • gke-connect
  • gke-system
  • config-management-system
  • config-management-monitoring
  • gatekeeper-system
  • istio-system
  • cnrm-system
  • knative-serving
  • monitoring-system

Después de configurar Policy Controller con las excepciones anteriores, agrega la etiqueta admission.gatekeeper.sh/ignore=true a cada espacio de nombres para excluir los espacios de nombres de la aplicación de restricciones. Si no agregas la etiqueta a cada espacio de nombres, los Pods del sistema (y, por lo tanto, todo tu clúster) pueden verse afectados por políticas restringidas.

Migra las SCC de OpenShift a las restricciones de Policy Controller

En esta sección, se describe cómo puedes exportar las SCC desde tu clúster de OpenShift y configurar las restricciones del Policy Controller de GKE Enterprise de destino para que coincidan con las políticas obligatorias. En esta sección, también se describen algunas diferencias entre las SCC y las restricciones de Policy Controller para que puedas planificar la migración según corresponda.

Evalúa las SCC de OpenShift

Para exportar una lista y configuración de las SCC que se instalan en tu clúster de OpenShift, puedes usar los siguientes comandos:

  1. Obtén una lista de todas las SCC:

    oc get scc
    
  2. Exporta la configuración de cada SCC:

    oc get scc SCC_NAME > SCC_NAME.yaml
    

    Reemplaza SCC_NAME por el nombre de la SCC para la que deseas exportar la configuración.

Después de exportar la configuración, puedes analizarla y usar la tabla en la siguiente sección Asigna las SCC de OpenShift para configurar las restricciones del Controlador de políticas que coincidan con los requisitos de seguridad de tu aplicación.

Asigna las SCC de OpenShift a las plantillas de restricciones del Controlador de políticas

En la siguiente tabla, se proporcionan las restricciones y la configuración del Controlador de políticas que corresponden a los campos de SCC de OpenShift y sus posibles valores. Usa la tabla para configurar las restricciones del Controlador de políticas de destino que coinciden con los requisitos de seguridad para aplicaciones que se implementaron a través de las SCC de OpenShift en el entorno de origen. En la sección Ejemplo de migración de extremo a extremo de este documento, se proporciona un ejemplo de cómo usar la información de la tabla.

Campo de SCC de OpenShift Tipo/valores posibles Plantilla de restricciones de Policy Controller Especificación de restricciones de Policy Controller
allowPrivilegedContainer: Booleano K8sPSPPrivilegedContainer Evita los contenedores privilegiados si se aplican.
allowHostIPC: Booleano K8sPSPHostNamespace Impide el acceso al espacio de nombres pid y ipc del host si se aplica.
allowHostPID: Booleano K8sPSPHostNamespace Impide el acceso al espacio de nombres pid y ipc del host si se aplica.
allowHostNetwork: Booleano K8sPSPHostNetworkingPorts Tiene un parámetro booleano a fin de evitar el acceso a la red de host y puede definir un rango para los puertos de host accesibles.
allowHostPorts: Booleano K8sPSPHostNetworkingPorts Tiene un parámetro booleano a fin de evitar el acceso a la red de host y puede definir un rango para los puertos de host accesibles.
readOnlyRootFilesystem: Booleano K8sPSPReadOnlyRootFilesystem Te permite activar el sistema de archivos raíz de contenedor como de solo lectura si se aplica.
allowPrivilegeEscalation: true Booleano K8sPSPAllowPrivilegeEscalationContainer Evita que los Pods con el contexto de seguridad AllowPrivilegeEscalation se establezcan como verdaderos si se aplican.
allowHostDirVolumePlugin: Booleano K8sPSPVolumeTypes Tiene un parámetro para definir una lista de tipos de volúmenes permitidos (como en las SCC) incluido el directorio de host.
volumes: Lista de arrays con el tipo de volúmenes permitidos K8sPSPVolumeTypes Tiene un parámetro para definir una lista de tipos de volúmenes permitidos (como en las SCC) incluido el directorio de host.
allowedCapabilities: Lista de arrays de capacidades de Linux que se pueden solicitar. K8sPSPCapabilities Tiene parámetros para definir las capacidades de Linux que se pueden solicitar (allowedCapabilities) y que están prohibidas (requiredDropCapabilites).

No se puede usar para agregar ni descartar directamente las capacidades enumeradas, como se puede hacer en defaultAddCapabilities: y requiredDropCapabilities: en las SCC de OpenShift.

defaultAddCapabilities: Lista de arrays de capacidades de Linux que se deben agregar a cada contenedor. K8sPSPCapabilities Tiene parámetros para definir las capacidades de Linux que se pueden solicitar (allowedCapabilities) y que están prohibidas (requiredDropCapabilites).

No se puede usar para agregar ni descartar directamente las capacidades enumeradas, como se puede hacer en defaultAddCapabilities: y requiredDropCapabilities: en las SCC de OpenShift.

requiredDropCapabilities: Lista de arrays de capacidades de Linux que se descartan de forma automática del Pod o contenedor. K8sPSPCapabilities Tiene parámetros para definir las capacidades de Linux que se pueden solicitar (allowedCapabilities) y que están prohibidas (requiredDropCapabilites).

No se puede usar para agregar ni descartar directamente las capacidades enumeradas, como se puede hacer en defaultAddCapabilities: y requiredDropCapabilities: en las SCC de OpenShift.

fsGroup: Tiene una type: key que puede ser una de las siguientes opciones:
  • MustRunAs: Requiere que se especifique al menos un rango si no se usan valores asignados con anterioridad.
  • RunAsAny: Permite especificar cualquier ID de fsGroup.
K8sPSPAllowedUsers Te permite definir reglas que tengan una función similar a type: key en SCC y en los rangos id para runAsUser, runAsGroup, supplementalGroups y parámetros fsGroup.

Se puede usar a fin de definir rangos permitidos para usuarios, grupos, grupos complementarios o grupos de FS, pero no para configurar el ID de usuario directamente en el Pod, como se puede hacer en las SCC de OpenShift.

runAsUser: Tiene una type: key que puede ser una de las siguientes opciones:
  • MustRunAs: Requiere que se configure un runAsUser.
  • MustRunAsRange: Requiere que se definan valores mínimos y máximos si no se usan valores asignados con anterioridad desde el espacio de nombres.
  • MustRunAsNonRoot: Requiere que el Pod se envíe con un runAsUser que no sea cero o que la directiva USER se defina en la imagen.
  • RunAsAny: Permite especificar cualquier runAsUser.
K8sPSPAllowedUsers Te permite definir reglas que tengan una función similar a type: key en SCC y en los rangos id para runAsUser, runAsGroup, supplementalGroups y parámetros fsGroup.

Se puede usar a fin de definir rangos permitidos para usuarios, grupos, grupos complementarios o grupos de FS, pero no para configurar el ID de usuario directamente en el Pod, como se puede hacer en las SCC de OpenShift.

supplementalGroups: Tiene una type: key que puede ser una de las siguientes opciones:
  • MustRunAs: Requiere que se especifique al menos un rango si no se usan valores asignados con anterioridad desde el espacio de nombres.
  • RunAsAny: Permite especificar cualquier supplementalGroups.
K8sPSPAllowedUsers Te permite definir reglas que tengan una función similar a type: key en SCC y en los rangos id para runAsUser, runAsGroup, supplementalGroups y parámetros fsGroup.

Se puede usar a fin de definir rangos permitidos para usuarios, grupos, grupos complementarios o grupos de FS, pero no para configurar el ID de usuario directamente en el Pod, como se puede hacer en las SCC de OpenShift.

seLinuxContext: Tiene una type: key que puede ser una de las siguientes opciones:
  • MustRunAs: Se requiere que seLinuxOptions se configure si no se usan valores asignados con anterioridad desde el espacio de nombres.
  • RunAsAny: Permite especificar cualquier seLinuxOptions.
K8sPSPSELinuxV2 Tiene un parámetro allowedSELinuxOptions en el que puedes establecer el nivel, el rol, el tipo y el usuario seLinuxOptions permitidos.

Diferencias entre las SCC de OpenShift y las restricciones del Controlador de políticas

En esta sección, se describen algunas diferencias entre las restricciones del Controlador de políticas y las SCC de OpenShift. Ten en cuenta estas diferencias antes de usar la tabla anterior para implementar restricciones en el entorno de destino.

Cómo se aplican las restricciones a los recursos

Puedes asignar las SCC de OpenShift a los usuarios y grupos mediante la especificación users: o group: que está presente en el objeto SCC. Con OpenShift 4.x y versiones posteriores, también puedes asignar las SCC a los usuarios o grupos mediante el control de acceso basado en roles (RBAC). Las SCC también tienen un campo priority: que se usa para ordenar las SCC que se aplican a un Pod.

Las restricciones de Policy Controller se aplican a los clústeres, los espacios de nombres o los Pods de destino que usan selectores de recursos específicos en la restricción, en lugar de segmentarse al usuario o cuenta de servicio. Para obtener más información, consulta la documentación de Policy Controller. El uso de selectores de recursos específicos ayuda a garantizar que el Pod se comporte de la misma manera, ya sea que un usuario de bajo privilegio lo ejecute con una herramienta de implementación o que un administrador de clúster lo inicie desde la línea de comandos.

Las restricciones del Controlador de políticas también admiten un modo de ejecución de prueba, que te permite probar políticas y auditar incumplimientos antes de la aplicación real. El uso de este modo te ayuda a evitar el impacto en las cargas de trabajo existentes, mientras que las SCC siempre se aplican si corresponde al usuario.

Mutación del Pod de SCC con valores asignados previamente en espacios de nombres de OpenShift

En las SCC de OpenShift, puedes modificar el contexto de seguridad relacionado de cada Pod al que se aplica la SCC con un ID específico de un rango asignado previamente que proporcionan las anotaciones en los espacios de nombres. Para ello, usa los campos RunAsUser, fsGroup, supplementalGroups y seLinuxContext con un tipo de estrategia MustRunAs o MustRunAsRange.

Por ejemplo, considera una SCC restricted que tiene un campo RunAsUser con un tipo de estrategia MustRunAsRange sin rango definido en la SCC. En este caso, cada Pod al que se aplica la SCC obtiene un ID RunAsUser del rango especificado en la anotación openshift.io/sa.scc.uid-range en el espacio de nombres del Pod.

Las restricciones de Policy Controller junto con las funciones de mutación proporcionan validación y mutación de Pods. Sin embargo, las restricciones no usan anotaciones en los espacios de nombres a fin de proporcionar valores para los contextos de seguridad de Pods. En la siguiente sección, Ejemplo de migración de extremo a extremo, se proporciona un ejemplo de cómo los equipos de entrega de aplicaciones deben configurar de forma explícita los contextos de seguridad en los Pods para que cumplan con las restricciones similares a las que se mencionaron antes.

Ejemplo de migración de extremo a extremo

En esta sección, se proporciona un archivo de manifiesto de destino de ejemplo que incluye todas las restricciones y los mutadores de políticas de Policy Controller que necesitas para asignar las siguientes SCC predeterminadas de OpenShift en tu clúster de GKE de destino:

  • privileged
  • anyuid
  • nonroot
  • restricted

Según el espacio de nombres en el que se ejecuta un Pod, este obtiene diferentes restricciones de Policy Controller cuando asignas las políticas SCC que se definen en un entorno de OpenShift de origen:

  • Las cargas de trabajo que necesitan el acceso con más privilegios, como la capacidad de ejecutarse en modo privilegiado o acceder a cualquier recurso de host, deben ejecutarse en uno de los espacios de nombres exentos que se definen en la configuración de Policy Controller.

    No se aplican restricciones a los espacios de nombres exentos. Las cargas de trabajo que tienen este acceso con privilegios más altos suelen ser componentes del sistema o cualquier carga de trabajo a la que se haya aplicado la SCC privilegiada en el entorno de origen de OpenShift.

  • Todos los Pods que se crean en cualquier espacio de nombres no exento tienen las restricciones más limitantes. Estas restricciones deniegan el acceso a todas las funciones de host y requieren que los Pods se ejecuten con un UID que sea parte de un rango específico. Esta configuración coincide con las políticas que aplican las SCC restricted de OpenShift. Las excepciones a esta configuración incluyen las siguientes:

    • Los Pods que se crean en un espacio de nombres y que tienen la etiqueta security=anyuid obtienen las restricciones limitantes anteriores, pero se pueden ejecutar con cualquier UID y cualquier GID. Esto coincide con las restricciones de la SCC anyuid en OpenShift.
    • Los Pods que se crean en un espacio de nombres que tiene la etiqueta security=nonroot obtienen las restricciones limitantes anteriores. Sin embargo, los Pods pueden ejecutarse con cualquier UID no raíz. Esto coincide con las restricciones de la SCC nonroot en OpenShift.

Ejemplo de manifiesto de destino

El siguiente es un ejemplo de un solo manifiesto que incluye un conjunto de restricciones y mutadores del Controlador de políticas que coinciden con el comportamiento descrito en el ejemplo de migración de extremo a extremo anterior. Te recomendamos que revises y ajustes las restricciones o su alcance en este ejemplo según las necesidades de tu organización.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNamespace
metadata:
  name: psp-host-namespace
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNetworkingPorts
metadata:
  name: psp-host-network-ports
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    hostNetwork: false
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: psp-privileged-container
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
---
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: restricted-capabilities
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    scope: Namespaced
    kinds:
    - apiGroups: ["*"]
      kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: NotIn
          key: security
          values: ["anyuid"]
  location: "spec.containers[name:*].securityContext.capabilities.drop"
  parameters:
    assign:
      value: ["KILL","MKNOD","SYS_CHROOT"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPCapabilities
metadata:
  name: restricted-capabilities
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: NotIn
          key: security
          values: ["anyuid"]
  parameters:
    requiredDropCapabilities: ["KILL","MKNOD","SYS_CHROOT"]
---
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: anyuid-capabilities
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    scope: Namespaced
    kinds:
    - apiGroups: ["*"]
      kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: In
          key: security
          values: ["anyuid"]
  location: "spec.containers[name:*].securityContext.capabilities.drop"
  parameters:
    assign:
      value: ["MKNOD"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPCapabilities
metadata:
  name: anyuid-capabilities
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: In
          key: security
          values: ["anyuid"]
  parameters:
    requiredDropCapabilities: ["MKNOD"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPAllowedUsers
metadata:
  name: restricted-users-and-groups
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: NotIn
          key: security
          values: ["anyuid","nonroot"]
  parameters:
    runAsUser:
      rule: MustRunAs # MustRunAsNonRoot # RunAsAny
      ranges:
        - min: 1000
          max: 2000
    fsGroup:
      rule: MustRunAs # MayRunAs # RunAsAny
      ranges:
        - min: 1000
          max: 2000
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPAllowedUsers
metadata:
  name: nonroot-users-and-groups
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: In
          key: security
          values: ["nonroot"]
  parameters:
    runAsUser:
      rule: MustRunAsNonRoot
    fsGroup:
      rule: MustRunAsNonRoot
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPVolumeTypes
metadata:
  name: psp-volume-types
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    volumes:
      - configMap
      - downwardAPI
      - emptyDir
      - nfs
      - persistentVolumeClaim
      - projected
      - secret

La restricción restricted-users-and-groups en el manifiesto de ejemplo usa la plantilla K8sPSPAllowedUsers a fin de establecer de forma explícita un rango de ejemplo de 1,000 a 2,000 para los parámetros runAsUser: y fsGroup:. Cualquier Pod que no esté configurado para usar un ID en ese rango para runAsUser: y fsGroup: se bloquea.

GKE Enterprise y Kubernetes no usan anotaciones de espacio de nombres para mutar de forma automática los Pods con un ID de usuario o grupo específico. Por lo tanto, para limitar el rango de UID como en el ejemplo anterior, tus equipos de entrega de aplicaciones deben establecer de forma explícita un UID que cumpla con los requisitos en el Pod creado, o debes quitar por completo la restricción para permitir cualquier ID.

El siguiente es un ejemplo de un manifiesto de Pod que cumple con las restricciones anteriores en cualquier espacio de nombres en el que lo crees (el manifiesto cumple con la SCC restricted):

apiVersion: v1
kind: Pod
metadata:
  name: restricted-pod-example
spec:
  securityContext:
    runAsUser: 1000
    fsGroup: 1100
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo

¿Qué sigue?

  • Explora arquitecturas de referencia, diagramas y prácticas recomendadas sobre Google Cloud. Consulta nuestro Cloud Architecture Center.