Aplica políticas de seguridad personalizadas a nivel de los Pods con Gatekeeper


En esta página, se muestra cómo usar el controlador de admisión Gatekeeper para aplicar controles de seguridad a nivel de Pod en los clústeres de Google Kubernetes Engine (GKE).

Descripción general

Gatekeeper es un controlador de admisión que valida las solicitudes para crear y actualizar Pods en los clústeres de Kubernetes con Open Policy Agent (OPA).

El uso de Gatekeeper permite que los administradores definan políticas con una restricción, que es un conjunto de condiciones que permiten o rechazan comportamientos de implementación en Kubernetes. Puedes aplicar estas políticas en un clúster mediante un ConstraintTemplate. En este documento, se proporcionan ejemplos para restringir las capacidades de seguridad de las cargas de trabajo para garantizar la aplicación forzosa, prueba y auditoría de las políticas de seguridad mediante Gatekeeper.

Gatekeeper también puede hacer lo siguiente:

  • Implementar políticas: Aplica la política de manera gradual y con alcance para limitar el riesgo de interrumpir las cargas de trabajo.
  • Ejecutar cambios de políticas en modo de prueba: Proporciona mecanismos para probar el impacto y el rango de la política antes de la aplicación.
  • Auditar las políticas existentes: Garantiza la aplicación de los controles de seguridad para las cargas de trabajo nuevas y existentes (controles de auditoría).

Conceptos

Gatekeeper presenta dos conceptos con el fin de proporcionarles a los administradores métodos potentes y flexibles para controlar sus clústeres: restricciones y plantillas de restricción, que son conceptos heredados del framework de restricciones de Open Policy Agent.

Las restricciones son la representación de tu política de seguridad, ya que definen los requisitos y el rango de aplicación. Las plantillas de restricción son declaraciones reutilizables (escritas en Rego) que aplican una lógica para evaluar campos específicos en objetos de Kubernetes, según los requisitos definidos en las restricciones.

Por ejemplo, podrías tener una restricción que declare perfiles de seccomp que se pueden aplicar a Pods en un espacio de nombres específico y una plantilla de restricción similar que proporciona la lógica para extraer estos valores y controlar la aplicación de manera forzosa.

En la siguiente plantilla de restricción, del repositorio de Gitkeeper, comprueba la existencia de securityContext.privileged en una especificación de Pod:

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8spspprivilegedcontainer
spec:
  crd:
    spec:
      names:
        kind: K8sPSPPrivilegedContainer
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8spspprivileged

        violation[{"msg": msg, "details": {}}] {
            c := input_containers[_]
            c.securityContext.privileged
            msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
        }
        input_containers[c] {
            c := input.review.object.spec.containers[_]
        }
        input_containers[c] {
            c := input.review.object.spec.initContainers[_]
        }

Para extender la plantilla de restricción anterior, la siguiente restricción define el permiso (kinds) de la aplicación específica de esta plantilla de restricción en un modo dryrun:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: psp-privileged-container
spec:
  enforcementAction: dryrun
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]

Con Gatekeeper, puedes crear tus propias restricciones y plantillas de restricciones para satisfacer tus necesidades específicas. También puedes usar un conjunto estándar de restricciones y plantillas de restricciones en el repositorio de Gitkeeper que se definió para permitir la adopción rápida y la aplicación de la seguridad. Cada restricción también incluye configuraciones de Pod de ejemplo.

Google Cloud proporciona una versión administrada y compatible de forma oficial de Gatekeeper llamada Controlador de políticas. Google no admite oficialmente el proyecto de código abierto Gatekeeper.

Antes de comenzar

Antes de comenzar, asegúrate de haber realizado las siguientes tareas:

  • Habilita la API de Kubernetes Engine de Google.
  • Habilitar la API de Kubernetes Engine de Google
  • Si deseas usar Google Cloud CLI para esta tarea, instala y, luego, inicializa gcloud CLI. Si ya instalaste gcloud CLI, ejecuta gcloud components update para obtener la versión más reciente.

Habilita el guardián de acceso en un clúster con el Controlador de políticas

El controlador de políticas es un motor de políticas compilado en el proyecto de código abierto guardián de acceso. Google recomienda el uso del Controlador de políticas porque incluye funciones adicionales para ayudar a aplicar la política a gran escala, incluida la política como código, la compatibilidad con varios clústeres, la integración con Cloud Logging y la habilidad de ver el estado de la política en la consola de Google Cloud. El controlador de políticas está disponible con una licencia de Google Kubernetes Engine (GKE) Enterprise Edition, pero en su lugar puedes instalar el guardián de acceso en tu clúster.

Para habilitar el Controlador de políticas en un clúster, sigue la Guía de instalación del Controlador de políticas.

Habilita las restricciones y las plantillas de restricciones

Gatekeeper y sus plantillas de restricciones se pueden instalar y habilitar sin afectar negativamente las cargas de trabajo nuevas o existentes. Por esta razón, se recomienda que todas las plantillas de restricción de seguridad de Pods aplicables se apliquen al clúster.

Además, las restricciones de Gatekeeper se pueden implementar para aplicar controles para objetos específicos, como espacios de nombres y Pods.

Observa el siguiente ejemplo que limita el alcance a los Pods ubicados en el espacio de nombres production y los define en la declaración de coincidencia de restricciones:

...
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces:
      - "production"

A fin de obtener más información sobre las opciones disponibles para los objetos Constraint y ConstraintTemplate, consulta Cómo usar Gatekeeper.

Prueba políticas

La introducción de políticas nuevas a los clústeres existentes puede tener un comportamiento adverso; por ejemplo, la restricción de las cargas de trabajo existentes. Uno de los beneficios de usar Gatekeeper para la seguridad de Pods es la capacidad de probar la eficacia y el impacto que tendrá una política sin realizar cambios reales con un modo de ejecución de prueba. Esto permite que se realice la prueba de la configuración de la política en clústeres en ejecución sin aplicación de políticas. Los incumplimientos de políticas se registran y se identifican sin interferir.

En los siguientes pasos, se demuestra cómo un desarrollador, operador o administrador puede aplicar plantillas de restricción y restricciones para determinar su eficacia o impacto potencial:

  1. Aplica los archivos de configuración de Gatekeeper a fin de replicar datos para la auditoría y la ejecución de prueba:

    kubectl create -f- <<EOF
    apiVersion: config.gatekeeper.sh/v1alpha1
    kind: Config
    metadata:
      name: config
      namespace: "gatekeeper-system"
    spec:
      sync:
        syncOnly:
          - group: ""
            version: "v1"
            kind: "Namespace"
          - group: ""
            version: "v1"
            kind: "Pod"
    EOF
    
  2. A continuación, se ejecuta una carga de trabajo con privilegios elevados sin aplicar restricciones:

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    
  3. Carga la plantilla de restricción k8spspprivilegedcontainer que se mencionó antes:

    kubectl create -f- <<EOF
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8spspprivilegedcontainer
    spec:
      crd:
        spec:
          names:
            kind: K8sPSPPrivilegedContainer
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8spspprivileged
    
            violation[{"msg": msg, "details": {}}] {
                c := input_containers[_]
                c.securityContext.privileged
                msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
            }
            input_containers[c] {
                c := input.review.object.spec.containers[_]
            }
            input_containers[c] {
                c := input.review.object.spec.initContainers[_]
            }
    EOF
    
  4. Ahora, creemos una restricción nueva para extender esta plantilla de restricción. Esta vez, estableceremos enforcementAction en dryrun:

    kubectl create -f- <<EOF
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
      name: psp-privileged-container
    spec:
      enforcementAction: dryrun
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
    EOF
    
  5. Con Gatekeeper sincronizando datos de objetos en ejecución y verificando de forma pasiva si hay incumplimientos, podemos confirmar si se encontraron infracciones mediante el status de la restricción:

    kubectl get k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container -o yaml
    
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
    ...
     name: psp-privileged-container
    ...
    spec:
     enforcementAction: dryrun
     match:
       kinds:
       - apiGroups:
         - ""
         kinds:
         - Pod
    status:
     auditTimestamp: "2019-12-15T22:19:54Z"
     byPod:
     - enforced: true
       id: gatekeeper-controller-manager-0
     violations:
     - enforcementAction: dryrun
       kind: Pod
       message: 'Privileged container is not allowed: nginx, securityContext: {"privileged":
         true}'
       name: nginx
       namespace: default
    
  6. Ejecutemos otro Pod con privilegios para confirmar que la política no interfiere con las implementaciones:

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: privpod
      labels:
        app: privpod
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    

    Este nuevo Pod se implementará correctamente.

  7. Para limpiar los recursos creados en esta sección, ejecuta los siguientes comandos:

    kubectl delete k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container
    kubectl delete constrainttemplate k8spspprivilegedcontainer
    kubectl delete pod/nginx
    kubectl delete pod/privpod
    

Aplicar políticas

Ahora que podemos confirmar la validez y el impacto de una política sin afectar las cargas de trabajo existentes o nuevas, implementemos una política con aplicación completa.

Sobre la base de los ejemplos utilizados para validar la política anterior, los siguientes pasos demuestran cómo un desarrollador, operador o administrador puede aplicar plantillas de restricciones y restricciones para aplicar una política:

  1. Carga la plantilla de restricción k8spspprivilegedcontainer que se mencionó antes:

    kubectl create -f- <<EOF
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8spspprivilegedcontainer
    spec:
      crd:
        spec:
          names:
            kind: K8sPSPPrivilegedContainer
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8spspprivileged
    
            violation[{"msg": msg, "details": {}}] {
                c := input_containers[_]
                c.securityContext.privileged
                msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
            }
            input_containers[c] {
                c := input.review.object.spec.containers[_]
            }
            input_containers[c] {
                c := input.review.object.spec.initContainers[_]
            }
    EOF
    
  2. Ahora, creemos una restricción nueva para extender esta plantilla de restricción. Esta vez, no configuraremos la clave enforcementAction. De forma predeterminada, la clave enforcementAction se establece en deny.

    kubectl create -f- <<EOF
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
      name: psp-privileged-container
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
    EOF
    
  3. Intenta implementar un contenedor que declare permisos con privilegios:

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    

    Deberías recibir el siguiente mensaje de error:

    Error from server ([denied by psp-privileged-container] Privileged container is not allowed:
    nginx, securityContext: {"privileged": true}): error when creating "STDIN": admission webhook "validation.gatekeeper.sh" denied the request: [denied by psp-privileged-container]
    Privileged container is not allowed: nginx, securityContext: {"privileged": true}
    
  4. Para realizar una limpieza, ejecuta los siguientes comandos:

    kubectl delete k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container
    kubectl delete constrainttemplate k8spspprivilegedcontainer
    

Alternativas a Gatekeeper

Gatekeeper te permite declarar y aplicar políticas de seguridad a nivel del Pod personalizadas. También puedes usar el controlador de admisión PodSecurity integrado de Kubernetes para aplicar políticas de seguridad predefinidas a nivel del Pod. Estas políticas predefinidas están alineadas con los niveles definidos por los Estándares de seguridad de Pods.

¿Qué sigue?

Gatekeeper proporciona un método extremadamente potente para aplicar y validar la seguridad en los clústeres de GKE mediante políticas declarativas. Sin embargo, el uso de Gatekeeper se extiende más allá de la seguridad y puede usarse en otros aspectos de la administración y las operaciones.