johntay379-hub/flask-devsecops-aws-pipeline

GitHub: johntay379-hub/flask-devsecops-aws-pipeline

一个生产级 Flask 应用的安全 DevSecOps 流水线,演示如何在 AWS 上通过 OIDC 无凭证认证、Trivy 漏洞扫描和 SSM 无 SSH 部署实现安全的容器化交付。

Stars: 0 | Forks: 0

# 🔐 Flask DevSecOps AWS Pipeline ![Python](https://img.shields.io/badge/Python-Flask-3776AB?style=for-the-badge&logo=python) ![Docker](https://img.shields.io/badge/Docker-Container-2496ED?style=for-the-badge&logo=docker) ![Terraform](https://img.shields.io/badge/Terraform-IaC-7B42BC?style=for-the-badge&logo=terraform) ![GitHub Actions](https://img.shields.io/badge/GitHub_Actions-CI%2FCD-2088FF?style=for-the-badge&logo=githubactions) ![AWS](https://img.shields.io/badge/AWS-Cloud-FF9900?style=for-the-badge&logo=amazonaws) ![Trivy](https://img.shields.io/badge/Trivy-Security_Scan-red?style=for-the-badge) ![Status](https://img.shields.io/badge/Pipeline-Passing-brightgreen?style=for-the-badge) ## 这是什么? 这是一个生产级别的容器化 Flask 应用,通过全自动的 DevSecOps pipeline 部署在 AWS 上。每次将代码推送到 GitHub 时,pipeline 都会构建 Docker 镜像,使用 Trivy 扫描其漏洞,将其推送到私有 ECR 注册表,并部署到 EC2 —— 整个过程无需使用任何硬编码的 AWS 凭证或 SSH 密钥。 在这里,安全性绝不是事后才考虑的问题。它已融入到每一层:通过 OIDC 实现无凭证的 AWS 身份验证、部署前的容器漏洞扫描、最小权限的 IAM role、基于 SSM 且无需 SSH 的远程访问,以及流量完全且独占地通过负载均衡器传输。 ## 在线演示 该基础设施经过部署、测试和截图后,已通过 terraform destroy 销毁,以避免持续产生 AWS 费用。/screenshots 目录中的截图展示了在线部署情况。整个技术栈可在几分钟内重新部署。 在线时的 ALB endpoint: ``` http://secure-flask-alb-1046257647.us-east-1.elb.amazonaws.com ``` API 响应: ``` GET / {"hostname": "f5ed7d14b8a7", "message": "Secure Containerised Flask App", "status": "running"} GET /health {"status": "healthy"} ``` hostname 字段返回的是 Docker 容器 ID —— 这证明了应用运行在容器内,而不是直接运行在主机上。 ## Flask 应用 这是一个轻量级的 Python Flask API,包含两个 endpoint: ``` GET / returns app info including container hostname GET /health returns health check status used by ALB ``` 该应用运行在 Gunicorn 上 —— 这是一个生产级的 WSGI 服务器,而不是 Flask 内置的开发服务器。Flask 开发服务器是单线程的,不适用于生产环境的流量。Gunicorn 能够正确处理多个并发请求。 ``` CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "2", "app:app"] ``` ## Pipeline 工作原理 ### 每次推送到 main 分支都会触发完整的 pipeline **第 1 步 — OIDC 身份验证** GitHub Actions 永远不会接触到 AWS 访问密钥。相反,GitHub 会生成一个已签名的 JWT token,以此证明“我是为 johntay379-hub/flask-devsecops-aws-pipeline 仓库运行的 GitHub Actions”。AWS 会针对 OIDC provider 验证此 token,并颁发一个临时会话凭证。任何地方都不存在长期凭证。 **第 2 步 — Docker 构建** Pipeline 从 ./app/dockerfile 构建 Flask Docker 镜像。每次构建都会生成一个全新的镜像,并使用 latest 和 Git commit SHA 进行标记 —— 这样每次部署都可以精确追溯到触发它的具体 commit。 **第 3 步 — Trivy 安全扫描** 在镜像进入生产环境之前,Trivy 会扫描其已知 CVE。它会检查基础 OS 包、Python 依赖项以及应用层,并与其漏洞数据库进行比对。CRITICAL 和 HIGH 级别的发现会被记录在 pipeline 日志中。这就是介于“我们构建了它”和“我们部署了它”之间的安全闸门。 **第 4 步 — 推送到 ECR** 扫描后的镜像会被推送到私有 ECR 仓库。ECR 还启用了 scan_on_push —— 因此 AWS 在镜像到达时会独立于 Trivy 运行自己的漏洞扫描。两次扫描,两次机会,在镜像运行于 EC2 之前捕捉到潜在问题。 **第 5 步 — 通过 SSM 部署** Pipeline 使用 AWS Systems Manager 向 EC2 实例发送 shell 命令 —— 无需 SSH,无需密钥对,也不开放 22 端口。SSM 通过附加到实例的 IAM role 进行工作。这些命令会从 ECR 拉取新镜像并重启容器。 ## 关键安全决策 **使用 OIDC 代替访问密钥** —— GitHub Secrets 中的长期 AWS 凭证是云账户被盗用的常见根源。OIDC 彻底消除了这一点。GitHub Actions role 会获取一个在 pipeline 运行后即过期的临时 token。 **最小权限 IAM role** —— GitHub Actions role 只能推送到 ECR 并向该特定实例发送 SSM 命令。EC2 role 只能从 ECR 拉取并注册到 SSM。 **无 SSH 访问** —— 安全组中未开放 22 端口。实例未附加任何密钥对。SSM 是唯一的访问途径 —— 并且每个 SSM session 都会被 AWS 记录。 **EC2 仅可通过 ALB 访问** —— EC2 安全组仅允许来自 ALB 安全组的 5000 端口入站流量。直接访问实例 IP 被阻止。 **强制执行 IMDSv2** —— EC2 实例要求数据元数据服务请求提供 session token,从而阻止 SSRF 攻击。 **双层漏洞扫描** —— Trivy 在推送前的 pipeline 中扫描镜像。ECR 在镜像到达时再次进行扫描。 ## Trivy 扫描结果 Trivy 在部署期间对 Flask 容器镜像进行了扫描。基础镜像 (Amazon Linux 2023) 和 Python 依赖项 (Flask 3.0.3, Gunicorn 22.0.0) 返回了干净的结果 —— 在部署时未检测到 CRITICAL 或 HIGH 级别的漏洞。可在 pipeline 日志的“Scan image with Trivy”步骤中查看。 ## 基础设施 | 资源 | 用途 | |---|---| | aws_ecr_repository | 私有 Docker 镜像注册表 | | aws_ecr_lifecycle_policy | 保留最后 5 个镜像,删除旧镜像 | | aws_iam_openid_connect_provider | 将 GitHub Actions 作为身份提供商信任 | | aws_iam_role (github_actions) | GitHub Actions 通过 OIDC 扮演的 role | | aws_iam_role_policy | 仅允许 ECR 推送 + 发送 SSM 命令 | | aws_iam_role (ec2) | 附加到 EC2 实例的 role | | aws_iam_role_policy_attachment (ssm) | 无需 SSH 的 SSM 访问权限 | | aws_iam_role_policy_attachment (ecr) | 从 ECR 拉取镜像 | | aws_iam_instance_profile | 封装 EC2 role 供实例使用 | | aws_security_group (alb) | 允许互联网到 ALB 的 80 端口流量 | | aws_security_group (ec2) | 仅允许来自 ALB 的 5000 端口流量 | | aws_lb | Application Load Balancer | | aws_lb_target_group | 路由到 EC2 的 5000 端口,对 /health 进行健康检查 | | aws_lb_listener | 80 端口,转发到 target group | | aws_lb_target_group_attachment | 将 EC2 注册到 target group | | aws_instance | EC2 t2.micro,Docker,SSM,IMDSv2 | ## 解决的挑战 | 挑战 | 解决方案 | |---|---| | GitHub pipeline 中的 AWS 凭证 | OIDC —— 使用临时 token,无存储的密钥 | | 用于部署的 SSH 密钥管理 | SSM —— 无需密钥,不开放 22 端口 | | 部署未经测试的镜像 | 推送前由 Trivy 扫描,到达时由 ECR 扫描 | | 从 ECR 拉取容器 | 使用具有 ECR 只读权限的 EC2 IAM role | | EC2 直接暴露在互联网中 | 以 ALB 作为单一入口点,安全组阻止直接访问 | | Terraform provider 二进制文件过大 | .gitignore 排除了 .terraform/ 文件夹 | ## 项目结构 ``` flask-devsecops-aws-pipeline/ ├── app/ │ ├── app.py # Flask app — 2 endpoints │ ├── dockerfile # Gunicorn production server │ └── requirements.txt # flask==3.0.3, gunicorn==22.0.0 ├── terraform/ │ ├── main.tf # ECR, OIDC, IAM, EC2, ALB │ ├── variables.tf # Region, project, GitHub repo │ ├── outputs.tf # ALB DNS, ECR URL, EC2 ID, Role ARN │ └── providers.tf # AWS provider ├── .github/ │ └── workflows/ │ └── deploy.yml # Full CI/CD pipeline ├── screenshots/ # Live deployment proof ├── .gitignore └── README.md ``` ## 自己动手部署 ``` git clone https://github.com/johntay379-hub/flask-devsecops-aws-pipeline.git cd flask-devsecops-aws-pipeline/terraform terraform init terraform apply ``` 将 terraform 输出的内容添加到这些 GitHub Secrets 中: - AWS_ROLE_ARN - AWS_REGION - ECR_REPOSITORY - EC2_INSTANCE_ID 然后推送到 main —— pipeline 将自动进行部署。 ## 相关项目 | 项目 | 涵盖范围 | |---|---| | [AWS CLI 安全框架](https://github.com/johntay379-hub/aws-end-to-end-security-framework) | IAM, S3, CloudTrail, VPC, EC2, CloudWatch, SNS | | [Terraform 安全框架](https://github.com/johntay379-hub/terraform-aws-security-framework) | 以 Infrastructure as Code 实现的相同安全模型 | | [Zero Trust 安全平台](https://github.com/johntay379-hub/aws-zero-trust-security-platform) | ALB, Auto Scaling, AWS Config | | [安全 CI/CD Pipeline](https://github.com/johntay379-hub/secure-cicd-pipeline) | 带有 tfsec 扫描的 Terraform pipeline | | **Flask DevSecOps AWS Pipeline** | **Docker, ECR, OIDC, SSM, Trivy** | ## 作者 **John Kamau** — AWS Cloud Engineer (专注于安全) [github.com/johntay379-hub](https://github.com/johntay379-hub) · [linkedin.com/in/john-kamau-60ba53342](https://linkedin.com/in/john-kamau-60ba53342)
标签:DevSecOps, NIDS, 上游代理, 容器化, 持续集成/持续交付(CI/CD), 请求拦截, 逆向工具