BabsBBG/project-citadel
GitHub: BabsBBG/project-citadel
以虚构金融公司 Nexus Financial Services 为场景,在 Azure 免费层上端到端构建一套涵盖身份、网络、计算、存储、机密、日志、态势管理、SIEM 检测、事件响应与合规策略的安全云环境实施方案。
Stars: 1 | Forks: 0
# Citadel 项目
### 具备监控与威胁检测功能的安全 Azure 云环境
**客户:** Nexus Financial Services(虚拟) | **工程师:** Tobi Babalola
## 概述
Citadel 项目是一个为 Nexus Financial Services(一家正在建立其首个安全云环境的虚构中型金融科技公司)构建的端到端 Azure 云安全实施方案。该项目涵盖了云安全的各个层面:身份、网络、计算、存储、机密管理、日志记录、威胁检测、事件响应、合规执行以及基础设施即代码。
该项目旨在反映真实的安全工程决策,以理解每项控制措施存在的理由以及缺少它们可能导致的后果。默认实施最小权限原则,采用身份优先架构,推行持续合规而非单点时间加固,并包含从检测到遏制、完整的 SOC 风格事件响应工作流。
** ---
## 架构
```
┌─────────────────────────────────────────────┐
│ NEXUS FINANCIAL SERVICES │
│ Azure Subscription │
└─────────────────────────────────────────────┘
│
┌────────────────────▼────────────────────────┐
│ Citadel-RG │
│ Region: West US 2 │
└─────────────────────────────────────────────┘
│
┌───────────────────────────────┼────────────────────────────┐
│ │ │
┌────────▼─────────┐ ┌─────────▼────────┐ ┌─────────▼────────┐
│ IDENTITY LAYER │ │ NETWORK LAYER │ │ SECRETS LAYER │
│ │ │ │ │ │
│ Entra ID │ │ Citadel-VNet │ │ Citadel-KV-0 │
│ Abigail Analyst │ │ 10.0.0.0/16 │ │ Key Vault │
│ SecurityTeam │ │ │ │ Managed Identity│
│ RBAC: Reader │ │ PublicSubnet │ │ Access Policies │
│ MFA: Enabled │ │ 10.0.1.0/24 │ └──────────────────┘
└──────────────────┘ │ │
│ PrivateSubnet │
│ 10.0.2.0/24 │
│ │
│ Citadel-NSG │
│ Allow SSH: MyIP │
│ Deny: All │
└────────┬─────────┘
│
┌────────▼─────────┐
│ COMPUTE LAYER │
│ │
│ Citadel-VM │
│ Ubuntu 24.04 │
│ SSH Key Auth │
│ Root: Disabled │
│ Passwd: Off │
└────────┬─────────┘
│
┌──────────────────▼──────────────────────────┐
│ STORAGE LAYER │
│ │
│ citadelstore │ citadel-data container │
│ TLS 1.2 │ Private Access Only │
│ HTTPS Only │ Entra ID Auth │
│ No Public Blob │ No Key Access │
└──────────────────┬──────────────────────────┘
│
┌──────────────────▼──────────────────────────┐
│ VISIBILITY LAYER │
│ │
│ Citadel-LAW │
│ Log Analytics Workspace │
│ │
│ VM Logs (AMA) │ Storage Diag Settings │
│ Syslog (DCR) │ Azure Activity Logs │
│ auth/authpriv │ Heartbeat Alerts │
└──────────────────┬──────────────────────────┘
│
┌─────────────────────────────┼──────────────────────────┐
│ │ │
┌────────▼──────────┐ ┌──────────▼──────────┐ ┌──────────▼──────────┐
│ POSTURE LAYER │ │ DETECTION LAYER │ │ COMPLIANCE LAYER │
│ │ │ │ │ │
│ Defender for │ │ Microsoft Sentinel │ │ Azure Policy │
│ Cloud │ │ │ │ │
│ Foundational │ │ Azure Activity │ │ SecureTransfer │
│ CSPM │ │ Connector │ │ NetworkAccess │
│ │ │ KQL Detection Rule │ │ PublicAccess │
│ 50/63 controls │ │ Failed Login Alert │ │ All: Audit Mode │
│ 0 Critical │ │ Threshold: 3 hits │ │ │
│ 0 High findings │ │ Window: 5 minutes │ │ Scope: Citadel-RG │
└───────────────────┘ └──────────────────────┘ └─────────────────────┘
```
## 构建内容
| 层级 | 服务 | 配置 |
|-------|---------|---------------|
| 身份 | Entra ID | 用户、组、RBAC、MFA |
| 网络 | Virtual Network | VNet、子网、NSG 规则 |
| 计算 | Virtual Machine | Ubuntu 24.04、SSH 密钥、加固 |
| 存储 | Storage Account | 专用、HTTPS、Entra ID 认证 |
| 机密 | Key Vault | 托管标识、访问策略 |
| 日志记录 | Log Analytics | AMA、DCR、诊断设置 |
| 警报 | Azure Monitor | 心跳警报规则 |
| 安全态势 | Defender for Cloud | 基础 CSPM,50/63 项控制 |
| SIEM | Microsoft Sentinel | Azure Activity 连接器,KQL 规则 |
| 合规性 | Azure Policy | 3 项策略,审计模式 |
| IaC | ARM Template | 完整的 RG 导出 |
## 实施说明
### 模块 1 — 身份与访问管理
**目标:** 在部署任何资源之前强制实施最小权限和强身份验证。
在 Entra ID 中创建了一个非管理员用户 `abigail.analyst`,日常操作绝不应在全局管理员账户下运行。将其分配至 `SecurityTeam` 组,以实现基于角色的规模化访问管理。在订阅级别分配了 `Reader` RBAC 角色 —— 默认为只读,任何写入操作都需要显式授权。为所有非管理员账户启用了 MFA。
**核心原则:** 身份是新的边界。每一个访问决策都流经 Entra ID。
### 模块 2 — 网络安全
**目标:** 对环境进行网络分段并显式控制所有流量。
构建了包含公用子网和专用子网的 `Citadel-VNet`,因为具有不同信任级别的工作负载永远不应共享同一个网段。部署了带有两条入站规则的 `Citadel-NSG`:
- `Allow-SSH-MyIP`(优先级 100) - 仅允许来自工程师 IP 的 SSH
- `Deny-All-Inbound`(优先级 200) - 阻断其他所有流量
将此 NSG 关联到 `Citadel-PublicSubnet`。任何流量如果不显式通过这些规则,都无法到达 VM。
### 模块 3 — VM 部署与加固
**目标:** 在安全的网络边界内部署计算资源并减少攻击面。
在 `Citadel-PublicSubnet` 内部署了 `Citadel-VM`(Ubuntu 24.04 LTS,Standard_B1s)。在部署时强制使用 SSH 密钥身份验证 —— 从未启用过密码身份验证。
部署后的加固:
```
# 禁用 root 登录
sudo sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config
# 禁用密码认证
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
# 应用更改
sudo systemctl restart ssh
# 验证
sudo grep -E "PermitRootLogin|PasswordAuthentication" /etc/ssh/sshd_config
```
**结果:** `PermitRootLogin no` | `PasswordAuthentication no`
### 模块 4 — 存储安全
**目标:** 消除最常见的云存储错误配置。
在创建存储账户时强制执行了四项安全控制:
| 控制 | 设置 | 原因 |
|---------|---------|-----|
| 安全传输 | 已启用 | 强制使用 HTTPS,禁止明文 HTTP |
| Blob 公共访问 | 已禁用 | 任何容器都不允许匿名读取 |
| 存储账户密钥访问 | 已禁用 | 消除共享密钥身份验证,强制使用 Entra ID |
| 最低 TLS 版本 | 1.2 | 阻止已弃用的 TLS 1.0/1.1 |
**验证:** 上传文件至 `citadel-data` 容器后,尝试直接通过 URL 访问 —— 返回 `PublicAccessNotPermitted`。
### 模块 5 — 机密管理 (Key Vault)
**目标:** 使用托管标识消除计算资源中的硬编码凭证。
使用保管库访问策略权限模型创建了 `Citadel-KV-0`。存储了一个模拟的生产机密:
```
Name: NovaPay-DB-ConnectionString
Value: Server=nexusfinancial-db.postgres.database.azure.com;Database=novapayprod;User=dbadmin;Password=Citadel@2026!
Type: database/connection-string
```
在 `Citadel-VM` 上启用了系统分配的托管标识。授予了 Key Vault 访问策略 —— 仅对机密具有 `Get` 和 `List` 权限。没有其他权限。最小权限原则应用于机密访问。
**概念验证 - 零硬编码凭证从 VM 检索机密:**
```
az login --identity
az keyvault secret show --vault-name Citadel-KV-0 --name NovaPay-DB-ConnectionString --query value -o tsv
```
**输出:** `Server=nexusfinancial-db.postgres.database.azure.com;Database=novapayprod;User=dbadmin;Password=Citadel@2026!`
**链路:** VM → 托管标识 (MSI) → Azure AD Token → Key Vault 访问策略 → 返回机密。VM 上任何地方都没有存储密码。
### 模块 6 — 日志记录与监控
**目标:** 在叠加威胁检测功能之前,建立对环境的完整可见性。
创建了 `Citadel-LAW` Log Analytics Workspace,作为所有资源的集中日志目标。
**VM 日志收集:**
- 通过 Azure Monitor Agent 在 Monitoring → Logs 将 VM 连接到工作区
- 创建了 `Citadel-DCR-Syslog` 数据收集规则,针对 LOG_DEBUG 级别的 `auth` 和 `authpriv` Syslog 设施
**存储日志收集:**
- 在 blob 服务上启用了诊断设置 - StorageRead、StorageWrite、StorageDelete → `Citadel-LAW`
**警报:**
- 创建了 `Citadel-Alert-VMHeartbeat` - 当 VM 停止向工作区发送心跳信号时触发
### 模块 7 — 云安全态势 (Defender for Cloud)
**目标:** 根据安全最佳实践对环境进行持续自动化评估。
在订阅上启用了基础 CSPM(免费层)。评估完成后:
| 指标 | 结果 |
|--------|--------|
| 已评估资源 | 6 |
| 严重发现 | 0 |
| 高危发现 | 0 |
| MCSB 控制通过数 | 50/63 |
| 合规领域 | NS, IM, PA, DP, AM, LT, IR, PV, ES, BR, DS, GS |
**Defender 识别出的已知缺陷(未来改进点):**
- 未在 VM 上配置 Azure Backup
- 未针对高严重性警报启用电子邮件通知
- 未启用 Azure Disk Encryption
- 未部署漏洞评估解决方案
- 未安装 Guest Attestation 扩展
这些已被刻意记录下来
### 模块 8 — SIEM (Microsoft Sentinel)
**目标:** 在日志记录管道之上构建 SOC 级别的检测和警报。
部署了 Sentinel 并连接到 `Citadel-LAW`。
**数据连接器 — Azure Activity:**
通过 Azure Policy 分配向导进行连接 - 将所有订阅级别的活动日志流式传输到工作区。
**检测规则 — 失败的登录尝试:**
```
AzureActivity
| where OperationNameValue contains "signin" or ActivityStatusValue == "Failed"
| where TimeGenerated > ago(5m)
| summarize FailedAttempts = count() by CallerIpAddress, Caller
| where FailedAttempts >= 3
```
- 严重性:中等
- 评估频率:每 5 分钟
- 事件创建:已启用
### 模块 9 — 事件模拟与响应
**目标:** 端到端验证完整的检测管道,并演示 SOC 响应工作流。
#### 攻击模拟
使用一个不存在的密钥文件对 `Citadel-VM` 执行了 15 次 SSH 暴力破解尝试:
```
for ($i=1; $i -le 15; $i++) {
ssh -i "wrongkey.pem" -o StrictHostKeyChecking=no -o ConnectTimeout=5 azureuser@20.3.20.191
Start-Sleep -Seconds 2
}
```
**结果:** 15 × `Permission denied (publickey)` - 连接尝试已记录在 VM 上。
#### 调查 — VM 端
```
sudo journalctl -u ssh --since "1 hour ago" | tail -20
```
**发现:** 在 systemd journal 的 preauth 阶段确认了来自 `197.210.52.203` 的全部 15 次连接重置。
#### 调查 — Log Analytics
```
Syslog
| where Facility == "auth" or Facility == "authpriv"
| where TimeGenerated > ago(1h)
| where SyslogMessage contains "197.210.52.203"
| project TimeGenerated, Facility, SyslogMessage
| order by TimeGenerated desc
```
**发现:** 在 Log Analytics 中确认了攻击者 IP `197.210.52.203` - 会话事件通过云端日志管道进行了追踪。
#### MITRE ATT&CK 映射
| 战术 | 技术 | ID | 观察到的活动 |
|--------|-----------|-----|---------|
| 初始访问 | 暴力破解:密码猜测 | T1110.001 | 来自单一 IP 的 15 次失败 SSH 尝试 |
| 初始访问 | 有效账户 | T1078 | 攻击者针对已知账户 `azureuser` |
| 发现 | 网络服务发现 | T1046 | 在定位端口 22 之前隐含了侦察行为 |
| 防御规避 | 使用备用身份验证材料 | T1550 | 尝试绕过公钥认证 |
| 初始访问 | 利用面向公众的应用程序 | T1190 | 推荐使用 Azure Bastion,已记录为已知缺陷 |
#### 遏制响应
添加了阻断攻击者 IP 的 NSG 入站拒绝规则:
| 规则 | 优先级 | 源 IP | 操作 |
|------|----------|-----------|--------|
| Allow-SSH-MyIP | 100 | 工程师 IP | 允许 |
| Deny-Attacker-IP | 105 | 197.210.52.203 | 拒绝 |
| Deny-All-Inbound | 200 | 任意 | 拒绝 |
**结果:** 攻击者 IP 已在网络层被阻断。后续的连接尝试将在到达 VM 之前被丢弃。
### 模块 10 — 合规执行 (Azure Policy)
**目标:** 将一次性手动加固转变为持续的自动化合规。
将三项内置策略分配给 `Citadel-RG` 范围,并设为审计模式:
| 策略 | 分配名称 | 强制执行的内容 |
|--------|----------------|------------------|
| 应启用安全传输到存储账户 | Citadel-Policy-SecureTransfer | 所有存储强制仅使用 HTTPS |
| 存储账户应限制网络访问 | Citadel-Policy-NetworkAccess | 禁止无限制的网络访问 |
| 应禁止存储账户公共访问 | Citadel-Policy-StoragePublicAccess | 禁止匿名 blob 访问 |
**为何采用审计模式:** 在生产环境中,应从审计模式开始以获取可见性,然后再切换为拒绝模式。在活跃环境中直接切换为拒绝模式可能会破坏现有的不合规资源
### 模块 11 — 基础设施即代码 (ARM Template)
**目标:** 使整个环境可复现,而不仅仅是文档化。
通过 Portal → Resource Groups → Export template 将 `Citadel-RG` 导出为 ARM 模板。
**输出:**
- `template.json` — 完整的环境定义
- `parameters.json` — 用于重新部署的参数化值
Portal 还生成了相同基础设施的 **Bicep** 版本,这两种格式均可在 `/arm-template` 目录中找到。
## 仓库结构
```
project-citadel/
├── README.md
├── arm-template/
│ ├── template.json
│ └── parameters.json
├── screenshots/
│ ├── 01-identity/
│ ├── 02-network/
│ ├── 03-vm-hardening/
│ ├── 04-storage/
│ ├── 05-key-vault/
│ ├── 06-logging/
│ ├── 07-defender/
│ ├── 08-sentinel/
│ ├── 09-incident-response/
│ ├── 10-azure-policy/
│ └── 11-arm-template/
└── incident-report/
└── citadel-incident-report.md
```
## 关键经验与问题
| 问题 | 根本原因 | 解决方案 |
|-------|-----------|-----|
| East US 中的 vCPU 配额限制 | 免费层订阅限制 | 在 West US 2 中重新构建了所有内容 |
| 找不到 `sshd` 服务 | Ubuntu 24.04 使用 `ssh` 而不是 `sshd` | `sudo systemctl restart ssh` |
| 禁用密钥访问后 Portal 被阻止 | 存储上没有 Entra ID 角色 | 通过 IAM 分配了 Storage Blob Data Contributor |
| 内容中心重定向到 Defender portal | Microsoft 将其永久迁移 | 使用 defender.microsoft.com 作为内容中心 |
| Azure Activity 连接器上的修复任务失败 | `Microsoft.PolicyInsights` 未注册 | 手动注册提供程序并创建了任务 |
| Ubuntu 24.04 上的 Syslog 为空 | 从 syslog 迁移到了 systemd journal | 使用 `journalctl -u ssh` 进行 VM 端调查 |
| 缺少旧版代理管理 | 已从较新的工作区中移除 | 改用数据收集规则 (DCR) |
| 托管标识 token 终结点无响应 | VM 已解除分配,连接丢失 | 重启 VM,重新安装 Azure CLI |
## 展示的技能
- Azure 身份与访问管理(Entra ID、RBAC、MFA)
- 网络分段与流量控制(VNet、NSG)
- Linux 服务器加固(SSH、sshd_config)
- 云存储安全(访问控制、Entra ID 认证)
- 机密管理(Key Vault、托管标识)
- 日志摄取与管道配置(AMA、DCR、诊断设置)
- 云安全态势管理(Defender for Cloud、MCSB)
- SIEM 配置与 KQL 检测工程(Microsoft Sentinel)
- 事件模拟、日志调查与遏制响应
- 合规策略执行(Azure Policy)
- 基础设施即代码(ARM 模板、Bicep、Terraform 导出)
- MITRE ATT&CK 框架映射
*Project Citadel — Nexus Financial Services | 基于 Microsoft Azure 免费层构建*
## 构建内容
| 层级 | 服务 | 配置 |
|-------|---------|---------------|
| 身份 | Entra ID | 用户、组、RBAC、MFA |
| 网络 | Virtual Network | VNet、子网、NSG 规则 |
| 计算 | Virtual Machine | Ubuntu 24.04、SSH 密钥、加固 |
| 存储 | Storage Account | 专用、HTTPS、Entra ID 认证 |
| 机密 | Key Vault | 托管标识、访问策略 |
| 日志记录 | Log Analytics | AMA、DCR、诊断设置 |
| 警报 | Azure Monitor | 心跳警报规则 |
| 安全态势 | Defender for Cloud | 基础 CSPM,50/63 项控制 |
| SIEM | Microsoft Sentinel | Azure Activity 连接器,KQL 规则 |
| 合规性 | Azure Policy | 3 项策略,审计模式 |
| IaC | ARM Template | 完整的 RG 导出 |
## 实施说明
### 模块 1 — 身份与访问管理
**目标:** 在部署任何资源之前强制实施最小权限和强身份验证。
在 Entra ID 中创建了一个非管理员用户 `abigail.analyst`,日常操作绝不应在全局管理员账户下运行。将其分配至 `SecurityTeam` 组,以实现基于角色的规模化访问管理。在订阅级别分配了 `Reader` RBAC 角色 —— 默认为只读,任何写入操作都需要显式授权。为所有非管理员账户启用了 MFA。
**核心原则:** 身份是新的边界。每一个访问决策都流经 Entra ID。
### 模块 2 — 网络安全
**目标:** 对环境进行网络分段并显式控制所有流量。
构建了包含公用子网和专用子网的 `Citadel-VNet`,因为具有不同信任级别的工作负载永远不应共享同一个网段。部署了带有两条入站规则的 `Citadel-NSG`:
- `Allow-SSH-MyIP`(优先级 100) - 仅允许来自工程师 IP 的 SSH
- `Deny-All-Inbound`(优先级 200) - 阻断其他所有流量
将此 NSG 关联到 `Citadel-PublicSubnet`。任何流量如果不显式通过这些规则,都无法到达 VM。
### 模块 3 — VM 部署与加固
**目标:** 在安全的网络边界内部署计算资源并减少攻击面。
在 `Citadel-PublicSubnet` 内部署了 `Citadel-VM`(Ubuntu 24.04 LTS,Standard_B1s)。在部署时强制使用 SSH 密钥身份验证 —— 从未启用过密码身份验证。
部署后的加固:
```
# 禁用 root 登录
sudo sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config
# 禁用密码认证
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
# 应用更改
sudo systemctl restart ssh
# 验证
sudo grep -E "PermitRootLogin|PasswordAuthentication" /etc/ssh/sshd_config
```
**结果:** `PermitRootLogin no` | `PasswordAuthentication no`
### 模块 4 — 存储安全
**目标:** 消除最常见的云存储错误配置。
在创建存储账户时强制执行了四项安全控制:
| 控制 | 设置 | 原因 |
|---------|---------|-----|
| 安全传输 | 已启用 | 强制使用 HTTPS,禁止明文 HTTP |
| Blob 公共访问 | 已禁用 | 任何容器都不允许匿名读取 |
| 存储账户密钥访问 | 已禁用 | 消除共享密钥身份验证,强制使用 Entra ID |
| 最低 TLS 版本 | 1.2 | 阻止已弃用的 TLS 1.0/1.1 |
**验证:** 上传文件至 `citadel-data` 容器后,尝试直接通过 URL 访问 —— 返回 `PublicAccessNotPermitted`。
### 模块 5 — 机密管理 (Key Vault)
**目标:** 使用托管标识消除计算资源中的硬编码凭证。
使用保管库访问策略权限模型创建了 `Citadel-KV-0`。存储了一个模拟的生产机密:
```
Name: NovaPay-DB-ConnectionString
Value: Server=nexusfinancial-db.postgres.database.azure.com;Database=novapayprod;User=dbadmin;Password=Citadel@2026!
Type: database/connection-string
```
在 `Citadel-VM` 上启用了系统分配的托管标识。授予了 Key Vault 访问策略 —— 仅对机密具有 `Get` 和 `List` 权限。没有其他权限。最小权限原则应用于机密访问。
**概念验证 - 零硬编码凭证从 VM 检索机密:**
```
az login --identity
az keyvault secret show --vault-name Citadel-KV-0 --name NovaPay-DB-ConnectionString --query value -o tsv
```
**输出:** `Server=nexusfinancial-db.postgres.database.azure.com;Database=novapayprod;User=dbadmin;Password=Citadel@2026!`
**链路:** VM → 托管标识 (MSI) → Azure AD Token → Key Vault 访问策略 → 返回机密。VM 上任何地方都没有存储密码。
### 模块 6 — 日志记录与监控
**目标:** 在叠加威胁检测功能之前,建立对环境的完整可见性。
创建了 `Citadel-LAW` Log Analytics Workspace,作为所有资源的集中日志目标。
**VM 日志收集:**
- 通过 Azure Monitor Agent 在 Monitoring → Logs 将 VM 连接到工作区
- 创建了 `Citadel-DCR-Syslog` 数据收集规则,针对 LOG_DEBUG 级别的 `auth` 和 `authpriv` Syslog 设施
**存储日志收集:**
- 在 blob 服务上启用了诊断设置 - StorageRead、StorageWrite、StorageDelete → `Citadel-LAW`
**警报:**
- 创建了 `Citadel-Alert-VMHeartbeat` - 当 VM 停止向工作区发送心跳信号时触发
### 模块 7 — 云安全态势 (Defender for Cloud)
**目标:** 根据安全最佳实践对环境进行持续自动化评估。
在订阅上启用了基础 CSPM(免费层)。评估完成后:
| 指标 | 结果 |
|--------|--------|
| 已评估资源 | 6 |
| 严重发现 | 0 |
| 高危发现 | 0 |
| MCSB 控制通过数 | 50/63 |
| 合规领域 | NS, IM, PA, DP, AM, LT, IR, PV, ES, BR, DS, GS |
**Defender 识别出的已知缺陷(未来改进点):**
- 未在 VM 上配置 Azure Backup
- 未针对高严重性警报启用电子邮件通知
- 未启用 Azure Disk Encryption
- 未部署漏洞评估解决方案
- 未安装 Guest Attestation 扩展
这些已被刻意记录下来
### 模块 8 — SIEM (Microsoft Sentinel)
**目标:** 在日志记录管道之上构建 SOC 级别的检测和警报。
部署了 Sentinel 并连接到 `Citadel-LAW`。
**数据连接器 — Azure Activity:**
通过 Azure Policy 分配向导进行连接 - 将所有订阅级别的活动日志流式传输到工作区。
**检测规则 — 失败的登录尝试:**
```
AzureActivity
| where OperationNameValue contains "signin" or ActivityStatusValue == "Failed"
| where TimeGenerated > ago(5m)
| summarize FailedAttempts = count() by CallerIpAddress, Caller
| where FailedAttempts >= 3
```
- 严重性:中等
- 评估频率:每 5 分钟
- 事件创建:已启用
### 模块 9 — 事件模拟与响应
**目标:** 端到端验证完整的检测管道,并演示 SOC 响应工作流。
#### 攻击模拟
使用一个不存在的密钥文件对 `Citadel-VM` 执行了 15 次 SSH 暴力破解尝试:
```
for ($i=1; $i -le 15; $i++) {
ssh -i "wrongkey.pem" -o StrictHostKeyChecking=no -o ConnectTimeout=5 azureuser@20.3.20.191
Start-Sleep -Seconds 2
}
```
**结果:** 15 × `Permission denied (publickey)` - 连接尝试已记录在 VM 上。
#### 调查 — VM 端
```
sudo journalctl -u ssh --since "1 hour ago" | tail -20
```
**发现:** 在 systemd journal 的 preauth 阶段确认了来自 `197.210.52.203` 的全部 15 次连接重置。
#### 调查 — Log Analytics
```
Syslog
| where Facility == "auth" or Facility == "authpriv"
| where TimeGenerated > ago(1h)
| where SyslogMessage contains "197.210.52.203"
| project TimeGenerated, Facility, SyslogMessage
| order by TimeGenerated desc
```
**发现:** 在 Log Analytics 中确认了攻击者 IP `197.210.52.203` - 会话事件通过云端日志管道进行了追踪。
#### MITRE ATT&CK 映射
| 战术 | 技术 | ID | 观察到的活动 |
|--------|-----------|-----|---------|
| 初始访问 | 暴力破解:密码猜测 | T1110.001 | 来自单一 IP 的 15 次失败 SSH 尝试 |
| 初始访问 | 有效账户 | T1078 | 攻击者针对已知账户 `azureuser` |
| 发现 | 网络服务发现 | T1046 | 在定位端口 22 之前隐含了侦察行为 |
| 防御规避 | 使用备用身份验证材料 | T1550 | 尝试绕过公钥认证 |
| 初始访问 | 利用面向公众的应用程序 | T1190 | 推荐使用 Azure Bastion,已记录为已知缺陷 |
#### 遏制响应
添加了阻断攻击者 IP 的 NSG 入站拒绝规则:
| 规则 | 优先级 | 源 IP | 操作 |
|------|----------|-----------|--------|
| Allow-SSH-MyIP | 100 | 工程师 IP | 允许 |
| Deny-Attacker-IP | 105 | 197.210.52.203 | 拒绝 |
| Deny-All-Inbound | 200 | 任意 | 拒绝 |
**结果:** 攻击者 IP 已在网络层被阻断。后续的连接尝试将在到达 VM 之前被丢弃。
### 模块 10 — 合规执行 (Azure Policy)
**目标:** 将一次性手动加固转变为持续的自动化合规。
将三项内置策略分配给 `Citadel-RG` 范围,并设为审计模式:
| 策略 | 分配名称 | 强制执行的内容 |
|--------|----------------|------------------|
| 应启用安全传输到存储账户 | Citadel-Policy-SecureTransfer | 所有存储强制仅使用 HTTPS |
| 存储账户应限制网络访问 | Citadel-Policy-NetworkAccess | 禁止无限制的网络访问 |
| 应禁止存储账户公共访问 | Citadel-Policy-StoragePublicAccess | 禁止匿名 blob 访问 |
**为何采用审计模式:** 在生产环境中,应从审计模式开始以获取可见性,然后再切换为拒绝模式。在活跃环境中直接切换为拒绝模式可能会破坏现有的不合规资源
### 模块 11 — 基础设施即代码 (ARM Template)
**目标:** 使整个环境可复现,而不仅仅是文档化。
通过 Portal → Resource Groups → Export template 将 `Citadel-RG` 导出为 ARM 模板。
**输出:**
- `template.json` — 完整的环境定义
- `parameters.json` — 用于重新部署的参数化值
Portal 还生成了相同基础设施的 **Bicep** 版本,这两种格式均可在 `/arm-template` 目录中找到。
## 仓库结构
```
project-citadel/
├── README.md
├── arm-template/
│ ├── template.json
│ └── parameters.json
├── screenshots/
│ ├── 01-identity/
│ ├── 02-network/
│ ├── 03-vm-hardening/
│ ├── 04-storage/
│ ├── 05-key-vault/
│ ├── 06-logging/
│ ├── 07-defender/
│ ├── 08-sentinel/
│ ├── 09-incident-response/
│ ├── 10-azure-policy/
│ └── 11-arm-template/
└── incident-report/
└── citadel-incident-report.md
```
## 关键经验与问题
| 问题 | 根本原因 | 解决方案 |
|-------|-----------|-----|
| East US 中的 vCPU 配额限制 | 免费层订阅限制 | 在 West US 2 中重新构建了所有内容 |
| 找不到 `sshd` 服务 | Ubuntu 24.04 使用 `ssh` 而不是 `sshd` | `sudo systemctl restart ssh` |
| 禁用密钥访问后 Portal 被阻止 | 存储上没有 Entra ID 角色 | 通过 IAM 分配了 Storage Blob Data Contributor |
| 内容中心重定向到 Defender portal | Microsoft 将其永久迁移 | 使用 defender.microsoft.com 作为内容中心 |
| Azure Activity 连接器上的修复任务失败 | `Microsoft.PolicyInsights` 未注册 | 手动注册提供程序并创建了任务 |
| Ubuntu 24.04 上的 Syslog 为空 | 从 syslog 迁移到了 systemd journal | 使用 `journalctl -u ssh` 进行 VM 端调查 |
| 缺少旧版代理管理 | 已从较新的工作区中移除 | 改用数据收集规则 (DCR) |
| 托管标识 token 终结点无响应 | VM 已解除分配,连接丢失 | 重启 VM,重新安装 Azure CLI |
## 展示的技能
- Azure 身份与访问管理(Entra ID、RBAC、MFA)
- 网络分段与流量控制(VNet、NSG)
- Linux 服务器加固(SSH、sshd_config)
- 云存储安全(访问控制、Entra ID 认证)
- 机密管理(Key Vault、托管标识)
- 日志摄取与管道配置(AMA、DCR、诊断设置)
- 云安全态势管理(Defender for Cloud、MCSB)
- SIEM 配置与 KQL 检测工程(Microsoft Sentinel)
- 事件模拟、日志调查与遏制响应
- 合规策略执行(Azure Policy)
- 基础设施即代码(ARM 模板、Bicep、Terraform 导出)
- MITRE ATT&CK 框架映射
*Project Citadel — Nexus Financial Services | 基于 Microsoft Azure 免费层构建*标签:AMSI绕过, Azure, 云迁移, 威胁检测, 子域名变形, 安全合规, 安全工程, 安全日志, 安全架构, 持续合规, 端到端安全, 网络代理, 网络安全, 网络安全审计, 身份与访问管理, 金融科技, 隐私保护, 零信任架构