Aplicar políticas de segurança personalizadas no nível do pod usando o Gatekeeper


Nesta página, mostramos como usar o controlador de admissão do Gatekeeper para aplicar controles de segurança no nível do pod aos 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.

O 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).

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.

O Google Cloud oferece uma versão gerenciada e oficialmente aceita do Gatekeeper de código aberto, chamada de Policy Controller. O Google não oferece suporte oficial ao projeto Gatekeeper de código aberto.

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

  • Ativar a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Se você quiser usar a Google Cloud CLI para essa tarefa, instale e, em seguida, inicialize a CLI gcloud. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando gcloud components update.

Ativar o Gatekeeper em um cluster com o Policy Controller

O Policy Controller é um mecanismo de políticas criado no projeto de código aberto Gatekeeper. O Google recomenda o uso do Policy Controller porque ele inclui outros recursos para ajudar a aplicar a política em escala, incluindo política como código, suporte a vários clusters, integração com o Cloud Logging e capacidade de visualizar status da política no console do Google Cloud. O Policy Controller está disponível com uma licença da edição Enterprise do Google Kubernetes Engine (GKE), mas é possível instalar o Gatekeeper no cluster.

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

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

O Gatekeeper e os modelos de restrição podem ser instalados e ativados sem afetar negativamente as cargas de trabalho novas ou atuais. 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
    

Alternativas ao Gatekeeper

O Gatekeeper permite que você declare e aplique políticas de segurança personalizadas no nível do pod. Também é possível usar o controlador de admissão PodSecurity (visualização) integrado do Kubernetes para aplicar políticas predefinidas de segurança no nível do pod. Essas políticas predefinidas estão alinhadas aos níveis definidos pelos padrões de segurança do pod.

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.