Escreva um modelo de restrição personalizado

Esta página mostra-lhe como escrever um modelo de restrição personalizado e usá-lo para expandir o Policy Controller se não conseguir encontrar um modelo de restrição pré-escrito que se adeque às suas necessidades.

Esta página destina-se a administradores de TI e operadores que querem garantir que todos os recursos executados na plataforma de nuvem cumprem os requisitos de conformidade da organização, fornecendo e mantendo a automatização para auditar ou aplicar, e usar modelos de configuração declarativa. Para saber mais sobre as funções comuns e as tarefas de exemplo que referimos no conteúdo, consulte o artigo Funções e tarefas comuns do utilizador do GKE. Google Cloud

As políticas do Policy Controller são descritas através da estrutura de restrições do OPA e são escritas em Rego. Uma política pode avaliar qualquer campo de um objeto Kubernetes.

Escrever políticas com o Rego é uma competência especializada. Por este motivo, é instalada uma biblioteca de modelos de restrições comuns por predefinição. É provável que possa invocar estes modelos de restrições quando criar restrições. Se tiver necessidades especializadas, pode criar os seus próprios modelos de restrições.

Os modelos de restrições permitem-lhe separar a lógica de uma política dos respetivos requisitos específicos para reutilização e delegação. Pode criar restrições através de modelos de restrições desenvolvidos por terceiros, como projetos de código aberto, fornecedores de software ou especialistas regulamentares.

Antes de começar

Exemplo de modelo de restrição

Segue-se um exemplo de um modelo de restrição que nega todos os recursos cujo nome corresponda a um valor fornecido pelo criador da restrição. O resto desta página aborda o conteúdo do modelo, destacando conceitos importantes ao longo do processo.

Se estiver a usar a sincronização de configuração com um repositório hierárquico, recomendamos que crie as restrições no diretório cluster/.

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdenyname
spec:
  crd:
    spec:
      names:
        kind: K8sDenyName
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            invalidName:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdenynames
        violation[{"msg": msg}] {
          input.review.object.metadata.name == input.parameters.invalidName
          msg := sprintf("The name %v is not allowed", [input.parameters.invalidName])
        }

Exemplo de restrição

Segue-se um exemplo de uma restrição que pode implementar para recusar todos os recursos denominados policy-violation:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyName
metadata:
  name: no-policy-violation
spec:
  parameters:
    invalidName: "policy-violation"

Partes de um modelo de restrição

Os modelos de restrições têm duas partes importantes:

  • O esquema da restrição que quer que os utilizadores criem. O esquema de um modelo de restrição é armazenado no campo crd.

  • O código fonte Rego que é executado quando a restrição é avaliada. O código-fonte Rego de um modelo é armazenado no campo targets.

Esquema (campo crd)

O campo CRD é um modelo para criar a definição de recursos personalizados do Kubernetes que define o recurso de restrição para o servidor da API Kubernetes. Só tem de preencher os seguintes campos.

Campo Descrição
spec.crd.spec.names.kind O tipo de restrição. Quando convertido em minúsculas, o valor deste campo tem de ser igual a metadata.name.
spec.crd.spec.validation.openAPIV3Schema

O esquema do campo spec.parameters do recurso de restrição (o Policy Controller define automaticamente o resto do esquema da restrição). Segue as mesmas convenções que seguiria num recurso CRD normal.

Adicionar o prefixo K8s ao modelo de restrição é uma convenção que lhe permite evitar colisões com outros tipos de modelos de restrições, como modelos do Forseti que segmentam recursos Google Cloud .

Código-fonte Rego (campo targets)

As secções seguintes fornecem mais informações sobre o código fonte do Rego.

Localização

O código fonte Rego é armazenado no campo spec.targets, onde targets é uma matriz de objetos do seguinte formato:

{"target": "admission.k8s.gatekeeper.sh","rego": REGO_SOURCE_CODE, "libs": LIST_OF_REGO_LIBRARIES}
  • target: indica ao Policy Controller o sistema que estamos a analisar (neste caso, o Kubernetes); só é permitida uma entrada em targets.
  • rego: o código-fonte da restrição.
  • libs: uma lista opcional de bibliotecas de código Rego que é disponibilizada ao modelo de restrição; destina-se a facilitar a utilização de bibliotecas partilhadas e está fora do âmbito deste documento.

Código fonte

Segue-se o código-fonte Rego para a restrição anterior:

package k8sdenynames

violation[{"msg": msg}] {
   input.review.object.metadata.name == input.parameters.invalidName
   msg := sprintf("The name %v is not allowed", [input.parameters.invalidName])
}

Tenha em conta o seguinte:

  • O campo package k8sdenynames é obrigatório para o OPA (tempo de execução do Rego). O valor é ignorado.
  • A regra Rego que o Policy Controller invoca para verificar se existem violações chama-se violation. Se esta regra tiver correspondências, ocorreu uma violação da restrição.
  • A regra violation tem a assinatura violation[{"msg": "violation message for the user"}], em que o valor de "msg" é a mensagem de violação devolvida ao utilizador.
  • Os parâmetros fornecidos à restrição são disponibilizados na palavra-chave input.parameters.
  • O request-under-test é armazenado na palavra-chave input.review.

A palavra-chave input.review tem os seguintes campos.

Campo Descrição
uid O ID exclusivo deste pedido específico. Não está disponível durante a auditoria.
kind

As informações de tipo para o object-under-test. Tem o seguinte formato:

  • kind: o tipo de recurso
  • group: o grupo de recursos
  • version: a versão do recurso
name O nome do recurso. Pode estar vazio se o utilizador estiver a usar o servidor da API para gerar o nome num pedido CREATE.
namespace O espaço de nomes do recurso (não fornecido para recursos com âmbito de cluster).
operation A operação pedida (por exemplo, CREATE ou UPDATE) não está disponível durante a auditoria.
userInfo

As informações do utilizador que está a fazer o pedido. Não estão disponíveis durante a auditoria. Tem o seguinte formato:

  • username: o utilizador que está a fazer o pedido
  • uid: o UID do utilizador
  • groups: uma lista de grupos dos quais o utilizador é membro
  • extra: quaisquer informações adicionais do utilizador fornecidas pelo Kubernetes
object O objeto que o utilizador está a tentar modificar ou criar.
oldObject O estado original do objeto; só está disponível em operações UPDATE.
dryRun Se este pedido foi invocado com kubectl --dry-run; não está disponível durante a auditoria.

Escreva modelos de restrições referenciais

Os modelos de restrições referenciais são modelos que permitem ao utilizador restringir um objeto relativamente a outros objetos. Um exemplo disto pode ser "não permitir a criação de um Pod antes de se saber que existe um Ingress correspondente". Outro exemplo pode ser "não permitir que dois serviços tenham o mesmo nome de anfitrião".

O Policy Controller permite-lhe escrever restrições referenciais monitorizando o servidor de API para um conjunto de recursos fornecido pelo utilizador. Quando um recurso é modificado, o Policy Controller armazena-o em cache localmente para que possa ser facilmente referenciado pelo código fonte Rego. O Policy Controller disponibiliza esta cache através da palavra-chave data.inventory.

Os recursos com âmbito de cluster são colocados em cache na seguinte localização:

data.inventory.cluster["GROUP_VERSION"]["KIND"]["NAME"]

Por exemplo, um nó com o nome my-favorite-node pode ser encontrado em

data.inventory.cluster["v1"]["Node"]["my-favorite-node"]

Os recursos com âmbito do espaço de nomes são colocados em cache aqui:

data.inventory.namespace["NAMESPACE"]["GROUP_VERSION"]["KIND"]["NAME"]

Por exemplo, um ConfigMap denominado production-variables no espaço de nomes shipping-prod pode ser encontrado em

data.inventory.namespace["shipping-prod"]["v1"]["ConfigMap"]["production-variables"]

O conteúdo completo do objeto é armazenado nesta localização da cache e pode ser referenciado no seu código-fonte Rego da forma que considerar mais adequada.

Mais informações sobre o Rego

As informações anteriores fornecem as funcionalidades únicas do Policy Controller que facilitam a escrita de restrições em recursos do Kubernetes no Rego. Um tutorial completo sobre como escrever em Rego está fora do âmbito deste guia. No entanto, a documentação do Open Policy Agent tem informações sobre a sintaxe e as funcionalidades da própria linguagem Rego.

Instale o modelo de restrição

Depois de criar o modelo de restrição, use kubectl apply para o aplicar e o Policy Controller encarrega-se de o carregar. Certifique-se de que verifica o campo status do modelo de restrição para se certificar de que não ocorreram erros na respetiva instanciação. Após a carregamento bem-sucedido, o campo status deve apresentar created: true e o valor observedGeneration indicado no campo status deve ser igual ao valor do campo metadata.generation.

Depois de o modelo ser carregado, pode aplicar restrições ao mesmo, conforme descrito no artigo Criar restrições.

Remova um modelo de restrição

Para remover um modelo de restrição, conclua os seguintes passos:

  1. Verifique se não existem restrições que queira preservar a usar o modelo de restrição:

    kubectl get TEMPLATE_NAME
    

    Se existir um conflito de nomenclatura entre o nome do modelo de restrição e um objeto diferente no cluster, use o seguinte comando:

    kubectl get TEMPLATE_NAME.constraints.gatekeeper.sh
    
  2. Remova o modelo de restrição:

    kubectl delete constrainttemplate CONSTRAINT_TEMPLATE_NAME
    

Quando remove um modelo de restrição, deixa de poder criar restrições que façam referência ao mesmo.

O que se segue?