
Kubernetes Goat 私有容器镜像仓库攻击实战利用 Registry HTTP API v2 拉取镜像元数据与敏感凭证【免费下载链接】kubernetes-goatKubernetes Goat is a Vulnerable by Design cluster environment to learn and practice Kubernetes security using an interactive hands-on playground 项目地址: https://gitcode.com/GitHub_Trending/ku/kubernetes-goat本篇基于 Kubernetes Goat 的 Scenario 7「Attacking private registry」演示一个典型的企业级误配置攻击链路当组织内部私有容器镜像仓库基于 Docker Registry v2未启用认证且被暴露时攻击者如何仅凭标准 HTTP API 枚举全部镜像、读取 manifest 中的环境变量与元数据从而窃取内置在镜像中的 API Key / FLAG。读完后你将掌握 Registry HTTP API v2 的核心查询端点、镜像 manifest 的存储结构以及该场景在仓库中对应的部署与漏洞成因源码。场景背景私有镜像仓库为什么会成为攻击目标容器镜像仓库registry是所有容器镜像的推送与拉取中枢。多数组织都有自己私有的 registry通常假设「内部仓库只有内部人员能访问」于是开发者把 API Key、Token、内部配置等敏感信息直接写进镜像例如通过ENV、ARG或层文件。文档原文指出容器早期曾有一起著名案例——Vine后被 Twitter 收购因 registry 简单误配置导致整个产品源代码泄露今天同样的问题在启用认证的 registry 上依然大量存在只是攻击者需要结合其他漏洞链来绕过认证。本场景的威胁模型如下来自场景文档 scenario-7.md 的 Overview每个组织通常有自己的私有 registry有时会被误配置为公开/开放状态开发者误以为内部 registry 天然安全把敏感信息塞进容器镜像攻击者一旦拿到 registry 的可达端点即可枚举镜像并读取其全部元数据。场景结束时你将学会三件事如何与 Docker 容器 registry 的 REST API 交互如何内省introspectregistry API、容器镜像与 manifest容器元数据是如何存储的、又是如何与镜像层layer产生交互的。场景目标获取私有 registry 镜像中的k8s-goat-FLAG值。环境准备poor-registry 是如何被部署进集群的本场景的靶机是一个名为poor-registry的 Deployment Service定义在 scenarios/poor-registry/deployment.yamlapiVersion: apps/v1 kind: Deployment metadata: name: poor-registry-deployment namespace: default spec: selector: matchLabels: app: poor-registry template: metadata: labels: app: poor-registry spec: containers: - name: poor-registry image: madhuakula/k8s-goat-poor-registry resources: limits: memory: 50Mi cpu: 30m ports: - containerPort: 5000 --- apiVersion: v1 kind: Service metadata: name: poor-registry-service namespace: default spec: ports: - protocol: TCP port: 5000 targetPort: 5000 selector: app: poor-registry部署入口在根目录的 setup-kubernetes-goat.sh其中一行kubectl apply -f scenarios/poor-registry/deployment.yaml负责把 registry 拉起。随后运行 access-kubernetes-goat.sh脚本会等待apppoor-registry的 Pod 就绪后执行kubectl port-forward $POD_NAME --address 0.0.0.0 1235:5000于是本地的http://127.0.0.1:1235就对应了集群内的 registry 5000 端口。场景文档要求从访问入口 http://127.0.0.1:1235 开始本场景见场景首页 scenario-7/index.md 的说明需要说明的前提本文所有端点与操作均针对该「Vulnerable by Design」环境本地 Kind/k3s 集群 port-forward真实环境中的私有 registry 往往在 VPC 内网需要先通过其他漏洞链如集群内横向移动、SSRF获得可达性——场景文档也在 Method 一节特别注明了这一点。攻击链第一步向 Registry 发送 v2 握手请求Docker Registry 提供一套标准化的 HTTP APIRegistry HTTP API V2。最简单的验证手段是对/v2/发送请求若 registry 无认证会直接返回200 OK若启用了认证则返回401 Unauthorized并携带 WWW-Authenticate 头curl http://127.0.0.1:1235/v2/这一步在真实渗透中的意义是指纹识别确认目标确实是一个 Docker Registry v2 服务并顺便判断它是否要求认证。本场景中由于 registry 完全未配置认证任何匿名请求都会成功。攻击链第二步用 _catalog 枚举全部镜像/v2/_catalog端点返回仓库中所有 image 的列表即 repository 名。这正是私有 registry 误配置最致命的地方——一次请求即可完整枚举企业内部的全部镜像资产curl http://127.0.0.1:1235/v2/_catalog从源码结构看/v2/_catalog的响应内容完全取决于 registry 的存储后端目录树。在 infrastructure/poor-registry/Dockerfile 中可以看到FROM registry:2 LABEL MAINTAINERMadhu Akula INFOKubernetes Goat WORKDIR /var/custom/registry/docker/registry COPY v2.tar.gz /tmp/v2.tar.gz COPY config.yml /etc/docker/registry/config.yml RUN tar -xf /tmp/v2.tar.gz -C /var/custom/registry/docker/registry/ \ rm /tmp/* CMD [ registry, serve, /etc/docker/registry/config.yml ]即镜像基于官方registry:2并把一个预制的v2.tar.gz解压到/var/custom/registry/docker/registry/。这个 tar 包就是预先 push 好的镜像存储数据filesystem 存储布局其中包含本场景要攻击的仓库madhuakula/k8s-goat-users-repo。所以_catalog能返回该镜像本质上是存储目录中已存在对应的 repository 元数据。攻击链第三步读取 manifest挖掘环境变量中的敏感信息拿到仓库名后用 manifest 端点查看指定 tag 的镜像元数据。manifest 中包含 image configurationdigest、环境变量 ENV、EXPOSE、CMD 等以及每个 layer 的 digestcurl http://127.0.0.1:1235/v2/madhuakula/k8s-goat-users-repo/manifests/latest这一步对应的目标镜像就是 infrastructure/users-repo/DockerfileFROM python:alpine LABEL MAINTAINERMadhu Akula INFOKubernetes Goat ENV API_KEYk8s-goat-cf658c56a501385205cc6d2dafee8fc1 COPY app.py /app.py CMD [ python, /app.py ]关键点ENV API_KEY...在构建时会被写入镜像的配置段config而配置段是 manifest 体系的一部分会随 manifest 一起被 registry 存储并可被任何有 pull 权限的客户端读取。也就是说不需要运行容器、不需要拉取任何 layer 内容仅凭 manifest 就能拿到密钥。这正是场景文档提示「Checkout the manifests file for all the metadata, variables, information and who knows maybe flag as well」的原理。因此可以进一步用grep直接过滤出 ENV 相关字段快速定位 API Key 与 FLAGcurl http://127.0.0.1:1235/v2/madhuakula/k8s-goat-users-repo/manifests/latest | grep -i env从返回的 JSON 中可以看到API_KEY环境变量的值其中包含的k8s-goat-前缀密钥即为本场景要提交的k8s-goat-FLAG。至此攻击链闭环/v2/握手 →/v2/_catalog枚举 →/manifests/tag读取配置 → 提取内置凭证。漏洞成因源码级剖析为什么这个 registry 一攻就破结合仓库配置可以从三个层面解释为什么这个 registry 是「poor」的未启用任何认证。infrastructure/poor-registry/config.yml 是 registry 的完整运行配置version: 0.1 log: fields: service: registry storage: cache: blobdescriptor: inmemory filesystem: rootdirectory: /var/custom/registry http: addr: :5000 headers: X-Content-Type-Options: [nosniff] health: storagedriver: enabled: true interval: 10s threshold: 3配置里没有auth段无htpasswd、无 token service、无 OIDC也没有 TLS 证书配置。Docker Registry 在缺省配置下就是完全匿名的GETcatalog/manifest/blobs与POST/PUTpush对所有人开放。这意味着不仅本文的只读枚举可行甚至匿名 push 覆盖镜像供应链投毒的前置条件在权限层面也是允许的——场景文档的 tip 也提到「in some cases, you can even push the image to the registry based on the permissions and privileges」。存储根目录直接落在容器内文件系统rootdirectory: /var/custom/registry且通过v2.tar.gz预置了目标镜像。这模拟了企业内网 registry「里面本来就存着所有内部镜像」的真实状态一旦端口可达等于把整个镜像资产清单直接交到了访问者手里。敏感信息以 ENV 形式固化在镜像里。infrastructure/users-repo/Dockerfile 第 4 行把API_KEY写死在构建参数中而该应用的运行时逻辑infrastructure/users-repo/app.py只是os.environ[API_KEY]读取并调用 GitHub API。这是「密钥烘焙进镜像」这一普遍反模式的典型示范镜像一旦进入 registry密钥就永久留在其配置元数据里即使之后删除容器或修改代码旧 tag 的 manifest 仍可通过 registry API 读到。延伸实战与防御建议场景文档在 walkthrough 结尾给出了一条延伸 tip可以顺着这条攻击链继续做两件事把镜像拉到本地完整分析既然_catalog和manifests都匿名可用docker pull配合docker login/DOCKER_CONFIG指向该 registry 或直接 pull 未认证仓库即可下载完整镜像逐层docker history、解压 layer tar 包审计文件、脚本与硬编码凭证比只读 manifest 能发现更多内容验证 push 权限构建一个本地镜像并docker push到127.0.0.1:1235的测试仓库验证匿名写入是否成立从而评估供应链篡改风险。对应的防御方向与上述成因逐条对应强制认证为 registry 配置auth: htpasswd或对接 token/OIDC 服务并配合网络层防火墙、Kubernetes NetworkPolicy、Ingress 白名单确保 registry 仅对内网特定网段可达启用 TLShttp: addr配置中补充tls.certificate/key避免内网明文传输与中间人风险网络隔离私有 registry 不应暴露到集群外若必须通过 Service 暴露应限制 NodePort/LoadBalancer 或仅在 Ingress 后挂认证不要把密钥写进镜像凭证应通过 Secret、Vault 或运行时注入获取而不是ENV同时定期用镜像扫描工具审计存量镜像的 layer 与 manifest 配置段清理历史 tag 中的残留密钥。小结与仓库文件索引本场景用最短的攻击链讲清了私有 registry 误配置的危害无认证 端口可达 全量镜像资产暴露 manifest 元数据含 ENV 凭证裸奔。核心命令仅三条 curl但背后涉及 Registry HTTP API v2 的握手、catalog 枚举与 manifest 配置读取三个知识点且都能从仓库源码中找到成因。关键文件索引相对仓库根目录场景文档guide/docs/scenarios/scenario-7/scenario-7.md目标服务部署scenarios/poor-registry/deployment.yaml漏洞 registry 镜像构建infrastructure/poor-registry/Dockerfile、infrastructure/poor-registry/config.yml内置密钥的受害镜像infrastructure/users-repo/Dockerfile、infrastructure/users-repo/app.py环境部署与端口转发脚本setup-kubernetes-goat.sh、access-kubernetes-goat.sh【免费下载链接】kubernetes-goatKubernetes Goat is a Vulnerable by Design cluster environment to learn and practice Kubernetes security using an interactive hands-on playground 项目地址: https://gitcode.com/GitHub_Trending/ku/kubernetes-goat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考