Como escrever um modelo de restrição

Nesta página, mostramos como programar um modelo de restrição personalizado e usá-lo para estender o Controlador de políticas.

Se você não encontrar um modelo de restrição pré-escrito que atenda às suas necessidades para estender o controlador de políticas, é possível escrever seu próprio modelo.

As políticas do controlador de políticas são descritas usando a biblioteca de restrições de OPA e são programadas em Rego (links em inglês). Uma política pode avaliar qualquer campo de um objeto Kubernetes.

Escrever políticas usando o Rego é uma habilidade especializada. Por esse motivo, uma biblioteca de modelos de restrição comuns é instalada por padrão. A maioria dos usuários pode chamar esses modelos de restrição ao criar restrições. Se você tiver necessidades especializadas, poderá criar seus próprios modelos de restrição.

Os modelos de restrição permitem separar a lógica de uma política dos requisitos específicos para reutilização e delegação. É possível criar restrições usando modelos de restrição desenvolvidos por terceiros, como projetos de código aberto, fornecedores de software ou especialistas em regulamentação.

Antes de começar

Modelo de restrição de exemplo

Veja a seguir um modelo de restrição de exemplo que nega todos os recursos cujo nome corresponde a um valor fornecido pelo criador da restrição. O restante desta página discute o conteúdo do modelo, destacando conceitos importantes.

Se você estiver usando um repositório estruturado, recomendamos que crie suas 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])
        }

Restrição de exemplo

Veja a seguir uma restrição de exemplo que pode ser implementada para negar todos os recursos chamados 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ção têm duas partes importantes:

  • O esquema da restrição que você quer que os usuários 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 para um modelo é armazenado no campo targets.

Esquema (campo crd)

O campo CRD é um modelo para criar a Definição de Recurso Personalizado do Kubernetes que define o recurso de restrição para o servidor da API Kubernetes. Você só precisa preencher os campos a seguir.

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

O esquema do campo spec.parameters do recurso de restrição (o restante do esquema da restrição é definido automaticamente pelo Anthos Config Management). Ele segue as mesmas convenções de um recurso regular de CRD.

A definição dela está documentada na documentação da API Kubernetes (em inglês).

Prefixo do modelo de restrição com nome K8s é uma convenção que permite evitar conflitos com outros tipos de modelos de restrição, como modelos do Forseti que segmentam recursos do Google Cloud.

Código-fonte original (campo targets)

As seções a seguir fornecem mais informações sobre o código-fonte do Rego.

Local

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

{"target": "admission.k8s.gatekeeper.sh","rego": REGO_SOURCE_CODE, "libs": LIST_OF_REGO_LIBRARIES}
  • target: informa ao Anthos Config Management qual sistema estamos observando (neste caso, Kubernetes). Só uma entrada em targets é permitida.
  • rego é o código-fonte da restrição.
  • libs: uma lista opcional de bibliotecas do código do Rego que é disponibilizada para o modelo de restrição. Ele foi desenvolvido para facilitar o uso de bibliotecas compartilhadas e está fora do escopo deste documento.

Código-fonte

Veja a seguir o código-fonte do 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])
}

Observe o seguinte:

  • package k8sdenynames é requerido pelo OPA (ambiente de execução do Rego). O valor é ignorado.
  • A regra Rego que o Policy Controller chama para verificar se há alguma violação é chamada violation. Se essa regra tiver correspondências, ocorreu uma violação da restrição.
  • A regra violation tem a assinatura violation[{"msg": "violation message for the user"}], onde o valor de "msg" é a mensagem de violação retornada ao usuário.
  • Os parâmetros fornecidos à restrição são disponibilizados sob a palavra-chave input.parameters.
  • O request-under-test é armazenado sob a palavra-chave input.review.

A palavra-chave input.review tem os campos a seguir.

Campo Descrição
uid O ID exclusivo dessa solicitação. Não fica disponíveis durante a auditoria.
kind

As informações de Tipo de object-under-test. Ele 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. É possível que ela esteja vazia se o usuário depende do servidor de API para gerar o nome em uma solicitação CREATE.
namespace O namespace do recurso (não fornecido para recursos com escopo no cluster).
operation A operação solicitada (por exemplo, CREATE ou UPDATE). Não ficam disponíveis durante a auditoria.
userInfo

As informações do usuário solicitante. Não é possível fazer isso durante a auditoria. Ele tem o seguinte formato:

  • username: o usuário que está fazendo a solicitação
  • uid: o UID do usuário
  • groups: uma lista de grupos do qual o usuário é membro
  • extra: qualquer informação extra fornecida pelo Kubernetes.
object O objeto que o usuário está tentando modificar ou criar
oldObject O estado original do objeto. Está disponível somente nas operações UPDATE.
dryRun Se esta solicitação foi invocada com kubectl --dry-run Ela não estará disponível durante a auditoria.

Como programar modelos de restrição referencial

Modelos de restrição referencial são modelos que permitem ao usuário restringir um objeto em relação a outros objetos. Um exemplo disso pode ser "não permita que um pod seja criado antes que se saiba que existe uma entrada correspondente". Outro exemplo pode ser "não permita que dois serviços tenham o mesmo nome de host".

O Policy Controller permite que você escreva restrições referenciais observando o servidor de API para conseguir um conjunto de recursos fornecidos pelo usuário. Quando um recurso é modificado, o Policy Controller o armazena em cache localmente, para que possa ser facilmente referenciado pelo código-fonte Rego. O Policy Controller disponibiliza esse cache com a palavra-chave data.inventory.

Os recursos com escopo definido em cluster são armazenados em cache no seguinte local:

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

Por exemplo, um nó chamado my-favorite-node pode ser encontrado em

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

Recursos com namespace são armazenados em cache aqui:

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

Por exemplo, um ConfigMap chamado production-variables no namespace shipping-prod pode ser encontrado em

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

O conteúdo completo do objeto é armazenado nesse local de cache e pode ser referenciado no seu Rego da maneira que você achar melhor.

Mais informações sobre Rego

As informações anteriores fornecem os recursos exclusivos do Policy Controller que facilitam a gravação de restrições nos recursos do Kubernetes no Rego. Um tutorial completo sobre como programar no Rego está fora do escopo deste guia. No entanto, o site do Open Policy Agent tem documentação sobre a sintaxe e os recursos da linguagem própria do Rego.

Como instalar o modelo de restrição

Depois de criar o modelo de restrição, use kubectl apply para aplicá-lo. O Policy Controller cuidará do processamento. Verifique o campo status do seu modelo de restrição para garantir que não haja erros ao instancia-lo. Na ingestão bem-sucedida, o campo status precisa mostrar created: true e o observedGeneration anotado no campo status precisa ser igual ao campo metadata.generation.

Depois que o modelo é ingerido, você pode aplicar restrições, conforme descrito em Como criar restrições.

Como remover um modelo de restrição

Para remover um modelo de restrição, siga estas etapas:

  1. Verifique se nenhuma restrição que você quer preservar está usando o modelo de restrição:

    kubectl get TEMPLATE_NAME
    

    No caso de 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 você remove um modelo de restrição, não é mais possível criar restrições que o referenciem.

A seguir