mrezwanulbari/azure-security

GitHub: mrezwanulbari/azure-security

该仓库提供覆盖 Azure 云全链路的综合安全框架,整合 Sentinel SIEM、Defender、Azure Policy 与合规自动化,解决企业级云安全运营中的威胁检测、防护治理与合规落地问题。

Stars: 0 | Forks: 0

# Azure 安全 — 云安全框架与 Sentinel SIEM ![Azure](https://img.shields.io/badge/Azure-0078D4?style=for-the-badge&logo=microsoft-azure&logoColor=white) ![Sentinel](https://img.shields.io/badge/Sentinel-0078D4?style=for-the-badge&logo=microsoft-azure&logoColor=white) ![License](https://img.shields.io/badge/License-MIT-green.svg) ## 📋 目录 - [概述](#overview) - [架构](#architecture) - [仓库结构](#repository-structure) - [Microsoft Sentinel](#microsoft-sentinel) - [Microsoft Defender for Cloud](#microsoft-defender-for-cloud) - [Azure Policy 与治理](#azure-policy--governance) - [身份安全 (Entra ID)](#identity-security-entra-id) - [网络安全](#network-security) - [KQL 检测查询](#kql-detection-queries) - [Sigma 检测规则](#sigma-detection-rules) - [合规性自动化](#compliance-automation) - [事件响应](#incident-response) - [贡献](#contributing) ## 概述 本仓库提供了一个全面的 Azure 安全框架,涵盖身份保护、使用 Microsoft Sentinel 进行威胁检测、使用 Defender 进行云工作负载保护、使用 Azure Policy 进行治理,以及面向企业和政府云环境的合规性自动化。 ### 安全领域 | 领域 | Azure 服务 | 重点领域 | |---|---|---| | **身份与访问** | Entra ID, PIM, Conditional Access | Zero Trust 身份, MFA, 特权访问 | | **威胁检测** | Microsoft Sentinel, Defender XDR | SIEM/SOAR, 分析规则, 自动化 | | **工作负载保护** | Defender for Cloud, Servers, Storage | CSPM, CWP, 漏洞管理 | | **治理** | Azure Policy, Blueprints, Management Groups | 合规性, 护栏, 资源治理 | | **网络安全** | NSGs, Azure Firewall, WAF, DDoS Protection | 分段, 过滤, DDoS 缓解 | | **数据保护** | Key Vault, Information Protection, Purview | 加密, 分类, DLP | | **监控** | Monitor, Log Analytics, Workbooks | 集中日志记录, 告警, 可视化 | ## 架构 ### Azure 安全参考架构 ``` ┌─────────────────────────────────────────────────────────────────┐ │ Azure Management Groups │ │ ┌────────────────────────────────────────────────────────────┐ │ │ │ Root Management Group │ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────────────┐ │ │ │ │ │ Azure Policy│ │ RBAC │ │ Microsoft Defender │ │ │ │ │ │ (Org-wide) │ │ (Inherited)│ │ for Cloud (Org) │ │ │ │ │ └────────────┘ └────────────┘ └────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────┘ │ │ │ │ ┌───────────────────────┐ ┌────────────────────────────────┐ │ │ │ Security Subscription │ │ Logging Subscription │ │ │ │ ┌──────────────────┐ │ │ ┌────────────────────────┐ │ │ │ │ │ Microsoft Sentinel│ │ │ │ Log Analytics Workspace│ │ │ │ │ │ (Unified SIEM) │ │ │ │ (Central) │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ • Analytics Rules│ │ │ │ • Activity Logs │ │ │ │ │ │ • Playbooks │ │ │ │ • Diagnostic Logs │ │ │ │ │ │ • Workbooks │ │ │ │ • Security Events │ │ │ │ │ │ • Hunting Queries│ │ │ │ • NSG Flow Logs │ │ │ │ │ │ • Data Connectors│ │ │ │ • Entra ID Logs │ │ │ │ │ └──────────────────┘ │ │ └────────────────────────┘ │ │ │ └───────────────────────┘ └────────────────────────────────┘ │ │ │ │ ┌───────────────────────┐ ┌────────────────────────────────┐ │ │ │ Production Sub │ │ Development Sub │ │ │ │ ┌──────┐ ┌────────┐ │ │ ┌──────┐ ┌────────┐ │ │ │ │ │ VNets│ │Defender │ │ │ │ VNets│ │ Key │ │ │ │ │ │ VMs │ │for Cloud│ │ │ │ AKS │ │ Vault │ │ │ │ │ │ AKS │ │ (CSPM) │ │ │ │ SQL │ │ │ │ │ │ │ │ SQL │ │ │ │ │ │ │ │ │ │ │ │ │ └──────┘ └────────┘ │ │ └──────┘ └────────┘ │ │ │ └───────────────────────┘ └────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## 仓库结构 ``` azure-security/ ├── README.md ├── sentinel/ │ ├── analytics-rules/ │ │ ├── identity/ │ │ │ ├── brute-force-entra-id.yaml │ │ │ ├── mfa-bypass-detection.yaml │ │ │ ├── suspicious-service-principal.yaml │ │ │ └── privileged-role-assignment.yaml │ │ ├── cloud-infrastructure/ │ │ │ ├── nsg-rule-modification.yaml │ │ │ ├── key-vault-access-anomaly.yaml │ │ │ ├── storage-account-public-access.yaml │ │ │ └── vm-extension-installed.yaml │ │ └── threat-intelligence/ │ │ ├── ti-map-ip-to-signin.yaml │ │ └── ti-map-domain-to-dns.yaml │ ├── hunting-queries/ │ │ ├── identity-hunting.kql │ │ ├── network-hunting.kql │ │ ├── persistence-hunting.kql │ │ └── lateral-movement-hunting.kql │ ├── playbooks/ │ │ ├── isolate-compromised-vm/ │ │ │ └── azuredeploy.json │ │ ├── block-ip-on-firewall/ │ │ │ └── azuredeploy.json │ │ └── disable-compromised-user/ │ │ └── azuredeploy.json │ ├── workbooks/ │ │ ├── security-operations-overview.json │ │ └── identity-security-posture.json │ └── data-connectors/ │ └── connector-setup-guide.md ├── defender/ │ ├── configurations/ │ │ ├── defender-for-servers.md │ │ ├── defender-for-storage.md │ │ ├── defender-for-sql.md │ │ └── defender-for-containers.md │ ├── security-recommendations/ │ │ └── high-priority-recommendations.md │ └── docs/ │ └── cspm-implementation.md ├── policies/ │ ├── custom-policies/ │ │ ├── deny-public-ip.json │ │ ├── require-nsg-on-subnet.json │ │ ├── enforce-tls-minimum.json │ │ ├── require-key-vault-soft-delete.json │ │ └── deny-unmanaged-disk.json │ ├── initiatives/ │ │ ├── security-baseline-initiative.json │ │ └── logging-initiative.json │ └── docs/ │ └── policy-governance-guide.md ├── identity/ │ ├── conditional-access/ │ │ ├── require-mfa-all-users.json │ │ ├── block-legacy-auth.json │ │ ├── require-compliant-device.json │ │ └── named-locations.json │ ├── pim/ │ │ └── pim-role-settings.md │ └── docs/ │ └── zero-trust-identity-guide.md ├── network/ │ ├── nsg-rules/ │ │ ├── baseline-nsg-rules.json │ │ └── application-nsg-rules.json │ ├── azure-firewall/ │ │ └── firewall-policy-rules.json │ └── docs/ │ └── network-segmentation-guide.md ├── sigma-rules/ │ ├── azure-ad/ │ │ ├── azure-ad-mfa-disabled.yml │ │ ├── azure-ad-suspicious-signin.yml │ │ ├── azure-ad-app-registration.yml │ │ └── azure-ad-pim-activation.yml │ ├── azure-activity/ │ │ ├── azure-nsg-deleted.yml │ │ ├── azure-keyvault-secret-read.yml │ │ └── azure-resource-group-deleted.yml │ └── office365/ │ ├── o365-mailbox-forwarding.yml │ └── o365-admin-role-assigned.yml ├── compliance/ │ ├── cis-benchmark/ │ │ └── cis-azure-checks.md │ ├── nist-800-53/ │ │ └── nist-control-mapping.md │ └── mcsb/ │ └── mcsb-assessment-guide.md ├── incident-response/ │ ├── playbooks/ │ │ ├── compromised-entra-id-account.md │ │ ├── compromised-vm.md │ │ ├── data-exfiltration-storage.md │ │ └── ransomware-response.md │ └── kql/ │ ├── investigation-queries.kql │ └── forensic-timeline.kql └── docs/ ├── security-architecture.md ├── logging-strategy.md ├── sentinel-deployment-guide.md └── zero-trust-framework.md ``` ## Microsoft Sentinel ### 分析规则 #### 针对 Entra ID 的暴力破解 ``` # sentinel/analytics-rules/identity/brute-force-entra-id.yaml name: Brute Force Attack Against Entra ID description: | Detects multiple failed sign-in attempts from a single IP address followed by a successful sign-in, indicating a potential brute force attack against Azure Active Directory. severity: High queryFrequency: PT5M queryPeriod: PT1H triggerOperator: GreaterThan triggerThreshold: 0 tactics: - CredentialAccess - InitialAccess relevantTechniques: - T1110 - T1078 query: | let failureThreshold = 10; let timeWindow = 1h; SigninLogs | where TimeGenerated >= ago(timeWindow) | where ResultType != "0" // Failed logins | summarize FailureCount = count(), FailedAccounts = make_set(UserPrincipalName), FirstFailure = min(TimeGenerated), LastFailure = max(TimeGenerated) by IPAddress, Location = tostring(LocationDetails.city) | where FailureCount >= failureThreshold | join kind=inner ( SigninLogs | where TimeGenerated >= ago(timeWindow) | where ResultType == "0" // Successful login | project SuccessTime = TimeGenerated, IPAddress, SuccessAccount = UserPrincipalName, AppDisplayName, DeviceDetail ) on IPAddress | where SuccessTime > LastFailure | project IPAddress, Location, FailureCount, FailedAccounts, SuccessAccount, AppDisplayName, FirstFailure, LastFailure, SuccessTime, TimeToSuccess = datetime_diff('minute', SuccessTime, LastFailure) entityMappings: - entityType: Account fieldMappings: - identifier: FullName columnName: SuccessAccount - entityType: IP fieldMappings: - identifier: Address columnName: IPAddress ``` #### 可疑的 Service Principal 活动 ``` # sentinel/analytics-rules/identity/suspicious-service-principal.yaml name: Suspicious Service Principal Credential Addition description: | Detects when new credentials (password or certificate) are added to a service principal, which could indicate an attacker establishing persistence via application-level access. severity: Medium queryFrequency: PT1H queryPeriod: PT1H triggerOperator: GreaterThan triggerThreshold: 0 tactics: - Persistence - PrivilegeEscalation relevantTechniques: - T1098.001 query: | AuditLogs | where OperationName has_any ( "Add service principal credentials", "Update application – Certificates and secrets management" ) | where Result == "success" | extend Actor = tostring(InitiatedBy.user.userPrincipalName), ActorIP = tostring(InitiatedBy.user.ipAddress), TargetApp = tostring(TargetResources[0].displayName), TargetAppId = tostring(TargetResources[0].id) | project TimeGenerated, Actor, ActorIP, OperationName, TargetApp, TargetAppId, Result ``` ## KQL 检测查询 ### 身份狩猎查询 ``` // === Detect Impossible Travel === // Identifies sign-ins from geographically distant locations // within a short time frame SigninLogs | where TimeGenerated >= ago(24h) | where ResultType == "0" | project TimeGenerated, UserPrincipalName, IPAddress, Latitude = tostring(LocationDetails.geoCoordinates.latitude), Longitude = tostring(LocationDetails.geoCoordinates.longitude), City = tostring(LocationDetails.city), Country = tostring(LocationDetails.countryOrRegion) | sort by UserPrincipalName, TimeGenerated asc | extend PrevTime = prev(TimeGenerated, 1), PrevLat = todouble(prev(Latitude, 1)), PrevLon = todouble(prev(Longitude, 1)), PrevCity = prev(City, 1), PrevUser = prev(UserPrincipalName, 1) | where UserPrincipalName == PrevUser | extend TimeDiffMinutes = datetime_diff('minute', TimeGenerated, PrevTime), Distance = geo_distance_2points( todouble(Longitude), todouble(Latitude), PrevLon, PrevLat ) / 1000 // Convert to km | where TimeDiffMinutes < 120 and Distance > 500 | project UserPrincipalName, PreviousLocation = strcat(PrevCity, " (", PrevLat, ",", PrevLon, ")"), CurrentLocation = strcat(City, " (", Latitude, ",", Longitude, ")"), DistanceKm = round(Distance, 0), TimeDiffMinutes, SpeedKmH = round(Distance / (TimeDiffMinutes / 60.0), 0) // === Detect OAuth Application Consent Grants === // Identifies when users grant consent to OAuth applications, // which could be an OAuth phishing attack AuditLogs | where TimeGenerated >= ago(7d) | where OperationName == "Consent to application" | extend Actor = tostring(InitiatedBy.user.userPrincipalName), AppName = tostring(TargetResources[0].displayName), AppId = tostring(TargetResources[0].id), Permissions = tostring(TargetResources[0].modifiedProperties) | project TimeGenerated, Actor, AppName, AppId, Permissions, Result // === Detect Privileged Role Assignments === // Tracks Global Admin, Security Admin, and other high-privilege role // assignments in Entra ID AuditLogs | where TimeGenerated >= ago(24h) | where OperationName has "Add member to role" | extend Actor = tostring(InitiatedBy.user.userPrincipalName), TargetUser = tostring(TargetResources[0].userPrincipalName), RoleName = tostring(parse_json( tostring(TargetResources[0].modifiedProperties) )[1].newValue) | where RoleName has_any ( "Global Administrator", "Security Administrator", "Privileged Role Administrator", "Exchange Administrator", "SharePoint Administrator" ) | project TimeGenerated, Actor, TargetUser, RoleName, Result ``` ### 网络狩猎查询 ``` // === Detect Data Exfiltration via Storage === // Identifies unusually high data downloads from Azure Storage StorageBlobLogs | where TimeGenerated >= ago(24h) | where OperationName == "GetBlob" | where StatusCode == 200 | summarize TotalBytesRead = sum(ResponseBodySize), BlobCount = count(), DistinctContainers = dcount(ObjectKey) by CallerIpAddress, AccountName, bin(TimeGenerated, 1h) | where TotalBytesRead > 1073741824 // > 1 GB | extend TotalGB = round(TotalBytesRead / 1073741824.0, 2) | sort by TotalBytesRead desc // === Detect NSG Rule Changes === // Monitors for network security group modifications AzureActivity | where TimeGenerated >= ago(24h) | where OperationNameValue has_any ( "MICROSOFT.NETWORK/NETWORKSECURITYGROUPS/SECURITYRULES/WRITE", "MICROSOFT.NETWORK/NETWORKSECURITYGROUPS/SECURITYRULES/DELETE" ) | where ActivityStatusValue == "Success" | extend Actor = Caller, NSGName = tostring(parse_json(Properties).resource), RuleName = tostring(parse_json(Properties).entity) | project TimeGenerated, Actor, OperationNameValue, NSGName, RuleName, CallerIpAddress, SubscriptionId ``` ## Sigma 检测规则 ### Azure AD MFA 已禁用 ``` title: Azure AD MFA Registration or Requirement Disabled id: e1f2a3b4-c5d6-7890-ef12-345678901234 status: stable level: high description: | Detects when MFA registration is disabled for a user or when Conditional Access policies requiring MFA are modified or disabled. This is a critical security control change that may indicate an attacker weakening authentication requirements. author: Shakil Md. Rezwanul Bari date: 2024/01/15 references: - https://learn.microsoft.com/en-us/entra/identity/authentication/howto-mfa-userstates - https://attack.mitre.org/techniques/T1556/006/ logsource: product: azure service: auditlogs detection: selection_mfa_disabled: OperationName: - 'Disable Strong Authentication' - 'Delete strong authentication phone app detail' - 'User disabled security info' selection_ca_modified: OperationName: - 'Update conditional access policy' - 'Delete conditional access policy' condition: selection_mfa_disabled or selection_ca_modified falsepositives: - Authorized administrative changes during MFA migration - Help desk MFA reset for locked-out users tags: - attack.persistence - attack.defense_evasion - attack.t1556.006 ``` ### Azure AD 可疑登录 ``` title: Azure AD Sign-in from Anonymous or Tor Network id: f2a3b4c5-d6e7-8901-f234-567890123456 status: stable level: high description: | Detects sign-in attempts from anonymous proxy networks (Tor, VPN) which may indicate credential abuse or unauthorized access attempts. author: Shakil Md. Rezwanul Bari date: 2024/01/15 logsource: product: azure service: signinlogs detection: selection: RiskDetail|contains: - 'anonymizedIPAddress' - 'maliciousIPAddress' selection_risk_level: RiskLevelDuringSignIn: - high - medium condition: selection or selection_risk_level falsepositives: - Users legitimately using VPN for privacy - Researchers or security team testing from Tor tags: - attack.initial_access - attack.t1078 - attack.t1090.003 ``` ## Azure Policy ### 自定义 Policy:拒绝公共 IP 地址 ``` { "mode": "All", "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.Network/publicIPAddresses" }, { "not": { "field": "tags['exception']", "equals": "approved-public-ip" } } ] }, "then": { "effect": "deny" } }, "parameters": {}, "displayName": "Deny Public IP Address Creation", "description": "Prevents creation of public IP addresses unless explicitly tagged as approved. This enforces private-only network architectures." } ``` ### 自定义 Policy:强制要求最低 TLS 1.2 ``` { "mode": "All", "policyRule": { "if": { "allOf": [ { "field": "type", "in": [ "Microsoft.Web/sites", "Microsoft.Storage/storageAccounts", "Microsoft.Sql/servers" ] }, { "field": "Microsoft.Web/sites/siteConfig.minTlsVersion", "notEquals": "1.2" } ] }, "then": { "effect": "deny" } }, "displayName": "Enforce TLS 1.2 Minimum Version", "description": "Ensures all web apps, storage accounts, and SQL servers use TLS 1.2 or higher." } ``` ## 事件响应 ### 受损的 Entra ID 账户 Playbook ``` ┌───────────────────────────────────────────────┐ │ PHASE 1: DETECTION & TRIAGE │ │ 1. Alert from Sentinel/Identity Protection │ │ 2. Review sign-in logs for anomalous access │ │ 3. Identify affected account scope │ │ 4. Assess data access and privilege level │ └───────────────────┬───────────────────────────┘ │ ┌───────────────────▼───────────────────────────┐ │ PHASE 2: CONTAINMENT │ │ 1. Reset user password immediately │ │ 2. Revoke all refresh tokens │ │ 3. Disable account if necessary │ │ 4. Block source IP in Conditional Access │ │ 5. Remove OAuth app consents (if phished) │ └───────────────────┬───────────────────────────┘ │ ┌───────────────────▼───────────────────────────┐ │ PHASE 3: INVESTIGATION │ │ 1. Query Entra ID audit logs (90 days) │ │ 2. Review mailbox rules (forwarding, etc.) │ │ 3. Check for new app registrations │ │ 4. Review file access in SharePoint/OneDrive │ │ 5. Check for lateral movement (new sessions) │ └───────────────────┬───────────────────────────┘ │ ┌───────────────────▼───────────────────────────┐ │ PHASE 4: REMEDIATION │ │ 1. Re-enable account with fresh credentials │ │ 2. Re-register MFA devices │ │ 3. Remove malicious inbox rules │ │ 4. Revoke unauthorized app consents │ │ 5. Update Conditional Access policies │ └───────────────────┬───────────────────────────┘ │ ┌───────────────────▼───────────────────────────┐ │ PHASE 5: LESSONS LEARNED │ │ 1. Document timeline and root cause │ │ 2. Update Sentinel analytics rules │ │ 3. Review and strengthen CA policies │ │ 4. Conduct user security awareness training │ └───────────────────────────────────────────────┘ ``` ### 调查 KQL 查询 ``` // === Full Account Activity Timeline === // Use when investigating a compromised account let compromisedUser = "user@company.com"; let investigationWindow = 7d; union (SigninLogs | where TimeGenerated >= ago(investigationWindow) | where UserPrincipalName == compromisedUser | project TimeGenerated, Activity="SignIn", Detail=strcat(AppDisplayName, " - ", ResultDescription), IPAddress, Location=tostring(LocationDetails.city)), (AuditLogs | where TimeGenerated >= ago(investigationWindow) | where InitiatedBy.user.userPrincipalName == compromisedUser | project TimeGenerated, Activity=OperationName, Detail=tostring(TargetResources[0].displayName), IPAddress=tostring(InitiatedBy.user.ipAddress), Location=""), (OfficeActivity | where TimeGenerated >= ago(investigationWindow) | where UserId == compromisedUser | project TimeGenerated, Activity=Operation, Detail=OfficeObjectId, IPAddress=ClientIP, Location="") | sort by TimeGenerated desc ``` ## 合规性 ### CIS Azure Foundations Benchmark — 关键控制项 | CIS 控制项 | 描述 | Azure 服务 | 状态检查 | |---|---|---|---| | 1.1.1 | 确保为所有特权用户启用 MFA | Entra ID | Conditional Access Policy | | 1.1.2 | 确保为所有用户启用 MFA | Entra ID + Security Defaults | CA Policy 或 Security Defaults | | 1.2.1 | 确保 Conditional Access 策略不允许旧版身份验证 | Entra ID CA | 阻止旧版身份验证 | | 2.1.1 | 确保为 Servers 启用 Defender for Cloud | Defender for Cloud | 定价层 = Standard | | 3.1 | 确保对 Storage Account 的访问进行限制 | Storage Accounts | 禁用公共 blob 访问 | | 4.1.1 | 确保为 SQL Servers 启用审计 | Azure SQL | 已启用服务器级审计 | | 5.1.1 | 确保为所有服务启用诊断日志 | Azure Monitor | 已配置诊断设置 | | 6.1 | 确保启用 NSG Flow Logs | Network Watcher | Flow logs 输出至 Log Analytics | | 7.1 | 确保 VM 使用托管磁盘 | Compute | 无非托管磁盘 | | 9.1 | 确保 App Service 使用 HTTPS | App Service | HTTPS Only = On | ## 许可证 本项目基于 MIT 许可证授权。
标签:AMSI绕过, Azure, DevSecOps, 上游代理, 合规自动化, 威胁检测