2. 环境搭建:Docker靶场环境搭建、Jenkins CI/CD环境配置、GitLab仓库配置、Kubernetes集群部署
说实话,凭据注入这个攻击面,光讲理论是没用的。你得亲手搭一套环境,看着凭据怎么在流水线里流转,才能理解漏洞到底出在哪。这一章,我就带你把这套「靶场」搭起来。
我个人习惯把环境拆成四个部分:Docker 做底层容器、GitLab 存代码和凭据、Jenkins 跑 CI/CD 流水线、Kubernetes 做编排。你想想看,这正好是一条完整的攻击链路。
核心思路:所有组件都跑在 Docker 里,方便重置和销毁。生产环境别这么干,但做靶场,越简单越好。
2.1 Docker 靶场环境搭建
我习惯用 docker-compose 一把梭。你想想看,三个服务写在一个文件里,一条命令全拉起来,多省事。
先创建一个项目目录:
mkdir -p ~/cred-injection-lab && cd ~/cred-injection-lab
然后写 docker-compose.yml。嗯,这里要注意版本和端口映射,别跟本地服务冲突了。
version: '3.8'
services:
gitlab:
image: gitlab/gitlab-ce:15.11.13-ce.0
hostname: gitlab.local
ports:
- "8080:80"
- "2222:22"
volumes:
- ./gitlab/config:/etc/gitlab
- ./gitlab/logs:/var/log/gitlab
- ./gitlab/data:/var/opt/gitlab
environment:
GITLAB_ROOT_PASSWORD: "Passw0rd!2024"
jenkins:
image: jenkins/jenkins:2.440.3-lts-jdk17
ports:
- "9090:8080"
- "50000:50000"
volumes:
- ./jenkins/home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
k8s-control:
image: kindest/node:v1.27.3
privileged: true
ports:
- "6443:6443"
小技巧:GitLab 第一次启动要等 3-5 分钟,别急。你可以用 docker logs -f gitlab 盯着日志,看到 "GitLab is ready!" 就说明好了。
启动命令很简单:
docker-compose up -d
等所有容器都变成 healthy 状态,环境就绪了。我个人习惯用 docker-compose ps 检查状态。
2.2 GitLab 仓库配置
GitLab 起来之后,先登录 http://localhost:8080,用 root 和刚才设的密码进去。
接下来我们要创建一个项目,专门用来演示凭据注入。我建议你创建一个 私有项目,别让无关的人看到。
- 点击「Create a project」→「Create blank project」
- 项目名称填
cred-injection-demo - 可见级别选 Private
- 初始化仓库时勾选「Initialize repository with a README」
项目建好后,我们要配置 CI/CD 变量。这是凭据注入的关键入口。
| 变量名 | 变量值 | 保护级别 | 掩码 |
|---|---|---|---|
DB_PASSWORD |
SuperSecret!2024 |
受保护分支 | 是 |
API_TOKEN |
glpat-xxxxxxxxxxxx |
所有分支 | 否 |
SSH_PRIVATE_KEY |
-----BEGIN OPENSSH PRIVATE KEY-----... |
受保护分支 | 是 |
注意:掩码(Masked)变量在 CI 日志里会显示为 ****,但如果你在脚本里 echo 出来,它还是会暴露。我曾经见过一个团队,掩码变量被 echo $VAR | base64 绕过了。
配置路径:项目 → Settings → CI/CD → Variables → Add variable。
然后写一个简单的 .gitlab-ci.yml,触发流水线:
stages:
- build
- deploy
build-job:
stage: build
script:
- echo "Building with DB_PASSWORD=$DB_PASSWORD"
- echo "API_TOKEN=$API_TOKEN"
only:
- main
deploy-job:
stage: deploy
script:
- echo "Deploying to K8s..."
- echo "Using SSH key length: ${#SSH_PRIVATE_KEY}"
only:
- main
你想想看,这个流水线直接把凭据打印到日志里了。这就是典型的凭据泄露。
2.3 Jenkins CI/CD 环境配置
Jenkins 的初始密码在容器日志里:
docker logs jenkins 2>&1 | grep "Initial admin password"
拿到密码后,访问 http://localhost:9090,解锁 Jenkins。我建议你安装「推荐的插件」,省得后面缺东西。
接下来我们要做三件事:
- 安装必要插件:GitLab、Kubernetes、Credentials Binding
- 配置 GitLab 连接:系统管理 → 系统配置 → GitLab → 添加 API Token
- 创建凭据:用于演示凭据注入
创建凭据的路径:系统管理 → Manage Credentials → 全局 → Add Credentials。
| 凭据 ID | 类型 | 值 | 用途 |
|---|---|---|---|
gitlab-token |
GitLab API Token | glpat-xxxxxxxx | 触发 GitLab Webhook |
k8s-config |
Secret file | kubeconfig 文件 | 连接 K8s 集群 |
docker-hub |
Username with password | dockerhub 账号 | 推送镜像 |
然后创建一个 Pipeline 任务,配置 GitLab 仓库地址和 Webhook。嗯,这里要注意 Jenkinsfile 的写法:
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scmGit(
branches: [[name: '*/main']],
userRemoteConfigs: [[url: 'http://gitlab.local/root/cred-injection-demo.git']]
)
}
}
stage('Build') {
steps {
withCredentials([string(credentialsId: 'gitlab-token', variable: 'TOKEN')]) {
sh 'echo "Using token: $TOKEN"'
}
}
}
}
}
关键点:withCredentials 会把凭据注入到环境变量里。如果脚本里不小心 echo 出来,凭据就暴露了。我在项目中遇到过好几次这种问题。
2.4 Kubernetes 集群部署
本地跑 K8s,我推荐用 kind(Kubernetes in Docker)。轻量、快速、好重置。
先安装 kind:
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind
然后创建一个集群配置文件 kind-config.yaml:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30080
hostPort: 30080
- role: worker
- role: worker
创建集群:
kind create cluster --config kind-config.yaml --name cred-lab
等集群就绪后,验证一下:
kubectl cluster-info --context kind-cred-lab
kubectl get nodes
接下来,我们要创建一个 Namespace 和 Secrets,模拟生产环境:
kubectl create namespace cred-injection
kubectl -n cred-injection create secret generic app-secrets \
--from-literal=db-password='ProdDB!2024' \
--from-literal=api-key='sk-prod-xxxxx'
避坑指南:我曾经见过有人把 Secrets 直接写在 YAML 里提交到 Git 仓库。千万别这么干!Secrets 的 value 是 base64 编码,不是加密。随便一个 echo xxx | base64 -d 就能解开。
最后,把 Jenkins 和 K8s 连起来。在 Jenkins 里配置 K8s 云:系统管理 → 系统配置 → 云 → 添加 Kubernetes。填上 K8s API 地址和凭据。
这样,整套环境就搭好了。你想想看,从 GitLab 的 CI 变量,到 Jenkins 的凭据,再到 K8s 的 Secrets,凭据在这条链路上到处流转。后面的章节,我们就拿这套环境做攻击和防御演练。