VladvonTranssylvanien/learningsteps-lockdown

GitHub: VladvonTranssylvanien/learningsteps-lockdown

一个记录Azure环境下FastAPI应用从不安全到端到端安全加固完整实战过程的项目。

Stars: 0 | Forks: 0

# LearningSteps 安全加固 - 端到端安全强化 ## 项目概述 本项目记录了 LearningSteps API 的完整安全加固过程。该 FastAPI 应用运行在 Azure 上。我们从一个故意不安全的部署开始,遵循**纵深防御**原则实施了多层安全架构。 ## 架构演进 ### 加固前(不安全基线) - 虚拟机通过公网 IP 直接暴露于互联网 - SSH 可从任意 IP 使用静态密钥文件访问 - API 完全匿名,无任何认证 - PostgreSQL 在 5432 端口可从任何位置访问 - 无日志、无监控、无告警 ### 加固后(强化状态) - 互联网 -> NSG (仅 443 端口) -> Nginx (TLS+WAF+速率限制) -> oauth2-proxy (JWT) -> FastAPI -> PostgreSQL (私有 VNet) - 管理通道:Azure Bastion -> 虚拟机 (Entra ID 身份) - 监控链路:Azure Monitor -> Log Analytics -> Microsoft Sentinel -> Logic App -> NSG (自动阻断) ``` graph TB Internet((Internet)) subgraph Edge["Edge Layer"] NSG["NSG - Port 443 only - Deny-SQLi-Attack auto-block"] Nginx["Nginx - TLS 1.2/1.3 - WAF + Rate Limiting"] end subgraph App["Application Layer"] OAuth["oauth2-proxy - JWT Validation"] API["FastAPI - Port 8000 internal"] end subgraph Data["Data Layer"] DB[("PostgreSQL - Private VNet")] end subgraph Mgmt["Management Layer"] Bastion["Azure Bastion"] EntraID["Microsoft Entra ID"] end subgraph SOC["SOC Layer"] AMA["Azure Monitor Agent"] LAW["Log Analytics"] Sentinel["Microsoft Sentinel - SQLi Hunter"] LogicApp["Logic App - Auto-block"] end Internet -->|HTTPS 443| NSG NSG --> Nginx Nginx -->|proxy_pass| OAuth OAuth -->|verified| API API --> DB Bastion -->|Entra ID| EntraID Nginx -->|JSON logs| AMA AMA --> LAW LAW --> Sentinel Sentinel -->|incident| LogicApp LogicApp -->|Deny rule| NSG style Internet fill:#e0e0e0,stroke:#333,color:#000 style Edge fill:#fff3e0,stroke:#ff9800,color:#000 style App fill:#e3f2fd,stroke:#2196f3,color:#000 style Data fill:#fce4ec,stroke:#e91e63,color:#000 style Mgmt fill:#e8f5e9,stroke:#4caf50,color:#000 style SOC fill:#f3e5f5,stroke:#9c27b0,color:#000 ``` ## 安全层级 ### 层级 1 - 边界与管理平面 **问题:** 22 端口向全球开放,静态 SSH 密钥存储于磁盘。 **解决方案:** 完全移除虚拟机公网 IP。仅通过使用 Microsoft Entra ID 身份的 Azure Bastion 进行访问。 | 组件 | 实施方案 | |------|----------| | 虚拟机访问 | Azure Bastion Standard (已启用隧道) | | 认证方式 | Microsoft Entra ID (AADSSHLoginForLinux 扩展) | | 授权策略 | RBAC 角色:虚拟机管理员登录 | | 网络配置 | NSG 22 端口仅允许特定 IP + Bastion 子网访问 | | 保护措施 | VNet 资源锁 (CanNotDelete) | ![第2天 - Entra ID 登录](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/95caffb78d051101.png) ### 层级 2 - API 身份网关 **问题:** 任何匿名请求均可读取、修改或删除数据。 **解决方案:** 部署 oauth2-proxy 作为安全边车,在将任何请求转发至 FastAPI 前验证 Microsoft Entra ID JWT 令牌。 | 组件 | 实施方案 | |------|----------| | 身份提供商 | Microsoft Entra ID (单租户) | | 令牌类型 | Bearer JWT (v2.0 访问令牌) | | 代理工具 | oauth2-proxy v7.6.0 运行于 4180 端口 | | 应用注册 | api://1a557f7c-0ac6-4232-8ecd-e3ed0fe7321f | | 网络策略 | 移除 8000 端口,FastAPI 不可直接访问 | **测试结果:** - 匿名请求:302 重定向至 Microsoft 登录页 - 无效令牌:302 重定向至 Microsoft 登录页 - 有效 Entra ID 令牌:200 OK 并返回数据 ![第3天 - 令牌测试](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/abeeb4506a051102.png) ### 层级 3 - 数据隔离 **问题:** PostgreSQL 拥有公网 IP 且防火墙规则允许所有连接。 **解决方案:** 将数据库迁移至 VNet 集成并配置私有 DNS 区域。实现零公网暴露。 | 组件 | 实施方案 | |------|----------| | 网络配置 | VNet 集成 (snet-db 10.0.3.0/24,已委托) | | DNS 配置 | 私有 DNS 区域:vladvontranssylvanien.private.postgres.database.azure.com | | 公网访问 | 已禁用 | | 数据迁移 | 通过 pg_dump 导出,在 VNet 内使用 psql 恢复 | **测试结果:** - 从虚拟机连接:200 OK,返回 5 条记录 - 从互联网连接:DNS 解析失败,主机未知 ![第4天 - 从虚拟机成功连接数据库](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/dbb042e397051102.png) ![第4天 - 从外部连接数据库失败](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/b4f043128c051103.png) ### 层级 4 - 边缘安全 **问题:** oauth2-proxy 直接暴露于 80 端口,无加密,无 WAF。 **解决方案:** Nginx 边缘代理提供 TLS、安全头、速率限制和自定义 WAF 规则。 | 组件 | 实施方案 | |------|----------| | TLS 配置 | 自签名证书,仅启用 TLS 1.2/1.3 | | HSTS | max-age=31536000; includeSubDomains | | 安全头 | X-Content-Type-Options, X-Frame-Options: DENY | | 速率限制 | 10 请求/秒,突发 20,返回 429 | | WAF 规则 | 使用 Nginx map 指令的自定义规则阻断 SQL 注入和 XSS | | Fail2Ban | 在 60 秒内触发 10 次以上 403 错误的 IP 将被封禁 1 小时 | **WAF 说明:** 由于 Ubuntu 22.04 上的 Nginx 1.18 缺少 ModSecurity OWASP CRS 预编译包,我们使用 Nginx map 指令实现了自定义 WAF,功能等同于 OWASP CRS 规则 942100 (SQL 注入) 和 941100 (XSS)。 **测试结果:** - HTTPS 请求:302 重定向,包含 HSTS 和安全头 - SQL 注入尝试:403 禁止访问 - 快速请求:429 请求过多 ![第5天 - HTTPS 和 WAF](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/6918835948051104.png) ![第5天 - 速率限制](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/4bce7a5f94051105.png) ### 层级 5 - 监控与自动化事件响应 **问题:** 日志孤立存储于虚拟机。缺乏可见性。无自动化响应。 **解决方案:** 基于 Microsoft Sentinel 的云原生安全运营中心与自动化 IP 阻断。 | 组件 | 实施方案 | |------|----------| | 日志格式 | Nginx JSON 结构化日志 | | 传输链路 | rsyslog -> Azure Monitor Agent -> Log Analytics | | SIEM 平台 | Microsoft Sentinel 部署在 law-vladvontranssylvanien | | DCR 规则 | 数据收集规则流式传输 local7 syslog | | 分析规则 | KQL 查询检测单 IP 在 30 分钟内超过 10 次 SQL 注入尝试 | | 自动化工具 | Logic App Playbook 配合托管身份 | | 响应动作 | 自动在 NSG 中为攻击 IP 创建拒绝规则 | **KQL 查询 (SQLi 猎手):** ``` Syslog | where TimeGenerated >= ago(30m) | where Facility == "local7" | where SyslogMessage has "UNION" and SyslogMessage has "403" | extend cleanMsg = extract(@'nginx: ({.*})', 1, SyslogMessage) | extend payload = parse_json(cleanMsg) | extend ClientIp = tostring(payload.remote_addr) | where isnotempty(ClientIp) | summarize AttemptCount = count() by ClientIp | where AttemptCount > 10 ``` **测试结果:** - 发送 50 个 SQL 注入请求:Sentinel 生成事件 (高严重级别) - Logic App 触发:自动创建 Deny-SQLi-Attack 的 NSG 规则 ![第6天 - Log Analytics SQL 注入日志](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/126e6ac08c051106.png) ![第6天 - KQL 查询结果](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/d598da3e06051107.png) ![第6天 - Sentinel 事件](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/534e73749a051107.png) ![第6天 - NSG 自动阻断](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/0a208480fc051108.png) ## 附加功能 | 功能 | 实施方案 | |------|----------| | 资源锁 | VNet 配置 CanNotDelete,删除操作因 ScopeLocked 错误而受阻 | | 活动日志 | Azure Monitor 跟踪所有 NSG 修改,记录调用者和时间戳 | | Fail2Ban | 基于 Nginx 403 模式的操作系统级 IP 封禁 | | 自动化 SOC | 从攻击到阻断的全自动流水线,无需人工干预 | | Key Vault | 数据库密码和 M2M 客户端密钥存储在 Azure Key Vault 中,通过托管身份获取 | | 机器间认证 | 使用从 Key Vault 检索的密钥测试客户端凭据流 | | 地理位置可视化 | Sentinel 工作簿通过世界地图展示 SQL 注入攻击来源 | | 架构图 | 展示所有 5 个安全层级和数据流的 Mermaid 图 | ![附加 - Key Vault](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/ebce7d0252051109.png) ![附加 - M2M 认证](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/c67e294a65051110.png) ![附加 - 地理位置可视化](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/f462f99f78051111.png) ## 修改的文件 | 文件 | 变更内容 | |------|----------| | vm.tf | 从网卡移除公网 IP (符合 Azure Policy) | | outputs.tf | 更新为私有 IP 和 az ssh 命令 | ## 部署 ``` git clone https://github.com/VladvonTranssylvanien/learningsteps-lockdown cd learningsteps-lockdown python3 deploy.py ``` 基础部署完成后,应用如上所述的安全加固措施。
标签:AppImage, AV绕过, Azure Bastion, Azure安全, Entra ID, FastAPI, JWT认证, Microsoft Sentinel, Nginx WAF, PostgreSQL, Streamlit, Web应用防火墙, 云计算安全, 多层防御, 测试用例, 私有数据库, 端到端安全加固, 网络安全, 自动事件响应, 访问控制, 逆向工具, 隐私保护, 零信任架构