raahulkurmi/-secure-k8s-platform
GitHub: raahulkurmi/-secure-k8s-platform
生产级安全 Kubernetes 平台参考实现,整合准入控制、运行时安全、零信任网络和 GitOps 流水线的端到端 DevSecOps 示范项目。
Stars: 0 | Forks: 0
# 🔐 安全的 Kubernetes 平台
## 📋 目录
- [概述](#overview)
- [架构](#architecture)
- [安全层](#security-layers)
- [技术栈](#tech-stack)
- [仓库结构](#repository-structure)
- [应用](#application)
- [CI/CD Pipeline](#cicd-pipeline)
- [Kyverno 策略](#kyverno-policies)
- [网络策略](#network-policies)
- [使用 ArgoCD 实现 GitOps](#gitops-with-argocd)
- [快速开始](#quick-start)
- [关键调试案例](#key-debugging-stories)
- [生产环境考量](#production-considerations)
## 概述
大多数 Kubernetes 项目止步于“部署应用”。本项目将安全性融入堆栈的每一层——从代码推送的那一刻到 Pod 在集群中运行的那一刻。
**本项目展示了:**
- **准入控制(Admission control)** — Kyverno 策略会在任何违反安全标准的 Pod 运行之前将其拦截
- **运行时安全(Runtime security)** — Falco 监控系统调用,并使用 eBPF 在内核层面检测威胁
- **零信任网络(Zero-trust networking)** — Calico NetworkPolicies 在每个服务之间执行明确的白名单策略
- **GitOps** — ArgoCD 确保集群始终与 Git 中的内容保持一致,绝无例外
- **安全的 CI/CD** — GitHub Actions 流水线包含 Dockerfile 检查、SAST 扫描、镜像扫描和 Kyverno 策略验证,作为镜像推送前的安全门禁
## 架构
```
┌─────────────────────────────────────────────────────────────────────────┐
│ Developer Workstation │
│ │
│ git push ──────────────────────────────────────────────────────────► │
└──────────────────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ GitHub Actions (CI) │
│ │
│ ① Lint & Validate ② Security Scan ③ Build & Scan Images │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────────┐ │
│ │ hadolint │ ───► │ Trivy (SAST) │ ───► │ Build image │ │
│ │ kubeconform │ │ Kyverno CLI │ │ Trivy (image) │ │
│ └───────────────┘ └───────────────┘ │ Push → GHCR │ │
│ └───────────────────┘ │
│ │ │
│ ④ Update Manifests │
│ sed image tag → git commit │
└──────────────────────────────────────────────────────────┬──────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ ArgoCD (CD / GitOps) │
│ │
│ Watches Git repo ──► Detects tag change ──► Auto-syncs to cluster │
└──────────────────────────────────────────────────────────┬──────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Kind Cluster (1 control-plane + 3 workers) │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ Admission Layer (Kyverno — 10 policies enforced) │ │
│ │ Every pod is validated before it runs │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────────┐ │
│ │ ingress- │ │ namespace: │ │ namespace: │ │
│ │ nginx │───►│ app │ │ argocd │ │
│ │ │ │ │ │ │ │
│ │ todo.local │ │ frontend (2x) │ │ argocd-server │ │
│ │ argocd.local │ │ backend (2x) │ │ app-controller │ │
│ └────────────────┘ │ postgres (1x) │ │ repo-server │ │
│ └────────────────┘ └────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ Runtime Layer (Falco — eBPF syscall monitoring) │ │
│ │ Detects privilege escalation, shell spawns, file tampering │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ Network Layer (Calico — Zero-trust NetworkPolicies) │ │
│ │ Default deny all · Explicit allow-lists only │ │
│ └──────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
```
## 安全层
| 层级 | 工具 | 功能描述 |
|---|---|---|
| **准入控制(Admission Control)** | Kyverno | 在创建时验证每个 Pod 规范——在非合规工作负载运行前将其拦截 |
| **运行时安全(Runtime Security)** | Falco | 使用 eBPF 监控内核级系统调用——检测权限提升、反向 Shell、文件篡改 |
| **网络安全(Network Security)** | Kubernetes NetworkPolicy | 零信任——默认拒绝所有,使用 namespaceSelector + podSelector AND 条件进行逐跳显式允许 |
| **镜像安全(Image Security)** | Trivy | 在 CI 流水线中扫描 Dockerfile 和容器镜像的 HIGH/CRITICAL CVE |
| **网络策略(Network Policies)** | Kubernetes NetworkPolicy (apiVersion: networking.k8s.io/v1) | 通过 hostPort 绑定进入集群的单一入口点——按主机名/路径路由 |
| **GitOps** | ArgoCD | Git 是唯一的真实来源——偏差检测和自动协调 |
| **Dockerfile Linting** | hadolint | 强制执行 Dockerfile 最佳实践(非 root,不使用 latest,正确的层顺序) |
| **清单验证(Manifest Validation)** | kubeconform | 在 CI 中根据官方 API schema 验证 Kubernetes 清单 |
## 技术栈
| 类别 | 技术 |
|---|---|
| **容器编排** | Kubernetes (kind — 1 control-plane + 3 workers) |
| **CNI** | Calico (在 kind 上启用 NetworkPolicy 强制执行) |
| **策略引擎** | Kyverno v1.11 |
| **运行时安全** | Falco (eBPF / modern_ebpf 驱动) |
| **GitOps / CD** | ArgoCD (通过 Helm 安装) |
| **Ingress** | ingress-nginx |
| **Ingress** | ingress-nginx |
| **容器镜像仓库** | GitHub Container Registry (GHCR) |
| **镜像扫描** | Trivy (文件系统 + 镜像扫描) |
| **Dockerfile Linting** | hadolint |
| **清单验证** | kubeconform |
| **TLS / 证书管理** | cert-manager |
| **前端** | React + Vite + Nginx |
| **后端** | Node.js + Express |
| **数据库** | PostgreSQL |
## 仓库结构
```
secure-k8s-platform/
│
├── app/
│ ├── frontend/ # React (Vite) — served via Nginx
│ │ ├── Dockerfile # Multi-stage, non-root, read-only FS
│ │ ├── src/App.jsx
│ │ └── package.json
│ │
│ └── backend/ # Node.js + Express REST API
│ ├── Dockerfile # Multi-stage, non-root, read-only FS
│ ├── src/index.js # Helmet, CORS, rate-limiting, pg pool
│ └── package.json
│
├── infra/
│ ├── kind-config.yaml # Cluster: 1 control-plane + 3 workers
│ │ # Port mappings: 80, 443 for ingress
│ └── audit-policy.yaml # CIS-compliant API server audit logging
│
├── k8s/
│ ├── base/
│ │ ├── kubernetes_spec.yaml # All app deployments + services
│ │ └── ingress.yaml # todo.local routing rules
│ │
│ ├── policies/
│ │ └── kyverno-policies.yaml # 10 ClusterPolicies (see below)
│ │
│ └── network-policies/
│ └── network-policies.yaml # 7 NetworkPolicies (zero-trust)
│
├── scripts/
│ ├── bootstrap.sh # One-shot cluster setup script
│ ├── deploy-app.sh # Build images + deploy to cluster
│ └── install-deps.sh # Install all CLI tools (macOS/Linux)
│
└── .github/
└── workflows/
└── ci.yaml # 4-stage CI/CD pipeline
```
## 应用
一个 3 层架构的 **Todo 应用**,旨在演示 Kubernetes 上的安全加固部署。
```
browser
│
▼
ingress-nginx (todo.local)
│
├── / ──► frontend (React + Nginx) :8080
└── /api/ ──► backend (Node.js + Express) :3000
│
▼
postgres :5432
(PersistentVolumeClaim)
```
**应用于每个容器的安全加固:**
- 多阶段 Docker 构建(最小化运行时镜像)
- 非根用户(`uid 1001`)
- 只读根文件系统
- 丢弃所有 Linux capabilities
- CPU 和内存的资源限制
- 健康和就绪探针(`/healthz`, `/readyz`)
- 后端的速率限制和 Helmet 安全头
**本地访问:**
```
# 集群设置完成后
echo "127.0.0.1 todo.local" | sudo tee -a /etc/hosts
# 应用访问地址:http://todo.local
```
## CI/CD 流水线
流水线在每次推送到 `main` 和每个 Pull Request 时运行。四个作业按顺序运行——每个作业都是必须通过才能进行下一个的安全门禁。
```
push to main
│
▼
┌─────────────────────┐
│ ① Lint & Validate │ hadolint (Dockerfile) + kubeconform (manifests)
└──────────┬──────────┘
│ pass
▼
┌─────────────────────┐
│ ② Security Scan │ Trivy filesystem (SAST) + Kyverno CLI policy check
└──────────┬──────────┘
│ pass
▼
┌─────────────────────┐
│ ③ Build & Scan │ Build images → Trivy image scan → Push to GHCR
│ Images │ Tags: ghcr.io/raahulkurmi/secure-todo-{backend,frontend}:
└──────────┬──────────┘
│ pass (main branch only)
▼
┌─────────────────────┐
│ ④ Update Manifests │ sed updates image tag in kubernetes_spec.yaml
│ │ Commits change back to repo → ArgoCD picks it up
└─────────────────────┘
```
**镜像标签策略:** 每次构建都会根据 commit SHA(例如 `a1b2c3d`)生成一个唯一的、不可变的标签。不使用 `:latest`——仅使用固定标签,这由 Kyverno 策略强制执行。
## Kyverno 策略
10 个以 **Enforce** 模式(拦截请求)或 **Audit** 模式(报告但允许)执行的 `ClusterPolicy` 资源。在准入时应用——在任何 Pod 到达节点之前。
| # | 策略 | 模式 | 原因 |
|---|---|---|---|
| 01 | `disallow-privileged-containers` | Enforce | 防止容器逃逸到宿主机——特权模式拥有完整的内核访问权限 |
| 02 | `require-run-as-non-root` | Enforce | 如果逃逸成功,容器中的 root = 宿主机上的 root。要求 `runAsUser ≥ 1000` |
| 03 | `disallow-latest-tag` | Enforce | `:latest` 是不可复现且未固定的——必须使用基于 SHA 的不可变标签 |
| 04 | `require-resource-limits` | Enforce | 没有限制,单个 Pod 可能会导致整个节点资源耗尽 |
| 05 | `disallow-host-namespaces` | Enforce | `hostPID`, `hostIPC`, `hostNetwork` 破坏节点隔离边界 |
| 06 | `require-readonly-rootfs` | Enforce | 只读根文件系统防止攻击者将恶意软件持久化到磁盘 |
| 07 | `disallow-host-path` | Enforce | hostPath 卷将节点文件系统暴露给容器 |
| 08 | `disallow-capabilities` | Enforce | 丢弃所有 Linux capabilities——消除如 `CAP_SYS_ADMIN` 等等效于 root 的权限 |
| 09 | `require-standard-labels` | Audit | 强制所有工作负载具有治理标签(`app`, `version`, `component`) |
| 10 | `require-pod-disruption-budget` | Audit | 标记没有 PDB 的工作负载——生产环境中安全滚动更新所需 |
**验证策略是否处于活动状态:**
```
kubectl get clusterpolicy
# 所有 10 个都应显示 READY: True
```
**查看实时策略报告:**
```
kubectl get policyreport -n app
```
## 网络策略
7 个 `NetworkPolicy` 资源(由 Calico 强制执行),在 `app` namespace 中实现零信任网络。模型很简单:**默认拒绝所有 Pod 的入站和出站流量**,然后仅显式允许应用程序所需的内容。
```
internet
│
▼
ingress-nginx controller pod (ingress-nginx namespace)
│
│ allowed by: allow-ingress-to-frontend
│ (namespaceSelector: ingress-nginx + podSelector: controller pod only)
▼
frontend pods :8080 (app namespace)
│
│ allowed by: allow-frontend-egress-backend (egress)
│ + allow-frontend-to-backend (ingress on backend)
▼
backend pods :3000 (app namespace)
│
│ allowed by: allow-backend-egress-postgres (egress)
│ + allow-backend-to-postgres (ingress on postgres)
▼
postgres pods :5432 (app namespace)
postgres → anything ❌ default deny (no egress policy)
backend → internet ❌ default deny (only DNS + postgres egress allowed)
frontend → postgres ❌ blocked (cannot skip backend layer)
any other pod → backend/postgres ❌ blocked (label selector is specific)
```
**所有 7 个策略——每个策略的作用及原因:**
| # | 策略名称 | 类型 | 方向 | 详情 |
|---|---|---|---|---|
| 1 | `default-deny-all` | Ingress + Egress | 所有 Pod | 基准——拦截一切。其他所有策略都是对此的例外。 |
| 2 | `allow-ingress-to-frontend` | Ingress | → frontend:8080 | 源必须同时匹配 `namespaceSelector: ingress-nginx` 和 `podSelector: app.kubernetes.io/component=controller`——仅限 ingress-nginx controller Pod,而非该 namespace 中的任何其他 Pod |
| 3 | `allow-frontend-to-backend` | Ingress | → backend:3000 | `podSelector: app=frontend`——仅 frontend Pod 可以访问 backend。Frontend 必须具有 `app: frontend` 标签,该标签在 deployment 中设置。策略位于 backend 的 namespace 中。 |
| 4 | `allow-backend-to-postgres` | Ingress | → postgres:5432 | `podSelector: app=postgres`——仅允许 backend Pod。Postgres 不能被 frontend 或任何其他 Pod 直接访问。 |
| 5 | `allow-backend-egress-dns` | Egress | backend → kube-dns:53 | Backend 需要 DNS 来解析 `postgres-svc`。没有此策略,即使允许的连接也会失败,因为无法解析服务名称。 |
| 6 | `allow-frontend-egress-backend` | Egress | frontend → backend:3000 | 策略 #3 的出站一侧。入站(在 backend 上)和出站(在 frontend 上)都必须被允许,流量才能流动。 |
| 7 | `allow-backend-egress-postgres` | Egress | backend → postgres:5432 | 策略 #4 的出站一侧。Backend 只能与 postgres 进行出站通信——不能与其他任何东西通信。 |
**实施过程中学到的关键概念:** NetworkPolicy 是 namespace 级别的资源。保护 `backend` 的策略必须在 `app` namespace 中创建——它不能保护其他 namespace 中的 Pod。`from` 块(源选择器)是独立的——它可以使用 `namespaceSelector` 引用任何 namespace。缩进相同 = AND 条件(namespace 和 Pod 标签都必须匹配)。列表项分开 = OR 条件。
**验证所有策略:**
```
kubectl get networkpolicy -n app
# 预期:列出 7 个 policies
# 应用 policies 后测试端到端流量是否正常
curl http://todo.local/api/todos
```
## 使用 ArgoCD 实现 GitOps
ArgoCD 通过 Helm 安装,并监视此仓库的 `k8s/base/` 目录。当 CI 流水线提交更新的镜像标签时,ArgoCD 检测到更改并自动同步集群。
```
Developer pushes code
│
▼
GitHub Actions builds + pushes image to GHCR
│
▼
Pipeline commits updated image tag to k8s/base/kubernetes_spec.yaml
│
▼
ArgoCD polls Git (every 3 minutes or via webhook)
│
▼
ArgoCD detects diff between Git state and cluster state
│
▼
ArgoCD syncs — cluster is updated automatically
```
**Git 是唯一的真实来源。** 生产环境中不使用 `kubectl apply`。对集群的任何手动更改都将在下次同步时被 ArgoCD 覆盖。
**本地访问 ArgoCD UI:**
```
kubectl port-forward svc/argocd-server -n argocd 8080:443
# 打开:https://localhost:8080
# 用户名:admin
# 密码:kubectl get secret argocd-initial-admin-secret -n argocd \
# -o jsonpath="{.data.password}" | base64 -d
```
## 快速开始
### 前置条件
```
# 安装所需工具
./scripts/install-deps.sh
# 所需:docker, kind, kubectl, helm, kyverno CLI
```
### 1. 创建集群
```
cd infra
kind create cluster --config kind-config.yaml --wait 120s
cd ..
```
### 2. 引导安全工具
```
# 安装:Calico, cert-manager, Kyverno, Falco
./scripts/bootstrap.sh
```
### 3. 部署应用
```
# 构建镜像,加载到 kind,应用 manifests
./scripts/deploy-app.sh
```
### 4. 安装 ingress-nginx
```
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=120s
echo "127.0.0.1 todo.local" | sudo tee -a /etc/hosts
kubectl apply -f k8s/base/ingress.yaml
```
### 5. 安装 ArgoCD
```
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm upgrade --install argocd argo/argo-cd \
--namespace argocd \
--create-namespace \
--set server.service.type=ClusterIP \
--wait --timeout 180s
```
### 6. 验证所有内容
```
kubectl get nodes
kubectl get pods -n kube-system # Calico
kubectl get pods -n cert-manager
kubectl get pods -n kyverno
kubectl get pods -n falco
kubectl get pods -n ingress-nginx
kubectl get pods -n argocd
kubectl get pods -n app
kubectl get clusterpolicy # All 10 Kyverno policies
kubectl get networkpolicy -n app # All 7 network policies
```
### 7. 访问应用
```
# Todo 应用
open http://todo.local
# ArgoCD UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
open https://localhost:8080
# API
curl http://todo.local/api/todos
```
## 关键调试案例
在此构建过程中遇到并解决的真实问题——每一个都教会了具体的东西。
**Kyverno 拦截了我们自己的 PostgreSQL 部署**
部署脚本失败,显示 `admission webhook denied the request`。Kyverno 正在执行 `require-readonly-rootfs` 和 `require-run-as-non-root`——而 PostgreSQL 需要写入其数据目录。修复:添加了带有 `runAsUser: 999`, `readOnlyRootFilesystem: true` 的 `securityContext`,以及用于数据目录的 `emptyDir` 卷。这正是 Kyverno 的预期工作方式——它强制执行了正确的修复。
**ingress-nginx 需要在 Kind 中映射端口 80**
初始集群在 kind-config 中只有 `30080 → 8888`。添加 ingress-nginx 并创建 Ingress 对象不起作用——controller 无法绑定到端口 80。修复:在 `kind-config.yaml` 中使用 `containerPort: 80 → hostPort: 80` 以及 control-plane 上的 `ingress-ready=true` 节点标签重新创建集群。
**GitHub Actions SARIF 重复上传错误**
在同一作业中为 frontend 和 backend 镜像运行 Trivy 扫描触发错误 `only one run per tool/category is allowed`。修复:为每个上传步骤添加唯一的 `category` 值(`trivy-frontend`, `trivy-backend`, `trivy-fs`)。后来完全删除了 SARIF 上传,改用表格格式输出以简化流水线。
**ArgoCD Helm 安装因现有 ClusterRoles 失败**
之前通过 `kubectl apply` 安装的 ArgoCD 留下了 Helm 无法接管的 ClusterRoles 和 CRD。修复:在重试 Helm 安装之前手动删除孤立的 CRD(`applications.argoproj.io`, `applicationsets.argoproj.io`, `appprojects.argoproj.io`)和 ClusterRoles。
**GitHub Actions `git push` 因 403 失败**
`update-manifests` 作业无法提交回仓库。修复:在仓库 Settings → Actions → General → Workflow permissions 中为 `GITHUB_TOKEN` 启用 **Read and write permissions**,并在作业定义中添加 `permissions: contents: write`。
## 生产环境考量
本项目在 kind 上本地运行。迁移到生产环境(EKS/GKE/AKS)将涉及:
| 领域 | 本地(本项目) | 生产环境 |
|---|---|---|
| **集群** | kind (本地) EKS / GKE / AKS via Terraform |
| **Ingress** | ingress-nginx + hostPort | Istio Gateway + Cloud LoadBalancer |
| **TLS** | cert-manager (自签名) | cert-manager + Let's Encrypt |
| **Secrets** | Kubernetes Secrets | HashiCorp Vault + External Secrets Operator |
| **镜像仓库** | GHCR | ECR / GAR / ACR |
| **可观测性** | — | Prometheus + Grafana + Loki |
| **Falco 输出** | stdout | Falcosidekick → Slack / PagerDuty |
| **ArgoCD HA** | 单副本 | 带有 Redis 的 HA 模式 |
标签:API集成, ArgoCD, Calico, CISA项目, DevSecOps, Falco, GitHub Actions, GitOps, Grafana, HashiCorp Vault, JSONLines, Kind, Loki, MITM代理, SAST, Web截图, 上游代理, 可观测性, 子域名突变, 安全, 安全合规, 容器安全, 敏感词过滤, 数据处理, 本地开发, 活动识别, 测试用例, 生产级, 盲注攻击, 网络代理, 网络策略, 自动化运维, 自动笔记, 自定义请求头, 超时处理, 镜像扫描, 零信任