Aplicar políticas de seguridad personalizadas a nivel de pod mediante 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 tus clústeres de Google Kubernetes Engine (GKE). En esta página se explica cómo usar Gatekeeper para aplicar restricciones que te permitan aplicar políticas de seguridad para cumplir los requisitos de seguridad de tu organización.

Esta página está dirigida a especialistas en seguridad que quieran aplicar controles de seguridad a sus clústeres de GKE. Para obtener más información sobre los roles habituales y las tareas de ejemplo a las que hacemos referencia en el contenido, consulta Roles y tareas habituales de los usuarios de GKE. Google Cloud

Antes de leer esta página, asegúrese de que conoce los siguientes conceptos:

Descripción general de Gatekeeper

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

Gatekeeper permite a los administradores definir políticas con una restricción, que es un conjunto de condiciones que permiten o deniegan los comportamientos de despliegue en Kubernetes. Después, puedes aplicar estas políticas a un clúster mediante un ConstraintTemplate. En este documento se proporcionan ejemplos para restringir las funciones de seguridad de las cargas de trabajo con el fin de aplicar, probar y auditar las políticas de seguridad mediante Gatekeeper.

Gatekeeper también puede hacer lo siguiente:

  • Implementar políticas: aplica las políticas de forma gradual y acotada para limitar el riesgo de interrumpir las cargas de trabajo.
  • Prueba de cambios en las políticas: proporciona mecanismos para probar el impacto y el alcance de las políticas antes de aplicarlas.
  • Auditar las políticas actuales: asegúrate de que se aplican controles de seguridad a las cargas de trabajo nuevas y actuales (controles de auditoría).

Conceptos clave de Gatekeeper

Gatekeeper introduce dos conceptos para ofrecer a los administradores un medio potente y flexible de controlar su clúster: restricciones y plantillas de restricciones. Ambos conceptos se han heredado del framework de restricciones de Open Policy Agent.

Las restricciones son la representación de tu política de seguridad. Definen los requisitos y el ámbito de la implementación. Las plantillas de restricciones son instrucciones reutilizables (escritas en Rego) que aplican lógica para evaluar campos específicos de objetos de Kubernetes en función de los requisitos definidos en las restricciones.

Por ejemplo, puedes tener una restricción que declare los perfiles de seccomp permitidos que se pueden aplicar a los pods de un espacio de nombres específico y una plantilla de restricción comparable que proporcione la lógica para extraer estos valores y gestionar la aplicación.

La siguiente plantilla de restricción, del repositorio Gatekeeper, comprueba si existe 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 ampliar el ejemplo de plantilla de restricción anterior, la siguiente restricción define el ámbito (kinds) para la aplicación específica de esta plantilla de restricción en el 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 Gatekeeper que se han definido para permitir una adopción rápida y la aplicación de la seguridad. Cada restricción también va acompañada de configuraciones de Pod de ejemplo.

Google Cloud proporciona una versión gestionada y con asistencia oficial de Gatekeeper de código abierto llamada Policy Controller. Google no ofrece asistencia oficial para el proyecto de código abierto Gatekeeper.

Antes de empezar

Antes de empezar, asegúrate de que has realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Si quieres usar Google Cloud CLI para esta tarea, instálala y, a continuación, inicialízala. Si ya has instalado la gcloud CLI, obtén la versión más reciente ejecutando gcloud components update.

Habilitar Gatekeeper en un clúster con Policy Controller

Policy Controller es un motor de políticas basado en el proyecto de código abierto Gatekeeper. Google recomienda usar Policy Controller porque incluye funciones adicionales para ayudar a aplicar políticas a gran escala, como la política como código, la compatibilidad con varios clústeres, la integración con Cloud Logging y la posibilidad de ver el estado de las políticas en la Google Cloud consola. Policy Controller está disponible en GKE, pero puedes instalar Gatekeeper en tu clúster.

Para habilitar Policy Controller en un clúster, sigue la guía de instalación de Policy Controller.

Habilitar restricciones y plantillas de restricciones

Gatekeeper y sus plantillas de restricciones se pueden instalar y habilitar sin que afecten negativamente a las cargas de trabajo actuales o nuevas. Por este motivo, se recomienda que se apliquen al clúster todas las plantillas de restricciones de seguridad de pods aplicables.

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

En el ejemplo siguiente se limita el ámbito a los pods ubicados en el espacio de nombres production definiéndolos en la instrucción de coincidencia de la restricción:

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

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

Probar políticas

La introducción de nuevas políticas en clústeres ya creados puede provocar comportamientos no deseados, como la restricción de cargas de trabajo. Una de las ventajas de usar Gatekeeper para la seguridad de los pods es la posibilidad de probar la eficacia y el impacto de una política sin hacer cambios reales, mediante un modo de prueba. Esto permite probar la configuración de las políticas en clústeres en ejecución sin aplicarlas. Las infracciones de las políticas se registran y se identifican sin interferencias.

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

  1. Aplica la configuración de Gatekeeper para replicar datos con el fin de realizar auditorías y pruebas:

    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. Sin aplicar ninguna restricción, ejecuta una carga de trabajo con privilegios elevados:

    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 anterior:

    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. Crea una restricción para ampliar esta plantilla de restricción. Esta vez, asigna el valor dryrun a enforcementAction:

    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 los datos de los objetos en ejecución y comprobando pasivamente si hay infracciones, confirma si se ha detectado alguna infracción comprobando 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. Para confirmar que la política no interfiere con las implementaciones, ejecuta otro pod con privilegios:

    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 desplegará 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 puedes confirmar la validez y el impacto de una política sin que afecte a las cargas de trabajo actuales o nuevas, puedes implementar una política con cumplimiento total.

Siguiendo los ejemplos utilizados para validar la política anterior, los pasos que se indican a continuación muestran cómo un desarrollador, un operador o un administrador pueden aplicar plantillas de restricciones y restricciones para aplicar una política:

  1. Carga la plantilla de restricción k8spspprivilegedcontainer que hemos mencionado 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. Crea una restricción para ampliar esta plantilla de restricción. Esta vez, no definas la clave enforcementAction. De forma predeterminada, la tecla enforcementAction está configurada como 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 desplegar 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ía aparecer 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 limpiar, 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 personalizadas a nivel de pod. También puedes usar el PodSecurity controlador de admisión integrado de Kubernetes para aplicar políticas de seguridad predefinidas a nivel de pod. Estas políticas predefinidas se ajustan a los niveles definidos por los estándares de seguridad de pods.

Siguientes pasos

Gatekeeper ofrece un medio increíblemente eficaz para aplicar y validar la seguridad en clústeres de GKE mediante políticas declarativas. Sin embargo, el uso de Gatekeeper va más allá de la seguridad y se puede utilizar en otros aspectos de la administración y las operaciones.