|
Este documento foi traduzido usando tecnologia de tradução automática de máquina. Sempre trabalhamos para apresentar traduções precisas, mas não oferecemos nenhuma garantia em relação à integridade, precisão ou confiabilidade do conteúdo traduzido. Em caso de qualquer discrepância, a versão original em inglês prevalecerá e constituirá o texto official. |
|
Esta é uma documentação não divulgada para Admission Controller 1.34-dev. |
Políticas CEL com reconhecimento de contexto
O SUSE Security Admission Controller de cel-policy suporta o recurso de consciência de contexto. A política tem a capacidade de ler informações do cluster e tomar decisões com base em outros recursos existentes além daquele que acionou a avaliação da política via solicitação de admissão.
Para alcançar isso, podemos usar as bibliotecas de extensão CEL de Admission Controller para capacidades de host incluídas na política.
Exemplo: Ingress único
Vamos escrever uma política que, ao criar ou atualizar Ingresses, verifica se o Ingress é único, para que os hosts tenham no máximo uma regra de Ingress.
Para isso, declaramos que a política é com reconhecimento de contexto. Também declaramos as permissões detalhadas que precisamos para ler outros recursos de Ingress. Isso é alcançado com spec.contextAwareResources (1). Podemos obter um ponto de partida como de costume usando kwctl:
$ kwctl scaffold manifest -t ClusterAdmissionPolicy \
registry://ghcr.io/kubewarden/policies/cel-policy:v1.0.0` \
--allow-context-aware
O qual podemos editar para ser relevante para nossos recursos de Ingress:
apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
name: "unique-ingress"
annotations:
io.kubewarden.policy.category: Best practices
io.kubewarden.policy.severity: low
spec:
module: ghcr.io/kubewarden/policies/cel-policy:v1.0.0
failurePolicy: Fail
rules:
- apiGroups: ["networking.k8s.io"]
apiVersions: ["v1"]
resources: ["ingresses"]
operations: ["CREATE", "UPDATE"]
contextAwareResources: # (1)
- apiVersion: networking.k8s.io/v1
kind: Ingress
Agora, precisamos escrever o código CEL que buscará os Ingresses existentes no cluster. Para isso, usamos a [biblioteca de extensão CEL Admission Controller](https://github.com/kubewarden/cel-policy?tab=readme-ov-file#host-capabilities).
Particularmente, as kw.k8s capacidades de host, que nos permitem consultar o cluster por GroupVersionKinds. Você pode ver a documentação disponível para as funções CEL [aqui](https://pkg.go.dev/github.com/kubewarden/cel-policy/internal/cel/library).
A biblioteca usa um padrão de construtor assim como as extensões CEL do Kubernetes upstream; chamar um método de função CEL retorna um objeto CEL que por si só possui métodos de função específicos. Isso simplifica a certeza sobre o escopo e os retornos do nosso código CEL.
Neste caso, usaremos kw.k8s.apiVersion("v1").kind("Ingress"); aqui chamamos a função apiVersion() da biblioteca kw.k8s, que nos retorna um objeto <ClientBuilder>. Este objeto possui o método <ClientBuilder>.kind(), que retorna uma lista de todos os recursos, em um array chamado items.
Com isso, salvamos a lista de Ingresses no cluster em uma variável:
variables:
- name: knownIngresses
expression: kw.k8s.apiVersion("networking.k8s.io/v1").kind("Ingress").list().items
Em seguida, construímos uma lista de hosts a partir desses Ingresses. Observe que pode haver vários hosts por Ingress, então essa expressão contém um array de arrays (o que é uma limitação atual da linguagem CEL):
variables:
- name: knownHosts
expression: |
variables.knownIngresses.map(i, i.spec.rules.map(r, r.host))
No entanto, isso não cuida das operações de atualização corretamente; para isso, precisamos remover o objeto atual e extrair os hosts dos Ingresses restantes.
Podemos fazer isso com um filter() no objeto atual em object.
Com isso, as operações de atualização são verificadas corretamente. Isso também significa que a política relatará corretamente os resultados para o Scanner de Auditoria. Ela ficará assim :
variables:
- name: knownHosts
expression: |
variables.knownIngresses
.filter(i, (i.metadata.name != object.metadata.name) && (i.metadata.namespace != object.metadata.namespace))
.map(i, i.spec.rules.map(r, r.host))
Também precisamos de uma lista de hosts na solicitação de Ingress atual para comparar :
variables:
- name: desiredHosts
expression: |
object.spec.rules.map(r, r.host)
Com essas 2 variáveis, podemos fazer uma interseção de conjuntos entre os hosts conhecidos e os hosts desejados, e se houver algum, rejeitamos :
validations:
- expression: |
!variables.knownHost.exists_one(hosts, sets.intersects(hosts, variables.desiredHosts))
message: "Cannot reuse a host across multiple ingresses"
Colocando tudo junto, a política fica da seguinte forma :
variáveis: +
- name: knownIngresses +
expression: | +
kw.k8s.apiVersion("networking.k8s.io/v1").kind("Ingress").list().items +
- name: knownHosts +
expression: | +
variables.knownIngresses +
.filter(i, (i.metadata.name != object.metadata.name) && (i.metadata.namespace != object.metadata.namespace)) +
.map(i, i.spec.rules.map(r, r.host)) +
- name: desiredHosts +
expression: | +
object.spec.rules.map(r, r.host) +
validações: +
- expression: | +
!variables.knownHosts.exists_one(hosts, sets.intersects(hosts, variables.desiredHosts)) +
message: "Não é possível reutilizar um host em vários Ingresses"
Deploying the policy
As normal, we can deploy our policy by instantiating its manifest:
$ kubectl apply -f ./cel-policy-example.yaml
Agora podemos testá-lo instanciando Ingresses. O primeiro terá sucesso, pois não há outro direcionamento para esse host:
$ kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-host-foobar-1
spec:
rules:
- host: "foo.bar.com"
http:
paths:
- pathType: Prefix
path: "/bar"
backend:
service:
name: service1
port:
number: 80
EOF
Mas o segundo resultará em uma rejeição:
$ kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-host-foobar-2
spec:
rules:
- host: "foo.bar.com"
http:
paths:
- pathType: Prefix
path: "/foo"
backend:
service:
name: service2
port:
number: 80
EOF
Error from server: error when creating "STDIN":
admission webhook "clusterwide-unique-ingress.kubewarden.admission" denied the request:
Cannot reuse a host across multiple ingresses