janebjobtech-cloud/janebjobtech-cloud-devsecops-container-pipeline-details

GitHub: janebjobtech-cloud/janebjobtech-cloud-devsecops-container-pipeline-details

这是一个基于Azure的自动化容器镜像安全扫描与推广流水线,解决容器部署中的安全合规问题。

Stars: 0 | Forks: 0

# 🔐 DevSecOps 容器镜像扫描与推广流水线 [![流水线状态](https://img.shields.io/badge/pipeline-passing-brightgreen)](https://github.com/janebjobtech-cloud/devsecops-container-pipeline/actions) [![平台](https://img.shields.io/badge/cloud-Microsoft%20Azure-0078D4)](https://azure.microsoft.com) [![基础设施即代码](https://img.shields.io/badge/IaC-Terraform-7B42BC)](https://www.terraform.io) [![扫描器](https://img.shields.io/badge/scanner-Trivy-00AEC7)](https://github.com/aquasecurity/trivy) [![许可证](https://img.shields.io/badge/license-MIT-blue)](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), 镜像晋升, 零信任安全