joshuaalwin/vulnops
GitHub: joshuaalwin/vulnops
一个基于 AWS EKS 的全栈 DevSecOps CVE 注册表,通过 CI/CD 与 GitOps 实现漏洞跟踪与安全审计。
Stars: 0 | Forks: 0
# VulnOps
一个用于跟踪和管理漏洞的 CVE 注册表,构建为一个全栈 DevSecOps 项目。该应用程序运行在 AWS EKS 上,并通过 GitHub Actions CI/CD 流水线部署,每个阶段都集成了安全工具。
**技术栈:** React + Nginx / Node.js Express / PostgreSQL
**基础设施:** AWS EKS(自动模式)/ Terraform / Docker / Kubernetes
## 功能说明
VulnOps 允许团队提交包含 ID、严重程度、影响产品、CVSS 分数、描述和修复状态的 CVE。每条记录支持嵌套备注。提交表单中内置了一个基于官方 FIRST 公式的实时 CVSS v3.1 计算器。
该应用程序设计简洁,但其安全架构并不简单:加固的容器、受限的 Kubernetes 部署、10 阶段 CI 流水线以及通过代码配置的所有 AWS 账户级监控。
提交表单包含一个基于官方 FIRST 公式的实时 CVSS v3.1 计算器。当选择攻击向量、复杂度、权限和影响指标时,分数会实时更新。
## 架构
```
Internet -> AWS NLB -> nginx (port 8080, non-root)
-> React SPA (static assets)
-> Express API (port 5000, ClusterIP) -> PostgreSQL (port 5432, ClusterIP)
```
后端和数据库是 ClusterIP 服务,没有外部负载均衡器和公网端点。只有前端 NLB 面向互联网。所有三层服务都在 EKS 上的 Kubernetes 中运行。集群节点位于私有子网,仅通过 NAT 网关进行出站流量。
## 基础设施
完全使用 Terraform 配置,采用官方的 AWS 模块。
**VPC:** 三个可用区。EKS 节点位于私有子网。公共子网仅包含 NAT 网关和 NLB。
**EKS 自动模式(Kubernetes 1.32):** AWS 管理节点组、CoreDNS 和 kube-proxy。启用全部五个控制平面日志类型(api、audit、authenticator、controllerManager、scheduler)。Kubernetes 静态密钥使用 AWS KMS 信封加密在静止状态下加密。
**Terraform 状态:** 使用 AES256 加密和版本控制的 S3 后端,并使用 DynamoDB 表进行状态锁定以防止并发写入冲突。
**AWS 安全监控:**
- CloudTrail:多区域跟踪并启用日志文件验证。SHA-256 摘要文件按交付生成,因此任何被删除或修改的日志都会破坏链条。由于 IAM 和 STS 事件始终记录到 us-east-1,因此启用了 `include_global_service_events`。
- VPC 流日志:捕获所有流量(ACCEPT 和 REJECT)并传输到 S3。自定义日志格式添加了 NAT 前的源地址、TCP 标志、子网 ID 和 VPC ID,以便进行取证重建。S3 传输无摄取成本;CloudWatch Logs 收费 0.50 美元/GB。
- IAM Access Analyzer(账户范围):持续评估基于资源的策略,并标记可从 AWS 账户外部访问的内容。
- 安全日志存储桶:完全阻止公共访问,启用 AES256 加密和版本控制,30 天后过渡到 STANDARD_IA,90 天后过期。
## 容器
两个镜像均采用多阶段构建:Alpine 基础镜像、非 root 用户(UID 1000),仅包含生产依赖。
Nginx 生产镜像使用 SHA256 摘要固定,而非标签。标签是可变的。如果同一标签下的上游镜像被入侵,会被静默拉取。摘要是对精确字节的加密承诺。
后端构建阶段故意使用未固定版本的 `node:20-alpine`,以引入已知 CVE。这为 CI 中的 Trivy 网关提供检测目标,证明在基础镜像升级前该网关确实有效。
## Kubernetes 安全加固
每个 Pod 规范都包含完整的 `securityContext`:
```
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: [ALL]
automountServiceAccountToken: false
```
没有任何 Pod 需要访问 Kubernetes API。禁用 `automountServiceAccountToken` 可从每个不需要它的 Pod 中移除自动挂载的凭证。
网络策略采用默认拒绝基线。仅显式允许所需路径:前端到后端使用 5000 端口,后端到 PostgreSQL 使用 5432 端口。其他所有流量在网络层被阻止,包括从被入侵的前端 Pod 到数据库的任何横向移动。
`vulnops` 命名空间将 Pod 安全标准强制设为 `baseline`,并将审计和警告设置为 `restricted`。该命名空间并未完全受限,因为 PostgreSQL 的 `initdb` 需要 `CAP_CHOWN` 来设置其数据目录的所有权。前端和后端 Pod 通过各自的 `securityContext` 强制执行等效的限制控制。
ArgoCD 在 EKS 内部运行,并监视本仓库中的 `k8s/` 目录。`selfHeal: true` 表示任何手动 `kubectl apply` 产生的偏差都会被自动恢复。CI 从不持有集群凭证。
## CI/CD 流水线
共 10 个阶段,在每次推送到 `main` 或拉取请求时触发。
| 阶段 | 工具 | 作用 |
|---|---|---|
| 密钥扫描 | Gitleaks | 全 Git 历史扫描凭证与令牌。优先执行。如果密钥已暴露,构建无意义。 |
| 代码检查 | ESLint | 并行检查后端与前端。 |
| 依赖审计 | npm audit | 失败于第三包的关键严重性漏洞。 |
| 静态分析(SAST)源码扫描 | Semgrep | 扫描 `backend/src/` 和 `frontend/src/`,使用 `p/nodejs`、`p/owasp-top-ten` 和 `p/javascript`。结果以上报为 GitHub 安全标签的 SARIF 格式。 |
| 静态分析(SAST)网关测试 | Semgrep | 对故意包含不安全代码的测试用例运行 `--error`。反向退出码:如果 Semgrep 未在测试用例中发现问题,则构建失败。这用于验证规则集是否生效。一个静默且无法检测问题的扫描器比没有扫描器更糟糕。 |
| 构建并推送 | Docker Buildx / GHCR | 镜像标记为 7 位提交 SHA。使用 `GITHUB_TOKEN` 进行认证,不存储 PAT。SBOM 和构建可追溯性证明通过 BuildKit 自动附加。 |
| 镜像扫描 | Trivy | 扫描两个镜像中的操作系统和库级 CVE。 |
| IaC 扫描 | Checkov | 扫描 `terraform/` 和 `k8s/` 清单文件中的错误配置。 |
| Dockerfile 检查 | Hadolint | 失败于错误,警告于警告。 |
| 清单更新 | git | 更新后端和前端的部署清单中的镜像标签。ArgoCD 检出提交并自动部署。 |
每个运行中的镜像都可追溯到构建它的精确提交。`latest` 是可变的,不会留下审计轨迹。
## 安全决策
| 决策 | 理由 |
|---|---|
| `npm install --ignore-scripts` | 阻止基于 postinstall 的供应链攻击。Axios 1.14.1 和 0.30.4(2025 年 4 月)曾被入侵以通过 `postinstall` 钩子投放 RAT。此举在安装时阻止此类攻击。 |
| EKS 节点位于私有子网 | 节点无法直接从互联网访问。仅通过 NAT 网关处理出站流量,缩小了被入侵节点的攻击面。 |
| Terraform 状态存储在 S3 + DynamoDB | 在静止状态下加密,具备版本控制(状态损坏时可回滚),并使用锁防止并发写入竞争。 |
| Nginx 使用 SHA256 摘要固定 | 镜像标签是可变的。摘要保证了字节级一致性,无论上游如何推送。 |
| `drop: [ALL]` 能力 | 前端和后端容器零 Linux 能力。移除原始套接字访问和权限提升路径,降低 RCE 后的影响。 |
| `readOnlyRootFilesystem: true` | 防止在容器文件系统中写入 WebShell、工具或恶意脚本。 |
| 默认拒绝网络策略 | 所有 Pod 到 Pod 的流量默认被阻止。被入侵的前端 Pod 无法直接访问数据库。 |
| `automountServiceAccountToken: false` | 从每个不需要它的 Pod 中移除自动挂载的 Kubernetes API 凭证。 |
| 使用 GHCR 而非 Docker Hub | CI 使用内置的 `GITHUB_TOKEN`,不存储 PAT,也不依赖第三方注册表。 |
| SHA 标签替代 `latest` | 将每个运行中的 Pod 与构建它的精确提交关联,实现从集群状态到源代码的完整可追溯性。 |
| ArgoCD GitOps | CI 从不持有集群凭证。`selfHeal` 强制以 Git 作为生产环境的唯一写入路径。手动偏差会被自动撤销。 |
| 每个镜像附带 SBOM + 可追溯性 | 由 BuildKit 自动附加。记录镜像及其构建位置,满足 SLSA 和 EO 14028 的意图。 |
| 使用 Semgrep 而非 CodeQL 进行 SAST | 该应用是简单的 CRUD。CodeQL 的污点跟踪开销过高,不适合此代码库。Semgrep 模式规则覆盖了 Express/Node.js 攻击面,且每个发现都直接映射为可读规则。 |
| Semgrep 网关测试(反向退出码) | Semgrep 默认在发现漏洞时仍退出 0。使用 `--error` 标志可改变此行为。网关测试确保规则集未被静默破坏或错误配置。 |
| CloudTrail 多区域 + 日志文件验证 | IAM 和 STS 事件始终记录到 us-east-1,无论资源所在区域。多区域跟踪捕获这些事件。SHA-256 摘要链条使事后可检测被删除或修改的日志。 |
| VPC 流日志输出到 S3 | 与 CloudWatch Logs 相同的数据,无摄取成本。自定义格式添加了 NAT 前的源地址和 TCP 标志,用于流量模式取证重建。 |
| IAM Access Analyzer | 持续标记允许从 AWS 账户外部访问的资源策略。在问题演变为事件前发现配置错误。 |
| 仅 PostgreSQL 使用基线 PSS | PostgreSQL 的 `initdb` 需要 `CAP_CHOWN`。前端和后端通过各自的 Pod 规范强制执行等效限制控制。 |
| `helmet()` 在 Express API 中 | 为每个响应添加 CSP、`X-Frame-Options`、`Strict-Transport-Security`、`X-Content-Type-Options`、`Referrer-Policy` 以及五个额外头部。此前 API 仅返回裸 Express 默认值,无任何安全头部。 |
| CORS 限制为 `ALLOWED_ORIGINS` | 未配置的 `cors()` 允许任意来源。锁定为通过环境变量显式允许的列表。对不允许的来源返回 403。服务器到服务器的请求(无 `Origin` 头)仍可通过。 |
| 速率限制:全局(200/15 分钟)+ 写入(30/15 分钟) | 全局限制器防止请求泛滥。对 `POST`、`PUT` 和 `DELETE` 采用更严格的每路由限制,减少写入路径滥用。每个响应返回 `RateLimit-*` 头。 |
| API 层输入验证 | CVE ID 验证符合 `CVE-YYYY-NNNNN` 格式。严重程度和状态进行枚举检查后再写入数据库。CVSS 分数范围强制为 0–10。对所有文本输入设置长度上限。此前不良输入直达数据库并以模糊的 500 错误形式暴露。 |
## 本地运行
**使用 Docker Compose:**
```
docker compose up --build
```
前端地址:`http://localhost`。API 地址:`http://localhost:5000`。数据库表会在首次启动时自动创建。
```
# 拆卸并移除卷
docker compose down -v
```
**不使用 Docker(需要 Node.js 20+ 和 PostgreSQL):**
```
# 创建数据库
sudo -u postgres psql <
= 1.5、kubectl、Helm 3。
**1. 配置基础设施:**
```
cd terraform
terraform init
terraform apply
```
**2. 配置 kubectl:**
```
aws eks update-kubeconfig --region us-east-1 --name vulnops-eks
```
**3. 安装 ArgoCD:**
```
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# 等待 ArgoCD 就绪
kubectl wait --for=condition=available --timeout=120s deployment/argocd-server -n argocd
```
**4. 创建数据库密钥:**
```
cp k8s/secrets.yaml.example k8s/secrets.yaml
# 编辑 k8s/secrets.yaml(使用 base64 编码的凭据),然后:
kubectl apply -f k8s/secrets.yaml
```
**5. 应用 ArgoCD 应用程序:**
```
kubectl apply -f k8s/argocd/application.yaml
```
ArgoCD 同步 `k8s/` 目录并部署所有三层服务。从此刻起,任何推送到 `main` 并更新镜像标签的提交都会自动触发部署。
**6. 获取前端 URL:**
```
kubectl get svc -n vulnops vulnops-frontend -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
```
## 拆除
**移除应用程序与命名空间:**
```
kubectl delete -f k8s/argocd/application.yaml
kubectl delete namespace vulnops
```
**移除 ArgoCD:**
```
kubectl delete namespace argocd
```
**销毁所有 AWS 基础设施:**
```
cd terraform
terraform destroy
```
这将移除 EKS 集群、VPC、NAT 网关、S3 存储桶(包括安全日志存储桶)、CloudTrail 跟踪、VPC 流日志、IAM Access Analyzer 以及 DynamoDB 状态锁定表。
## 仓库结构
```
VulnOps/
├── backend/ # Express API and database schema
├── frontend/ # React + Vite + nginx.conf
├── k8s/
│ ├── namespace.yaml
│ ├── secrets.yaml.example
│ ├── postgres/
│ ├── backend/
│ ├── frontend/
│ ├── network-policies/
│ └── argocd/
├── terraform/ # VPC, EKS cluster, and security monitoring
├── .github/workflows/ # GitHub Actions CI pipeline
├── deploy/ # EC2 setup script for manual deployment
└── docker-compose.yml
```
标签:ArgoCD, AWS, AWS EKS, AWS账户监控, CI管道, ClusterIP, CVE, CVSS, CVSS v3.1, DevSecOps, Docker, DPI, ECS, Gitleaks, GitOps, GPT, Hardened Kubernetes, NAT网关, Nginx, Node.js Express, PostgreSQL, React, Semgrep, Syscalls, Terraform, Web截图, WordPress安全扫描, 上游代理, 前端负载均衡, 子域名突变, 安全左移, 安全开发生命周期, 安全架构, 安全防御评估, 容器安全, 开源框架, 持续交付, 持续集成, 数字签名, 测试用例, 漏洞注册表, 漏洞管理, 私有子网, 线程化注释, 自动化安全扫描, 自定义脚本, 请求拦截