Como aplicar políticas de segurança de pods usando o Gatekeeper


Nesta página, explicamos a maneira recomendada de aplicar controles de segurança no nível dos Pods para os clusters do Google Kubernetes Engine (GKE).

Visão geral

O Gatekeeper é um controlador de admissão que valida solicitações para criar e atualizar Pods nos clusters do Kubernetes, usando o Open Policy Agent (OPA).

O uso do Gatekeeper permite que os administradores definam políticas com uma restrição, ou seja, um conjunto de condições que permitem ou negam comportamentos de implantação no Kubernetes. É possível aplicar essas políticas em um cluster usando um ConstraintTemplate. Neste documento, apresentamos exemplos de como restringir os recursos de segurança das cargas de trabalho para garantir, aplicar, testar e auditar políticas de segurança usando o Gatekeeper.

Além de aplicar os mesmos recursos que as PodSecurityPolicies do Kubernetes, o próprio Gatekeeper também pode fazer o seguinte:

  • Lançar políticas: aplica a política de maneira gradual e com escopo definido para limitar o risco de interrupção das cargas de trabalho.
  • Simulação de alterações na política: fornece mecanismos para testar o impacto da política e o intervalo antes da aplicação.
  • Auditar políticas existentes: garante a aplicação dos controles de segurança a cargas de trabalho novas e atuais (controles de auditoria).

O Kubernetes Open Source Software (OSS) está em processo de suspensão do uso das PodSecurityPolicies do Kubernetes, e o Google não recomenda mais o uso dele.

Conceitos

O Gatekeeper oferece dois conceitos para proporcionar aos administradores uma maneira avançada e flexível de controlar os clusters: restrições e modelos de restrições, sendo que ambos são conceitos herdados do framework de restrições de Open Policy Agent.

Restrições são a representação da política de segurança e definem os requisitos e o intervalo de aplicação. Modelos de restrições são instruções reutilizáveis (escritas em Rego) que aplicam lógica para avaliar campos específicos em objetos do Kubernetes, com base nos requisitos definidos nas restrições.

Por exemplo, é possível ter uma restrição que declara perfis seccomp permitidos que podem ser aplicados a Pods em um namespace específico, e um modelo de restrição comparável que fornece a lógica para extrair esses valores e manipular a aplicação.

O modelo de restrição a seguir, do repositório Gatekeeper, verifica a existência de securityContext.privileged em uma especificação do 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 estender o modelo de restrição acima, a restrição a seguir define o escopo (kinds) para a aplicação específica desse modelo de restrição em um modo dryrun:

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

Com o Gatekeeper, é possível criar suas próprias restrições e modelos de restrições para atender às suas necessidades específicas. Também é possível usar um conjunto padrão de restrições e modelos de restrições no repositório Gatekeeper que foi definido para permitir uma rápida adoção e aplicação de segurança. Cada uma das restrições também é acompanhada por exemplos de configurações de Pod.

Antes de começar

Antes de começar, veja se você realizou as seguintes tarefas:

  • Verifique se você ativou a API do Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Verifique se o SDK do Cloud está instalado.
  • Defina as configurações padrão da ferramenta de linha de comando gcloud do seu projeto usando um dos seguintes métodos:
    • Use gcloud init se quiser orientações para definir os padrões do projeto.
    • Use gcloud config para definir individualmente a região, a zona e o ID do projeto.

    gcloud init

    1. Execute gcloud init e siga as instruções:

      gcloud init

      Se você estiver usando SSH em um servidor remoto, utilize a sinalização --console-only para impedir que o comando inicie um navegador:

      gcloud init --console-only
    2. Siga as instruções para autorizar a ferramenta gcloud a usar sua conta do Google Cloud.
    3. Crie uma nova configuração ou selecione uma atual.
    4. Escolha um projeto do Google Cloud.
    5. Escolha uma zona padrão do Compute Engine.
    6. Escolha uma região padrão do Compute Engine.

    gcloud config

    1. Defina o ID do projeto padrão:
      gcloud config set project PROJECT_ID
    2. Defina a região padrão do Compute Engine (por exemplo, us-central1):
      gcloud config set compute/region COMPUTE_REGION
    3. Defina a zona padrão do Compute Engine (por exemplo, us-central1-c):
      gcloud config set compute/zone COMPUTE_ZONE
    4. Atualize gcloud para a versão mais recente:
      gcloud components update

    Ao definir locais padrão, é possível evitar erros na ferramenta gcloud como o seguinte: One of [--zone, --region] must be supplied: Please specify location.

Ativar o Gatekeeper em um cluster com o Anthos Config Management

O Anthos Config Management oferece o Policy Controller, que é um mecanismo de políticas criado no projeto de código aberto do Gatekeeper. O Google recomenda o uso do Anthos Config Management porque ele resolve problemas comuns associados à aplicação de políticas em escala, incluindo política como código, suporte a vários clusters, integração com o Cloud Logging e capacidade de sincronizar a configuração.

Para ativar o Policy Controller em um cluster, siga o guia de instalação do Anthos Config Management.

Ativar restrições e modelos de restrição

Ao contrário do PodSecurityPolicy, o Gatekeeper e os modelos de restrições dele podem ser instalados e ativados sem afetar negativamente as cargas de trabalho atuais ou novas. Por esse motivo, recomendamos que todos os modelos de restrições de segurança aplicáveis do Pod sejam aplicados ao cluster.

Além disso, as restrições do Gatekeeper podem ser implementadas para aplicar controles para objetos específicos, como namespaces e Pods.

Observe o exemplo abaixo que limita o escopo aos Pods localizados no namespace production definindo-os na instrução de correspondência de restrição:

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

Para mais informações sobre as opções disponíveis para objetos Constraint e ConstraintTemplate, consulte Como usar o Gatekeeper.

Políticas de teste

A introdução de novas políticas a clusters atuais pode ter um comportamento adverso, por exemplo, restringindo as cargas de trabalho atuais. Um dos benefícios de usar o Gatekeeper para a segurança de Pods é a capacidade de testar a eficácia e o impacto de uma política sem precisar fazer alterações reais. Isso é feito pelo modo de simulação. Isso permite que a configuração da política seja testada em clusters em execução sem que a política seja aplicada. As violações de políticas são registradas e identificadas sem interferências.

As etapas a seguir demonstram como um desenvolvedor, operador ou administrador pode aplicar modelos de restrições e restrições para determinar a eficácia ou o possível impacto deles:

  1. Aplique a configuração do Gatekeeper para replicar dados para a funcionalidade de auditoria e simulação:

    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. Sem restrições aplicadas, vamos executar uma carga de trabalho com privilégios 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. Carregue o modelo de restrição k8spspprivilegedcontainer mencionado acima:

    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. Agora vamos criar uma nova restrição para estender esse modelo de restrição. Desta vez, definiremos enforcementAction como 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. Como o Gatekeeper sincroniza os dados do objeto em execução e verifica passivamente as violações, podemos confirmar se alguma violação foi encontrada verificando o status da restrição:

    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. Execute outro Pod com privilégios para confirmar se a política não interfere nas implantações:

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

    Esse novo Pod será implantado com sucesso.

  7. Para limpar os recursos criados nesta seção, execute os comandos a seguir:

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

Aplicação de políticas

Agora que podemos confirmar a validade e o impacto de uma política sem afetar as cargas de trabalho novas ou atuais, vamos implementar uma política com aplicação completa.

Com base nos exemplos usados para validar a política acima, as etapas a seguir demonstram como um desenvolvedor, operador ou administrador pode aplicar restrições e modelos de restrições para aplicar uma política:

  1. Carregue o modelo de restrição k8spspprivilegedcontainer mencionado anteriormente:

    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. Agora vamos criar uma nova restrição para estender esse modelo de restrição. Desta vez, não vamos definir a chave enforcementAction. Por padrão, a chave enforcementAction está definida 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. Tente implantar um contêiner que declare permissões privilegiadas:

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

    A mensagem de erro a seguir será recebida:

    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 fazer a limpeza, execute os comandos a seguir:

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

A seguir

O Gatekeeper fornece um meio incrivelmente avançado para aplicar e validar a segurança em clusters do GKE usando políticas declarativas. No entanto, o uso do Gatekeeper vai além da segurança e pode ser usado em outros aspectos de administração e operações.