我在生产环境中看到的7个Azure安全缺口(以及如何修复它们)
Source: Dev.to
1. 网络安全组(NSG)规则不足
问题
网络安全组(NSG)是 Azure 虚拟机的主要网络层控制。生产环境中常出现过于宽松的入站规则,例如:
Allow * from 0.0.0.0/0- SSH(22)或 RDP(3389)对公网开放
实际案例
在一次安全审计中,发现 12 台生产 VM 的 SSH 对互联网开放。NSG 流日志显示 30 天内超过 50,000 次登录失败。
检测方法
Azure 门户
- 网络安全组 → 入站规则 – 查找:
- 源:
Any或0.0.0.0/0 - 端口:
22、3389、1433、5432
- 源:
- 查看每台 VM 的有效安全规则
KQL(NSG 流日志)
AzureNetworkAnalytics_CL
| where SubType_s == "FlowLog"
| where SrcIP_s !startswith "10."
and SrcIP_s !startswith "172."
and SrcIP_s !startswith "192.168."
| where DestPort_d in (22, 3389)
| summarize Attempts = count() by SrcIP_s, DestPort_d
| order by Attempts desc
解决方案
立即措施
- 删除 SSH/RDP 的
0.0.0.0/0访问 - 将可信的办公或 VPN IP 加入白名单
- 使用 Azure Bastion 实现安全远程访问
- 通过 Microsoft Defender for Cloud 启用 Just‑In‑Time (JIT) VM 访问
长期措施
- 采用 应用安全组 (ASG)
- 部署 Azure 防火墙 进行集中过滤
- 使用 Azure Policy 强制执行 NSG 标准
2. 缺失 Azure 备份策略
问题
许多团队误以为 Azure 会自动备份 VM,实际上并不会。生产工作负载中常发现没有恢复服务保管库或任何备份计划。
检测方法
Azure 门户
- 恢复服务保管库 → 备份项 – 与 VM 清单进行对比。
KQL 查询
Resources
| where type == "microsoft.compute/virtualmachines"
| project name, resourceGroup
| join kind=leftouter (
RecoveryServicesResources
| where type contains "protectedItems"
| extend vmName = tostring(split(properties.sourceResourceId, "/")[8])
| project vmName
) on $left.name == $right.vmName
| where isnull(vmName)
解决方案
- 按区域创建 恢复服务保管库。
- 定义符合 RPO/RTO 的备份策略。
- 启用 软删除。
- 每 季度 测试一次恢复。
- 通过 Azure Monitor 配置备份警报。
3. 认证方式薄弱
问题
基于密码的 SSH 与 RDP 访问仍然普遍。部分环境在多个管理员账户之间复用相同密码,形成单点故障。
检测方法
Linux
grep -i PasswordAuthentication /etc/ssh/sshd_config
grep -i PubkeyAuthentication /etc/ssh/sshd_config
Windows
- 检查 Azure AD 条件访问 策略。
- 查看 Azure AD 登录日志 中基于密码的登录记录。
解决方案
Linux
- 禁用密码认证:
PasswordAuthentication no - 强制 基于 SSH 密钥的认证。
- 将私钥存放在 Azure Key Vault 中。
- 为 Linux VM 启用 Azure AD 登录。
Windows
- 强制 多因素认证 (MFA)。
- 最小化本地管理员使用。
- 部署 特权访问工作站 (PAW)。
4. 传输中的数据未加密
问题
生产环境仍存在 HTTP 接口、未使用 TLS 的数据库以及 FTP 传输,即使涉及敏感数据。
检测方法
应用网关 / WAF 日志
AzureDiagnostics
| where ResourceType == "APPLICATIONGATEWAYS"
| where requestUri_s startswith "http://"
| summarize Count = count() by requestUri_s, clientIP_s
| order by Count desc
解决方案
- 强制 HTTPS 端到端。
- 将
http://重定向到https://。 - 为所有数据库连接启用 TLS 1.2+。
- 用 SFTP/FTPS 替代 FTP。
- 通过 Azure Key Vault 管理证书。
5. 角色‑基于访问控制 (RBAC) 不当
问题
开发人员常拥有 Contributor 或 Owner 权限,且作用域为订阅级别,违背最小特权原则。
检测方法
authorizationresources
| where type == "microsoft.authorization/roleassignments"
| where properties.roleDefinitionId contains "Owner"
or properties.roleDefinitionId contains "Contributor"
| project principalId, scope = tostring(properties.scope)
解决方案
- 定期进行 RBAC 审计。
- 移除不必要的订阅级别角色。
- 创建 自定义角色,仅保留最小权限。
- 使用 Azure AD 特权身份管理 (PIM)。
- 为高特权账户启用 访问审查。
6. 缺失活动日志警报
问题
关键变更(如 NSG 规则更新、VM 删除)未触发任何警报,导致团队无法及时获知。
检测方法
- Azure Monitor → 警报 – 按 活动日志 过滤,确认相关类别已被监控。
解决方案
为以下事件创建警报:
- NSG 规则变更
- VM 创建/删除
- RBAC 修改
- Defender for Cloud 策略更新
- Key Vault 访问变更
7. 管理和数据库端口暴露
问题
除 SSH/RDP 外,数据库端口和管理界面也常对互联网开放(如 SQL、MySQL、PostgreSQL、MongoDB、Redis)。
检测方法
AzureNetworkAnalytics_CL
| where SubType_s == "FlowLog"
| where DestPort_d in (1433, 3306, 5432, 8080, 8443, 27017, 6379)
| where SrcIP_s !startswith "10."
and SrcIP_s !startswith "172."
and SrcIP_s !startswith "192.168."
| summarize Count = count() by DestPort_d, DestIP_s
| order by Count desc
解决方案
- 关闭非必要端口。
- 为数据库访问使用 私有端点 / Private Link。
- 为基于 Web 的管理界面部署 带 WAF 的应用网关。
- 利用 Azure Bastion 实现安全远程管理。
- 参考 Defender for Cloud 的建议进行配置。
结论
Azure 安全是一个持续的过程,需要不断监控、定期审计和主动修复。大多数安全缺口来源于缺少防护措施,而非缺少工具。充分利用 Azure Policy、Defender for Cloud 与 基础设施即代码,可以在问题进入生产前将其拦截。
快速安全检查清单(≈ 85 分钟)
- 审计 NSG 规则中
0.0.0.0/0– 5 分钟 - 验证 VM 备份 – 10 分钟
- 检查 RBAC 分配 – 15 分钟
- 检查 SSH 密码认证 – 10 分钟
- 启用活动日志警报 – 20 分钟
- 扫描暴露的数据库端口 – 10 分钟
- 识别 HTTP 流量 – 15 分钟
讨论
你在生产环境中遇到过类似的 Azure 安全问题吗?你使用了哪些防护措施来防止它们?