Pare de sofrer com REGO, vá de YAML
A criação de políticas de Segurança no Kubernetes é uma busca incessante da área de Segurança para evitar que incidentes exponham os negócios a riscos, como o de vazamento de dados.Até aí, a gente sabe que o negócio é aplicar políticas de segurança nos clusters Kubernetes para impedir ao máximo qualquer exposição a riscos e, no mercado, há várias alternativas de Security Policies para isso: OPA, Gatekeeper, Syra, AWS Opa, Azure Policy e etc.No entanto, o desafio para nós, kuberneteiros de plantão, está em implementar e manter essas políticas na linguagem em que estão escritas, REGO. Por estarmos acostumados a trabalhar com YAML, ferramentas que usam uma nova linguagem, nesse caso REGO, só dificultam a nossa vida! É como dar um passo para trás no que que estamos fazendo para aprender uma nova linguagem e, daí, aplicá-la nas políticas de segurança do cluster K8s.Cansado de sofrer com isso, fui atrás de uma saída e achei o Kyverno. O Kyverno é um controller de Kubernetes capaz de criar a sua própria política de segurança com YAML.Ainda, se mudar de cloud provider, as suas regras já farão parte de seu CI/CD ou de um backup velero ou, no pior cenário, nos YAMLS files do seu diretório escondido no seu drive. Em resumo, é fácil de escrever, entender, ficam num único lugar e podem migrar de cloud provider ou, até mesmo, para on-premise, evitando o lock-in com as operadoras cloud.Você consegue quase tudo com o Kyverno, veja só:
Bloquear remoção de resources, principalmente, o próprio Kyverno;
Rastrear o que estão executando que possa infringir na segurança dos nós;
Automatizar e policiar a criação de labels pra cobrar $$ dos times, quando for um K8s multi tenant;
Automatizar a criação de Network Policy e quem pode mexer nelas;
Bloquear o uso de recursos específicos, por exemplo, só quero que subam Ingress usando meu ingress-nginx ou o meu kong e o traefik são só do time X;
Automagicamente saber que qualquer deploy tem que ter um mínimo de:. recursos de cpu/memória. labels. réplicas
Distribuir secrets e configmaps para qualquer namespace criado;
Restringir uso de services LoadBalancer e/ou NodePort;
Impossibilitar a galera de subir coisas no namespace Default;
Forçar todo recurso a usar tag nas imagens e sempre do mesmo registry;
Aplicar NetworkPolicy quando um novo namespace é criado;
Criar um namespace, gerar todas as políticas e gerar um report do que é aplicado.
Ainda, dá para gerar relatórios de infração, inspeção e aplicação — tudo em YAML — para você extrair com aquele “-o json” e brincar de converter pra HTML. Tem CLI pra quem gosta também.Instalando o Kyverno
Quer instalar o Kyverno, brincar com políticas iniciais e ver como funciona?
A instalação não é intrusiva! Nada vai parar, nenhum erro vai ser gerado pela instalação e não há regra default que force qualquer política. Isso é, pode aplicar o Kyverno no seu cluster de produção, pois ele vai gerar no máximo policies reports indicando onde existe problema a ser tratado, com base nas regras default que não interferem, só aferem. Quer instalar o Kyverno, brincar com políticas iniciais e ver como funciona?Apenas atente-se para o fato de que quanto mais workloads você tem em seu cluster, mais recursos de cpu e memória seu Kyverno vai precisar para analisar, gerar e manter políticas e reports. Se for seu caso, aumente esses valores no deploy do Kyverno.Vamos ao que interessa!Você vai precisar:
* kubectl
* helm => 3.23
* 1 cluster k8s
* git
* kyverno cli, https://kyverno.io/docs/kyverno-cli/ (opcional, só se quiser mesmo, para validar politicas, etc)$ helm repo add kyverno https://kyverno.github.io/kyverno/
$ helm repo update
$ helm install kyverno -n kyverno kyverno/kyverno --create-namespaceVerifique se o pod do Kyverno está instalado:$ kubectl get pod -n kyvernoNAME READY STATUS RESTARTS AGE
pod/kyverno-6868bc56fb-gfcqn 1/1 Running 0 114s
$
$ kubectl get cpolNAME BACKGROUND ACTION
disallow-add-capabilities true audit
disallow-host-namespaces true audit
disallow-host-path true audit
disallow-host-ports true audit
Disallow-privileged-containers true audit
disallow-selinux true audit
require-default-proc-mount true audit
restrict-apparmor-profiles true audit
restrict-sysctls true audit
$
$ kubectl get polr -AO “get pod” vai trazer seu pod; aguarde até estar “running”.A partir desse momento, o “get cpol” vai trazer as políticas aplicadas ao cluster, no âmbito de cluster.O “get polr -A” trará os reports por namespaces, se você tiver namespaces criados e com workloads em execução.Veja que todas as políticas criadas por default estão em audit na coluna action, ou seja, só auditam os workloads. A partir do momento em que se deseja que se apliquem e impeçam alguma execução ou configuração, basta alterar a regra validationFailureAction: enforce e isso impedirá o próximo pod de seguir “quebrando a política”.$ kubectl edit cpol disallow-add-capabilities
(...)
spec:
validationFailureAction: audit #ou enforce para forçar a regra
(...)Primeiro exemplo:Bloqueio de workloads sem label específica:$ cat require-pod-ns-svc-ing-label-required.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-certain-labels
spec:
validationFailureAction: audit
rules:
- name: validate-name-labels
exclude:
resources:
namespaces:
- kube-system
- app1
- workloads-x
match:
resources:
kinds:
- Pod
- Namespace
- Service
- Ingress
validate:
message: "The label `app.kubernetes.io/name` and is required."
pattern:
metadata:
labels:
app.kubernetes.io/name: "?*"
- name: validate-component-labels
exclude:
resources:
namespaces:
- kube-system
- app1
- workloads-x
match:
resources:
kinds:
- Pod
- Namespace
- Service
- Ingress
validate:
message: "The label `app.kubernetes.io/component` is required."
pattern:
metadata:
labels:
app.kubernetes.io/component: "?*"Aplique essa política:$ kubectl apply -f require-pod-ns-svc-ing-label-required.yamlVerifique nos logs do pod do Kyverno e nos objetos de ClusterPolicy:$ kubectl get cpolNAME BACKGROUND ACTION
disallow-add-capabilities true audit
disallow-host-namespaces true audit
disallow-host-path true audit
disallow-host-ports true audit
disallow-privileged-containers true audit
disallow-selinux true audit
require-default-proc-mount true audit
restrict-apparmor-profiles true audit
restrict-sysctls true audit
require-certain-labels true auditAqui, já se observa que nossa regra exigindo as labels informadas sejam aplicadas a qualquer workload em qualquer namespace, com exceção dos namespaces app1, kube-system e workloads-x.Crie um deploy de teste:$ cat web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
app.kubernetes.io/name: web
name: web
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
labels:
app: web
app.kubernetes.io/name: web
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}$ kubectl apply -f web.yamldeployment.apps/web createdPerceba aqui que só criei uma label app.kubernetes.io/name: web, o que não satisfaz na íntegra minha política recém-criada. Para visualizar as auditorias FAIL dos reports, execute:$ kubectl get polr -n default -o yaml | grep “status: fail” -B14
---
scored: true
status: pass
- message: 'validation error: The label`app.kubernetes.io/component`
is required. Rule validate-certain-labels[0] failed at path
/metadata/labels/app.kubernetes.io/component/.
Rule validate-certain-labels[1] failed at path /metadata/labels
/app.kubernetes.io/component/.'
policy: require-certain-labels
resources:
- apiVersion: apps/v1
kind: Deployment
name: web
namespace: default
uid: cbe8ecc1-71f8-4b2c-819d-59417039fc77
rule: validate-ccomponent-labels
scored: true
status: fail
(...)O policyReport vai mostrar o service kubernetes e o namespace default com a mesma falta de labels que indicamos na política. Se essa política estiver enforce, então será obrigatória a adição dessas labels nesses resources e o pod não será criado até ser resolvida essa pendência.Existem dezenas de outras políticas que podem ser aplicadas no quesito cluster, o que não te impede de aplicá-las somente a um namespace específico, usando o kind: ClusterPolicy ou para namespace, usando o Kind: Policy. Elas estão disponíveis em https://github.com/kyverno/policies.Uma que gosto bastante é a que limita a utilização de recursos e obriga todo pod a obedecer uma regra pré-definida de resources limits/requests:$ cat require-and-set-requests-limits.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-requests-limits
annotations:
policies.kyverno.io/title: Require Limits and Requests
policies.kyverno.io/category: Multi-Tenancy
spec:
validationFailureAction: audit
rules:
- name: validate-resources
exclude:
resources:
namespaces:
- linkerd
- kube-system
match:
resources:
kinds:
- Pod
validate:
message: "CPU and memory resource requests and limits are required."
pattern:
spec:
containers:
- resources:
requests:
memory: "<=1000Mi"
cpu: "<=500m"
limits:
memory: "<=2000Mi"
cpu: "<=1000m"
$
$ kubectl apply -f require-and-set-requests-limits.yamlCom isso, qualquer pod, em qualquer namespace, com exceção do Kube-system, terá que declarar a utilização de resources e, ainda, respeitar os limites para requests e limits. Como diria meu irmão: “existem mil maneiras de preparar Neston, invente a sua”.Baseando-se nos modelos e exemplos do repositório e na documentação, fica fácil criarmos as políticas que precisamos aplicar, sem precisar aprender uma nova linguagem ou nos debruçar sobre vários recursos do K8s para troubleshooting ou evolução.É isso aí, galera! Recomendo que corram pra se atualizar. Kyverno é uma maravilha e a curva de aprendizado é de algumas horas.Qualquer dúvida, sugestão ou crítica, podem me chamar: adonai@getup.io.