infrastructure-as-code
format
cloud
region
# ================================================================
# Attack path: Container supply chain → host root
# Difficulty: hard · Cloud: multi · Est. time: 60 min
#
# Starting position: Anonymous internet user.
# Objective: Obtain root on a Kubernetes node by poisoning the container image the cluster pulls.
#
# Playbook:
# 1. Discovers the public registry — Shodan, organisation's GitHub Actions logs, or a leaked Dockerfile.
# exploits: REG-001
# 2. Anonymously pushes a backdoored image at the same tag the cluster pulls. Scan-on-push is disabled, so no alarm fires.
# exploits: REG-001, REG-004
# 3. Waits for the next deployment (or triggers a rollout). The pod runs with `privileged: true` and `hostPath: /` mounted read-write.
# exploits: K8S-101, K8S-108
# 4. Backdoor sees `/host`, runs `chroot /host /bin/bash`, drops a persistent SSH key — root on the node.
# exploits: K8S-108
#
# Cleanup: terraform destroy -auto-approve (or: aws cloudformation delete-stack)
# ================================================================
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
random = { source = "hashicorp/random", version = "~> 3.6" }
kubernetes = { source = "hashicorp/kubernetes", version = "~> 2.0" }
}
}
provider "aws" {
region = "us-east-1"
}
resource "random_id" "suffix" {
byte_length = 4
}
# Configure the kubernetes provider against your EKS cluster before applying pod / RBAC resources:
# provider "kubernetes" {
# config_path = "~/.kube/config"
# }
# Public registry
# vulnerabilities: REG-001, REG-004
resource "aws_ecr_repository" "ctr_public_registry" {
name = "vbuild-public-registry"
image_tag_mutability = "MUTABLE"
image_scanning_configuration {
scan_on_push = false
}
}
resource "aws_ecr_repository_policy" "ctr_public_registry" {
repository = aws_ecr_repository.ctr_public_registry.name
policy = jsonencode({
Version = "2012-10-17",
Statement = [{
Sid = "AllowAll",
Effect = "Allow",
Principal = "*",
Action = [
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
]
}]
})
}
# Privileged Kubernetes pod
# vulnerabilities: K8S-101, K8S-108, K8S-115
# Requires a kubernetes provider configured against the cluster.
resource "kubernetes_manifest" "ctr_priv_pod" {
manifest = {
apiVersion = "v1"
kind = "Pod"
metadata = {
name = "vbuild-priv-pod"
namespace = "default"
}
spec = {
hostPID = true
containers = [{
name = "priv"
image = "alpine:3.19"
command = ["sleep", "infinity"]
securityContext = {
privileged = true
}
volumeMounts = [{
name = "host-root"
mountPath = "/host"
}]
}]
volumes = [{
name = "host-root"
hostPath = { path = "/" }
}]
}
}
}
# Default ServiceAccount → cluster-admin (K8S-115).
resource "kubernetes_manifest" "ctr_priv_pod_binding" {
manifest = {
apiVersion = "rbac.authorization.k8s.io/v1"
kind = "ClusterRoleBinding"
metadata = { name = "vbuild-default-cluster-admin" }
roleRef = {
apiGroup = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = "cluster-admin"
}
subjects = [{
kind = "ServiceAccount"
name = "default"
namespace = "default"
}]
}
}
intentionally vulnerable. Apply only in an isolated sub-account / project, time-boxed and tagged. Never deploy on top of production.