janebjobtech-cloud/janebjobtech-cloud-devsecops-container-pipeline-details
GitHub: janebjobtech-cloud/janebjobtech-cloud-devsecops-container-pipeline-details
这是一个基于Azure的自动化容器镜像安全扫描与推广流水线,解决容器部署中的安全合规问题。
Stars: 0 | Forks: 0
# 🔐 DevSecOps 容器镜像扫描与推广流水线
[](https://github.com/janebjobtech-cloud/devsecops-container-pipeline/actions)
[](https://azure.microsoft.com)
[](https://www.terraform.io)
[](https://github.com/aquasecurity/trivy)
[](LICENSE)
## 🚀 项目功能
本项目是一个基于 Microsoft Azure 端到端构建的**全自动 DevSecOps 容器镜像扫描与推广流水线**。每个组件均以代码形式预置,每个安全边界都在基础设施层面强制执行,每个进入生产环境的容器镜像都已自动完成扫描——审批环节无需人工干预,杜绝人为错误。
每次代码推送到 `main` 分支时,流水线会**自动执行四项任务**:
| 步骤 | 任务 | 具体内容 |
|------|-----|-------------|
| 1 | **构建** | Docker 构建容器镜像,并使用 Git SHA 标签将其推送到暂存仓库 |
| 2 | **扫描** | Trivy 根据国家漏洞数据库扫描镜像中的关键 CVE |
| 3 | **SBOM** | 生成 CycloneDX 和 SPDX 格式的软件物料清单(与扫描并行运行) |
| 4 | **推广** | 如果扫描通过,已扫描的精确镜像将通过 `az acr import` 复制到生产仓库 |
## 🏗️ 架构图
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ DEVELOPER WORKSTATION │
│ │
│ git push origin main ──────────────────────────────────────────────────► │
│ │
└────────────────────────────────────┬────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ GITHUB (janebjobtech-cloud) │
│ │
│ Repository: devsecops-container-pipeline │
│ ├── .github/workflows/container-pipeline.yml ◄── Pipeline Definition │
│ ├── app/ │
│ │ ├── app.py (Flask API) │
│ │ └── requirements.txt (pinned dependencies) │
│ ├── Dockerfile (secure build blueprint) │
│ ├── .trivyignore (formal exception register) │
│ └── infra/ (Terraform IaC) │
│ ├── main.tf │
│ ├── variables.tf │
│ ├── outputs.tf │
│ └── terraform.tfvars │
│ │
│ ┌─── GitHub Actions Runner ────────────────────────────────────────────┐ │
│ │ │ │
│ │ JOB 1: Build & Push to Staging │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ docker build -t demo-app:${GITHUB_SHA} . │ │ │
│ │ │ docker push acrstagingjaneburo.azurecr.io/... │ │ │
│ │ └──────────────────┬───────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ (on build success) │ │
│ │ ┌──────────────────────────┐ ┌───────────────────────────────┐ │ │
│ │ │ JOB 2: Vulnerability │ │ JOB 3: SBOM Generation │ │ │
│ │ │ Scan (Trivy) │ │ (runs parallel with scan) │ │ │
│ │ │ │ │ │ │ │
│ │ │ trivy image │ │ trivy image --format │ │ │
│ │ │ --exit-code 1 │ │ cyclonedx > sbom.xml │ │ │
│ │ │ --severity CRITICAL │ │ │ │ │
│ │ │ │ │ trivy image --format │ │ │
│ │ │ ✅ PASS → continue │ │ spdx > sbom.spdx │ │ │
│ │ │ ❌ FAIL → STOP │ │ │ │ │
│ │ │ │ │ Artifacts saved: 365 days │ │ │
│ │ │ Artifacts saved: 90d │ └───────────────────┬───────────┘ │ │
│ │ └──────────────┬───────────┘ │ │ │
│ │ │ │ │ │
│ │ └─────────────┬─────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ (only if BOTH jobs pass) │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ JOB 4: Promote to Production │ │ │
│ │ │ │ │ │
│ │ │ az acr import │ │ │
│ │ │ --name acrprodjaneburo │ │ │
│ │ │ --source acrstagingjaneburo.../demo-app:SHA │ │ │
│ │ │ --image demo-app:SHA │ │ │
│ │ │ --image demo-app:latest │ │ │
│ │ │ │ │ │
│ │ │ NOTE: Copies EXACT scanned image by digest. │ │ │
│ │ │ NOT a rebuild. What was scanned = │ │ │
│ │ │ what gets deployed. │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ GitHub Secrets (encrypted vault — never in code): │
│ STAGING_ACR_NAME │ PROD_ACR_NAME │ STAGING_CLIENT_ID │ STAGING_CLIENT_SECRET │
│ PROD_CLIENT_ID │ PROD_CLIENT_SECRET │ AZURE_TENANT_ID │ AZURE_SUBSCRIPTION_ID│
│ │
└────────────────────────────┬──────────────────────────┬────────────────────────┘
│ │
▼ ▼
┌────────────────────────────────────────────────────────────────────────────────┐
│ MICROSOFT AZURE (Provisioned with Terraform) │
│ │
│ Resource Group: rg-container-pipeline-janeburo │ Region: East US │
│ Tags: managed_by: terraform │ project: container-pipeline │
│ │
│ ┌───────────────────────────────┐ ┌──────────────────────────────────┐ │
│ │ STAGING REGISTRY │ │ PRODUCTION REGISTRY │ │
│ │ acrstagingjaneburo │ │ acrprodjaneburo │ │
│ │ acrstagingjaneburo.azurecr.io│ │ acrprodjaneburo.azurecr.io │ │
│ │ SKU: Basic │ │ SKU: Basic │ │
│ │ Admin: DISABLED │ │ Admin: DISABLED │ │
│ │ │ │ │ │
│ │ 🟡 ALL builds land here │ │ 🟢 ONLY clean scans land here │ │
│ │ (quarantine zone) │ │ (approved shelf) │ │
│ │ │ │ │ │
│ │ Tags present: │ │ Tags present: │ │
│ │ • 13d2f75f94c0... │ │ • fe51c4105a2cb... │ │
│ │ • 2483485f04f8... │ │ • latest │ │
│ │ • b59127e5a02b... │ │ │ │
│ │ • e9cd8539c547... │ │ │ │
│ │ • fe51c4105a2c... │ │ │ │
│ │ • staging-latest │ │ │ │
│ └───────────────────────────────┘ └──────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ SERVICE PRINCIPALS (Robot employees with specific access badges) │ │
│ │ │ │
│ │ sp-acr-staging-janeburo sp-acr-prod-janeburo │ │
│ │ ├── AcrPush → staging registry ├── AcrPush → production ONLY │ │
│ │ └── AcrPull → staging registry └── AcrPull → staging (for import│ │
│ │ │ │
│ │ ⚠️ Staging SP has ZERO access to production. │ │
│ │ ⚠️ Production SP has ZERO push access to staging. │ │
│ │ These are INFRASTRUCTURE-LEVEL restrictions. Cannot be bypassed. │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────────┘
SECURITY FLOW SUMMARY:
─────────────────────────────────────────────────────────────────────
git push → GitHub Actions → Docker Build → Staging ACR
│
┌──────────┴──────────┐
▼ ▼
Trivy Scan SBOM Generation
│ │
CRITICAL CVE? CycloneDX + SPDX
YES → ❌ STOP saved 365 days
NO → ✅ PASS
│
▼
az acr import (exact digest)
│
▼
Production ACR ✅
─────────────────────────────────────────────────────────────────────
```
## 💼 解决的业务问题
容器镜像并非静态。当镜像构建时,它基于可能已创建数周或数月的基础镜像。在此期间,团队可能发现了无人知晓的安全漏洞(CVE - 常见漏洞和暴露)。
**危险假设:** 大多数组织的工程师拉取和部署容器时,假设有人已检查过其安全性。而实际上,无人检查。
**本流水线如何解决:**
| 之前的问题 | 使用本流水线后 |
|---|---|
| 镜像手动检查(或根本不检查) | 每次构建自动扫描每个镜像 |
| 无镜像组成记录 | 每次构建生成并存储 SBOM,保存 365 天 |
| 人工审批环节在压力下被跳过 | 机器强制执行的关卡——无法跳过 |
| 暂存和生产环境共享访问权限 | 独立的仓库、独立的服务主体,基础设施层面分离 |
| 在门户中手动拼凑基础设施 | 所有内容在 Terraform 中定义——受版本控制且可重复 |
## 🛠️ 工具与技术
| 工具 | 用途 |
|------|---------|
| **Terraform** | 基础设施即代码 — 预置了全部 13 个 Azure 资源 |
| **Azure 容器注册表 (ACR)** | 容器镜像的云存储 — 两个独立的注册表 |
| **GitHub Actions** | 自动化流水线 — 构建、扫描、SBOM、推广 |
| **Docker** | 容器镜像构建 |
| **Trivy** | 漏洞扫描和 SBOM 生成(Aqua Security) |
| **Azure CLI** | 云身份验证和注册表管理 |
| **Git** | 版本控制 — 每个镜像用 Git SHA 标记 |
| **Python + Flask** | 示例应用(用于演示流水线) |
## 📁 仓库结构
```
devsecops-container-pipeline/
│
├── .github/
│ └── workflows/
│ └── container-pipeline.yml ← The brain of the entire operation
│
├── app/
│ ├── app.py ← Flask API with health + version endpoints
│ └── requirements.txt ← Pinned Python dependencies
│
├── .trivyignore ← Formal exception register for accepted risks
├── Dockerfile ← Secure container build blueprint
└── infra/
├── main.tf ← All Azure resources defined here (13 resources)
├── variables.tf ← Input variable declarations
├── outputs.tf ← Sensitive credential outputs (marked sensitive)
└── terraform.tfvars ← Name and location configuration
```
**逐文件说明:**
- **`container-pipeline.yml`** — 定义所有四个流水线任务及其顺序、依赖关系和条件。这是实现全自动化的关键。
- **`app.py`** — 一个极简的 Flask API,刻意保持简单。流水线才是重点,而非应用本身。包含 `/` 健康检查和 `/version` 端点。
- **`requirements.txt`** — `flask==3.0.3` 和 `gunicorn==22.0.0` 固定精确版本。版本固定是软件供应链安全实践。
- **`.trivyignore`** — 记录已接受的 CVE 及解释。并非忽视安全——而是记录经过审查并承担的责任。
- **`Dockerfile`** — 使用 `python:3.12-slim` 基础镜像,非 root 用户(`appuser`),层缓存,HEALTHCHECK,EXPOSE 8080。
- **`main.tf`** — 预置资源组、两个 ACR 注册表、带密码的两个服务主体及所有角色分配。
- **`outputs.tf`** — 为 GitHub Secrets 设置输出凭据。敏感值标记为 `sensitive = true`。
## ☁️ Azure 基础设施 (Terraform)
通过单次 `terraform apply` 预置了全部 13 个资源。Azure 门户中无任何手动创建项。
| 资源 | 名称 | 用途 |
|----------|------|---------|
| 资源组 | `rg-container-pipeline-janeburo` | 包含项目所有资源的容器 |
| 暂存注册表 | `acrstagingjaneburo` | 接收每个新构建的镜像 |
| 生产注册表 | `acrprodjaneburo` | 仅接收经过清洁扫描的镜像 |
| 暂存服务主体 | `sp-acr-staging-janeburo` | 用于构建和扫描任务的标识 |
| 生产服务主体 | `sp-acr-prod-janeburo` | 仅用于推广任务的标识 |
| 角色分配 (×5) | AcrPush + AcrPull (暂存) / AcrPush (生产) + AcrPull (暂存) | 最小权限访问强制执行 |
| SP 密码 (×2) | 自动生成的秘密 | 流水线身份验证凭据 |
| Azure AD 应用程序 (×2) | 后端应用注册 | 服务主体基础 |
**执行的 Terraform 命令:**
```
# Step 1 — 初始化插件
terraform init
# Step 2 — 预览将构建的内容(13 个资源)
terraform plan
# Step 3 — 在 Azure 中构建所有内容
terraform apply
```
**确认的 Terraform 计划输出:**
```
Plan: 13 to add, 0 to change, 0 to destroy
prod_acr_name = "acrprodjaneburo"
staging_acr_name = "acrstagingjaneburo"
subscription_id = "77a478f1-cf4f-4516-ab81-e0614ec50b95"
tenant_id = "54f5c437-8a83-45a3-ad08-318f7d26fb76"
prod_client_id = (sensitive value)
prod_client_secret = (sensitive value)
...
```
## 🔄 流水线 — 四个自动化任务
**触发条件:** 每次推送到 `main` 分支。
### 任务 1 — 构建并推送到暂存区
```
- name: Build and push to staging ACR
run: |
docker build -t ${{ env.IMAGE_NAME }}:${{ github.sha }} .
docker push ${{ secrets.STAGING_ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }}
```
每个镜像都使用 **Git SHA** 标记——这是生成它的精确提交的唯一指纹。注册表中的每个镜像都可以完全追溯到构建它的确切代码。
### 任务 2 — 漏洞扫描 (Trivy)
```
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: '${{ secrets.STAGING_ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }}'
exit-code: '1'
severity: 'CRITICAL'
ignore-unfixed: true
```
- 根据**国家漏洞数据库 (NVD)** 进行扫描
- 如果存在任何已提供修复程序的**严重** CVE,则流水线失败
- 扫描结果作为 **GitHub 制品保存 90 天** — 永久审计跟踪
- `ignore-unfixed: true` — 仅针对存在补丁的漏洞使流水线失败
### 任务 3 — SBOM 生成(与扫描并行)
```
- name: Generate SBOM (CycloneDX)
run: trivy image --format cyclonedx --output sbom-cyclonedx.xml ...
- name: Generate SBOM (SPDX)
run: trivy image --format spdx --output sbom.spdx ...
```
以行业标准格式生成两个 SBOM:
| 格式 | 使用方 |
|--------|---------|
| **CycloneDX** | 企业安全工具、OWASP |
| **SPDX** | 美国政府机构(现为行政命令要求) |
两个文件均作为 **GitHub 制品存储 365 天**。无论扫描结果如何,此任务都会运行——即使对于失败的镜像,也需要清单记录。
### 任务 4 — 推广到生产环境
```
- name: Promote image to production ACR
run: |
az acr import \
--name ${{ secrets.PROD_ACR_NAME }} \
--source ${{ secrets.STAGING_ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }} \
--image ${{ env.IMAGE_NAME }}:${{ github.sha }} \
--image ${{ env.IMAGE_NAME }}:latest \
--force
```
**仅当:** 扫描任务通过 ✅ 且 SBOM 任务通过 ✅ 且推送到 `main` 分支时运行。
使用 `az acr import` 通过摘要复制**精确的已扫描镜像** — 而非重新构建。所扫描的内容保证与部署内容完全一致。
## 🔒 强制执行的安全边界
### 基础设施层面分离
暂存和生产注册表是两个完全独立的 Azure 资源,具有完全独立的服务主体。这些边界无法从流水线绕过——它们是在云基础设施层面强制执行的。
```
Staging SP → AcrPush (staging) + AcrPull (staging) = ZERO production access
Prod SP → AcrPush (production) + AcrPull (staging) = ZERO staging push access
```
### 最小权限访问
每个服务主体仅拥有其特定任务所需的**最小权限**。每个未明确要求的权限都是一个攻击面。
### 无管理员凭据
两个注册表均设置 `admin_enabled = false`。无人能使用用户名/密码登录。访问权限完全通过具有特定角色分配的服务主体获得。
### 正式例外流程
`.trivyignore` 文件提供了所接受安全风险的文档化、版本控制、可审计记录——这是受监管行业所要求的那种正式例外流程。这并非忽视问题——而是记录经过审查的决策并承担责任。
### 纵深防御
安全在**多个层面同时强制执行**:
```
Layer 1: Pipeline gate → Trivy scan fails on CRITICAL CVEs
Layer 2: Infrastructure → Staging credentials physically cannot write to production
Layer 3: No admin access → admin_enabled = false on both registries
Layer 4: Audit trail → SBOM + scan results saved permanently
Layer 5: Exception docs → .trivyignore formal exception register
```
## ✅ 前置条件
在部署本项目之前,请确保以下条件已满足:
| 前置条件 | 状态 |
|---|---|
| 活跃的 Azure 订阅 | 必需 |
| 本地安装 Azure CLI | 必需 — `az --version` |
| 安装 Terraform | 必需 — `terraform --version`(已在 v1.14.8 测试) |
| 安装并运行 Docker Desktop | 必需 — `docker --version` |
| 创建 GitHub 仓库 | 必需 |
| 安装并配置 Git | 必需 |
## 🚀 快速开始 — 部署基础设施
### 步骤 1 — 克隆仓库
```
git clone https://github.com/janebjobtech-cloud/devsecops-container-pipeline.git
cd devsecops-container-pipeline
```
### 步骤 2 — 登录 Azure
```
az login --use-device-code
az account show
```
### 步骤 3 — 配置 Terraform 变量
导航到 `infra/` 文件夹并编辑 `terraform.tfvars`:
```
yourname = "janeburo" # lowercase, no spaces — appended to all resource names
location = "eastus"
```
### 步骤 4 — 初始化 Terraform
```
cd infra
terraform init
```
预期输出:
```
Terraform has been successfully initialized!
Installing hashicorp/azurerm v3.117.1
Installing hashicorp/azuread v2.53.1
```
### 步骤 5 — 预览计划
```
terraform plan
```
您应看到:`Plan: 13 to add, 0 to change, 0 to destroy`
### 步骤 6 — 应用(在 Azure 中构建所有内容)
```
terraform apply
```
提示时输入 `yes`。所有 13 个资源将在 3 分钟内创建完成。
### 步骤 7 — 检索 GitHub Secrets 的凭据
```
terraform output staging_acr_name
terraform output prod_acr_name
terraform output -raw staging_client_id
terraform output -raw staging_client_secret
terraform output -raw prod_client_id
terraform output -raw prod_client_secret
terraform output -raw tenant_id
terraform output -raw subscription_id
```
## 🔑 GitHub Secrets 配置
导航到您的仓库 → **设置** → **Secrets 和变量** → **操作** → **新建仓库密钥**
添加全部 8 个 secrets:
| 密钥名称 | 值来源 |
|---|---|
| `STAGING_ACR_NAME` | `terraform output staging_acr_name` |
| `PROD_ACR_NAME` | `terraform output prod_acr_name` |
| `STAGING_CLIENT_ID` | `terraform output -raw staging_client_id` |
| `STAGING_CLIENT_SECRET` | `terraform output -raw staging_client_secret` |
| `PROD_CLIENT_ID` | `terraform output -raw prod_client_id` |
| `PROD_CLIENT_SECRET` | `terraform output -raw prod_client_secret` |
| `AZURE_TENANT_ID` | `terraform output -raw tenant_id` |
| `AZURE_SUBSCRIPTION_ID` | `terraform output -raw subscription_id` |
## ✅ 流水线验证
### 触发流水线
```
git add .
git commit -m "feat: initial pipeline deployment"
git push origin main
```
### 确认所有 4 个任务通过
在 GitHub 中导航到 **Actions** 选项卡。您应看到:
```
✅ Build and Push to Staging (26s)
✅ Vulnerability Scan (24s)
✅ Generate SBOM (32s)
✅ Promote to Production (1m 12s)
Status: Success in 2m 24s
```
### 通过 Azure CLI 验证
```
# 检查预发环境注册表标签
az acr repository show-tags \
--name acrstagingjaneburo \
--repository demo-app \
--output table
# 检查生产环境注册表标签
az acr repository show-tags \
--name acrprodjaneburo \
--repository demo-app \
--output table
```
## 📦 注册表证据
### 暂存注册表 — `acrstagingjaneburo`
每次构建首先到达此处:
```
13d2f75f94c0f162fee8e4c06cc104be47acfec8
2483485f04f8766a7f8f09c1f5ef22fbeb8a60db
b59127e5a02b70c0722b4710615bde5d91bd0101
e9cd8539c547474b6a3ef0a22e7a1ccec6d77aa7
fe51c4105a2cb5671c6943a8cc8d5e70e4617382
staging-latest
```
### 生产注册表 — `acrprodjaneburo`
只有清洁扫描才能到达此处:
```
fe51c4105a2cb5671c6943a8cc8d5e70e4617382
latest
```
### Azure 门户确认
| 注册表 | 登录服务器 | 区域 | SKU | 管理员 | 状态 |
|----------|-------------|--------|-----|-------|--------|
| `acrstagingjaneburo` | `acrstagingjaneburo.azurecr.io` | 美国东部 | Basic | 已禁用 | ✅ 运行中 |
| `acrprodjaneburo` | `acrprodjaneburo.azurecr.io` | 美国东部 | Basic | 已禁用 | ✅ 运行中 |
## 🏁 项目完成总结
| 组件 | 状态 |
|-----------|--------|
| 使用 Terraform 预置的 Azure 基础设施 | ✅ 完成 |
| 创建两个独立的容器注册表 | ✅ 完成 |
| 两个具有最小权限访问的服务主体 | ✅ 完成 |
| 在基础设施层面配置所有角色分配 | ✅ 完成 |
| 创建 Flask 应用程序和安全的 Dockerfile | ✅ 完成 |
| 包含四个任务的 GitHub Actions 流水线 | ✅ 完成 |
| Trivy 漏洞扫描关卡 | ✅ 完成 |
| 生成 CycloneDX 和 SPDX 格式的 SBOM | ✅ 完成 |
| 清洁扫描后自动推广到生产环境 | ✅ 完成 |
| 在两个注册表中验证镜像 | ✅ 完成 |
| 配置全部 8 个 GitHub Secrets | ✅ 完成 |
| 保存并可访问所有制品 | ✅ 完成 |
## 🎤 面试讨论要点
**我可以阐述:**
- 暂存注册表与生产注册表的区别及其分离的重要性
- CVE 是什么,Trivy 如何检查它们,以及 NVD 是什么
- SBOM 是什么以及美国政府为何现在要求联邦软件必须提供 SBOM
- `az acr import` 与重新构建的区别及其对安全的影响
- `.trivyignore` 文件作为正式例外流程的含义
- Terraform 如何将基础设施作为代码预置及其对可重复性的重要性
- 为何最小权限访问是在服务主体层面而非仅在流水线层面强制执行
- 纵深防御的含义以及本项目如何在多个层面实施
## 👩💻 作者
**Jane Buro**
马里兰大学全球校区 (UMGC) 云计算研究生
GitHub: [@janebjobtech-cloud](https://github.com/janebjobtech-cloud)
*本项目是作为实践 DevSecOps 作品集的一部分构建的,展示了在 Microsoft Azure 上现实世界容器安全流水线的设计与实现。*
## 📄 许可证
本项目根据 MIT 许可证授权。详见 [LICENSE](LICENSE)。
标签:AI应用开发, CI/CD安全, Docker容器镜像, GitHub Actions持续集成, Llama, Terraform基础设施即代码, Trivy安全扫描, Web截图, 安全门禁, 容器安全, 容器注册表, 开发安全运维(DevSecOps), 微软Azure云, 最小权限访问, 自动化管道, 请求拦截, 软件物料清单(SBOM), 镜像晋升, 零信任安全