Kubernetes Goat 场景 12 实战:通过容器环境变量获取 Kubernetes Secret 注入的敏感凭据
2026/9/17 19:30:27 网站建设 项目流程

Kubernetes Goat 场景 12 实战:通过容器环境变量获取 Kubernetes Secret 注入的敏感凭据

【免费下载链接】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(一个"设计上就脆弱"的 Kubernetes 靶场)中的场景 12「Gaining environment information(获取环境信息)」展开。你将学会从一个容器内的 Web 终端出发,用cat /proc/self/cgroupcat /etc/hostsmountprintenv等标准 Linux 手段完成一次完整的信息枚举,最终定位到通过secretKeyRef注入容器环境变量的 Kubernetes Secret 凭据(vault key),并从源码与清单层面理解"把密钥放环境变量"这一常见反模式的风险本质。

场景背景与目标

在真实的生产环境中,绝大多数计算实例在运行应用时都会把敏感信息(secrets、API keys、配置值等)存放在环境变量里。Kubernetes 场景 12 正是模拟了这种典型做法:团队把 Kubernetes Secret(本例中是一把 vault 的 API key)以环境变量的形式注入 Pod。文档给出的背景判断是——如果攻击者找到应用漏洞(如 RCE 远程代码执行或命令注入),那么这些密钥基本宣告失守。

场景的核心设定如下(对应 场景 12 指南文档 与 集群内置引导页):

  • 故事线:Kubernetes 中的每个环境都有大量信息可被分享——secrets、API keys、configs、services 等,任务就是"找到那把 vault key"。
  • 目标(Goal):拿到k8s_goat_flag的 flag 值即完成场景,且文档明确提示"这可以通过多种方式达成"。
  • 提示(Hint):如果不知道环境变量存在哪里,回到标准 Linux 工具,比如env
  • 完成后的收获:1)如何探索并分析容器环境变量;2)如何获取容器内的敏感信息。
  • 入口:启动靶场后访问http://127.0.0.1:1233

场景环境架构:127.0.0.1:1233 背后是什么

读懂场景的前提是弄清楚http://127.0.0.1:1233到底指向哪个工作负载、flag 又藏在哪里。从仓库源码可以确认以下链路:

1. 端口 1233 由访问脚本转发到 system-monitor Pod。在 access-kubernetes-goat.sh 中,脚本通过kubectl get pods -l "app=system-monitor"找到 Pod,并执行:

kubectl port-forward $POD_NAME --address 0.0.0.0 1233:8080

也就是说本地 1233 端口最终打到 Pod 内的 8080 端口。

2. 8080 端口是一个"免密 Web Shell"。infrastructure/system-monitor/Dockerfile 基于ubuntu:noble,安装了htopcurl等工具,并下载 gotty(一个把终端共享到浏览器的工具),容器入口为:

EXPOSE 8080 CMD [ "gotty", "-w", "bash" ]

gotty -w bash会在 8080 端口起一个 Web 页面,任何人打开页面就能获得一个交互式 bash——这正是场景 12 的"入口"。它模拟的是攻击者已经拿到容器内执行权(例如通过 RCE)之后的视角。

3. flag 的来源:secretKeyRef 注入的环境变量。在 scenarios/system-monitor/deployment.yaml 中定义了 Secret:

apiVersion: v1 kind: Secret metadata: name: goatvault namespace: default type: Opaque data: k8sgoatvaultkey: azhzLWdvYXQtY2QyZGEyNzIyNDU5MWRhMmI0OGVmODM4MjZhOGE2YzM=

Deployment 通过valueFrom.secretKeyRef把它注入容器:

env: - name: K8S_GOAT_VAULT_KEY valueFrom: secretKeyRef: name: goatvault key: k8sgoatvaultkey

(见 deployment.yaml 第 47-52 行)对清单中的 base64 值解码即可验证 flag:

echo 'azhzLWdvYXQtY2QyZGEyNzIyNDU5MWRhMmI0OGVmODM4MjZhOGE2YzM=' | base64 -d # 输出: k8s-goat-cd2da27224591da2b48ef83826a86c3

这串k8s-goat-cd2da27224591da2b48ef83826a86c3就是本场景要你在容器内"找到"的 vault key 值。

4. 顺带一提的额外风险面。从源码结构看,同一个 system-monitor Pod 还声明了hostPID: truehostIPC: trueprivileged: true,并把宿主机根目录hostPath: /挂载到/host-system(见 deployment.yaml 第 25-46 行)。这些配置服务于仓库中后续的"容器逃逸"相关场景;在场景 12 里你不需要用到它们,但这也提醒读者:真实环境中一个既暴露了 Web Shell、又带有特权容器配置的 Pod,风险是叠加的。

如何把环境跑起来:使用仓库根目录的 setup-kubernetes-goat.sh 部署所有场景清单(其中 第 85 行 部署了scenarios/system-monitor/deployment.yaml),再运行 access-kubernetes-goat.sh 建立本地端口转发,然后浏览器访问http://127.0.0.1:1233即可进入 Web 终端;访问http://127.0.0.1:1234则是集群内的 Kubernetes Goat 主页(goat-home),本场景的任务说明页由 infrastructure/goat-home/home/content/scenario-12.md 渲染。

实战演练:容器内信息枚举(Method 1)

进入 Web Shell 后,场景指南给出的方法是"把容器探索一遍"。以下命令与 场景 12 指南 中的 Solution & Walkthrough 一一对应。

1. 确认自己是否在容器里:cat /proc/self/cgroup

cat /proc/self/cgroup

输出中的 cgroup 层级路径(docker/containerd 风格的层级与容器 ID)能直接暴露容器运行时信息,帮助判断隔离边界。

2. 查看容器主机的基础信息

cat /etc/hosts

/etc/hosts会显示 Pod 的容器 ID、主机名与网络配置,是确认"我正处在一个被编排过的环境里"的常用手段。

3. 查看挂载信息

mount

mount输出可以揭示容器看到了哪些文件系统挂载(对于 system-monitor 这类把宿主机根目录挂进来的 Pod,这里的信息量尤其大,也印证了清单中的hostPath配置)。

4. 探索文件系统

ls -la /home/

逐步翻看目录结构,了解容器内有哪些账号、文件与工具,判断还有哪些入口点。

5. 关键一击:printenv列出全部环境变量

printenv

这是场景 12 的核心命令。printenv会输出当前进程的全部环境变量,其中就包含 Deployment 通过secretKeyRef注入的K8S_GOAT_VAULT_KEY——也就是那把 vault key(flag 值k8s-goat-cd2da27224591da2b48ef83826a86c3)。除此之外,Kubernetes 还会自动注入一批环境变量(服务发现变量、KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT等 API Server 地址等),这些同样是攻击者做横向移动的线索。

拿到该值即完成场景。文档提示"可以以多种方式找到它",从仓库证据可以印证其中两种:其一就是上面的容器内枚举;其二是不进容器、直接从集群侧读取——kubectl get secret goatvault并对 base64 值解码,结果与容器内看到的一致。这恰恰说明:当凭据的读取权限(容器内进程或集群 API 权限)被突破后,"注入方式"本身并不提供额外保护。

为什么环境变量是"弱防线":风险分析与加固建议

场景 12 的价值在于演示了一条非常短的攻击链:能执行任意命令 = 能读到全部环境变量 = 能拿到密钥。从本仓库的实现看,其根因可以归纳为几点:

  1. 环境变量对容器内任何进程可见。主进程、它 fork 出的任何子进程、乃至通过/proc/1/environ这类内核接口,都可以读到同一份环境变量。一个无密码的 gotty Web Shell 足以演示这一点——场景中甚至没有 RCE,"拿到 shell"这一步被靶场直接送给了玩家。
  2. secretKeyRef 只保护"清单里的值",不保护"运行时的值"。使用secretKeyRef时,kubectl get pod -o yaml不会显示密钥明文,但任何已执行进容器的进程都能直接printenv拿到明文,Pod 清单层面的"隐藏"因此形同虚设。
  3. 凭据生命周期与注入方式错配。环境变量在容器创建时一次性注入、进程存活期间常驻内存,无法按次读取、无法细粒度授权、也无法在进程间共享之外被其他进程看见。

对应的加固方向(与本场景的风险点逐条对应):

  • 避免把长期有效的 API key 放进环境变量:优先使用以文件形式挂载的 Secret Volume(可控制文件权限),或改用外部密钥管理系统按需注入。场景 12 指南的 References 即指向了 Kubernetes Secrets 概念与 Vault Agent 以 sidecar 方式注入密钥的模式——后者正是"短时效、按需获取"的典型代表。
  • 收紧能"进入容器"的一切入口:无认证的 Web 终端、调试 sidecar、宽松的exec权限都会把环境变量直接暴露给攻击者;RBAC 应按最小权限授予(本仓库另有场景演示了服务账号被赋予过宽权限导致 Secret 可被 API 读取的情形,可对照 scenarios/hunger-check/deployment.yaml 中的secret-readerRole 理解权限模型)。
  • 消除叠加风险面:本例 Pod 同时带有privileged: true与宿主机根目录挂载,环境变量泄漏只是第一层损失;对监控类负载应使用只读根文件系统、非特权容器与最小化命名空间挂载。

关键文件索引

内容仓库相对路径
场景 12 指南(Overview/Goal/Hints/Solution & Walkthrough)guide/docs/scenarios/scenario-12/scenario-12.md
集群内置场景说明页(1234 主页展示的任务文案)infrastructure/goat-home/home/content/scenario-12.md
场景清单:Secret goatvault + secretKeyRef 环境变量注入scenarios/system-monitor/deployment.yaml
Web Shell 镜像(gotty -w bash,EXPOSE 8080)infrastructure/system-monitor/Dockerfile
部署脚本(第 85 行部署 system-monitor)setup-kubernetes-goat.sh
端口转发脚本(1233:8080 指向 system-monitor Pod)access-kubernetes-goat.sh

适用前提说明:以上所有步骤与端口映射以当前仓库的脚本与清单为准(本地 1233 端口转发依赖access-kubernetes-goat.sh先于浏览访问运行;flag 值取自当前清单中的 base64 数据)。靶场环境仅应在隔离的实验集群中部署,请勿将其中任何"脆弱配置"带入生产。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询