azure-terraform-defender
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAzure Terraform — Defender for Cloud Compliance Skill
Azure Terraform — Defender for Cloud 合规技能
Scope
适用范围
This skill applies to all Terraform code using the provider. It encodes
controls required to maintain a clean Microsoft Defender for Cloud secure score and
avoid security recommendations across compute, storage, networking, identity, databases,
containers, and PaaS services.
azurermReference files — load the relevant one when working on a specific resource type:
| Topic | File | Covers |
|---|---|---|
| Storage Accounts | | |
| Key Vault | | |
| Databases | | SQL, PostgreSQL, MySQL Flexible, Cosmos DB |
| Containers | | AKS, ACR, Defender for Containers |
| Networking | | NSG, VNet, Firewall, Bastion, DDoS, Private Endpoints |
| App Service | | Web apps, Function apps |
| VMs | | Linux/Windows VMs, disk encryption, backup |
| Identity & IAM | | Managed identities, RBAC, Defender plans, policy |
| Monitoring | | Log Analytics, diagnostic settings, activity alerts |
| PaaS (misc) | | Redis, Service Bus, Event Hub, API Mgmt, Automation |
| Terraform Patterns | | Provider config, state, secrets, naming, modules |
| Full MDC Remediation | | Complete MDC alert → Terraform fix table |
本技能适用于所有使用 provider的Terraform代码。它纳入了维持Microsoft Defender for Cloud安全评分达标、避免计算、存储、网络、身份、数据库、容器及PaaS服务触发安全建议所需的控制措施。
azurerm参考文件 — 处理特定资源类型时加载对应的参考文件:
| 主题 | 文件 | 覆盖范围 |
|---|---|---|
| 存储账户 | | |
| 密钥保管库 | | |
| 数据库 | | SQL、PostgreSQL、MySQL Flexible、Cosmos DB |
| 容器 | | AKS、ACR、Defender for Containers |
| 网络 | | NSG、VNet、防火墙、Bastion、DDoS、专用终结点 |
| 应用服务 | | Web应用、函数应用 |
| 虚拟机 | | Linux/Windows虚拟机、磁盘加密、备份 |
| 身份与IAM | | 托管标识、RBAC、Defender计划、策略 |
| 监控 | | Log Analytics、诊断设置、活动警报 |
| PaaS(其他) | | Redis、Service Bus、Event Hub、API管理、自动化 |
| Terraform模式 | | Provider配置、状态、机密、命名、模块 |
| MDC完整修复指南 | | MDC警报→Terraform修复对照表 |
Mandatory Defaults (All Resources)
强制默认配置(所有资源)
Apply ALL of the following defaults unless the user explicitly overrides with justification.
除非用户提供合理理由明确覆盖,否则必须应用以下所有默认配置。
Required Tags
必填标签
Every resource must include these tags:
hcl
tags = {
environment = var.environment # dev | staging | prod
cost-center = var.cost_center
owner = var.owner_email
managed-by = "terraform"
workload = var.workload_name
created-date = formatdate("YYYY-MM-DD", timestamp())
}所有资源必须包含以下标签:
hcl
tags = {
environment = var.environment # dev | staging | prod
cost-center = var.cost_center
owner = var.owner_email
managed-by = "terraform"
workload = var.workload_name
created-date = formatdate("YYYY-MM-DD", timestamp())
}Managed Identity on Every Resource
所有资源启用托管标识
hcl
identity {
type = "SystemAssigned"
}Every resource that calls other Azure services must use a managed identity.
Never use service principals with client secrets where managed identity is supported.
hcl
identity {
type = "SystemAssigned"
}所有调用其他Azure服务的资源必须使用托管标识。在支持托管标识的场景下,绝不要使用带有客户端密钥的服务主体。
TLS 1.2 Minimum on All Services
所有服务强制最低TLS 1.2版本
Every service that exposes a network endpoint must enforce TLS 1.2 as the minimum version.
所有暴露网络端点的服务必须强制将TLS 1.2设为最低版本。
Private Endpoints for All Data Services
所有数据服务使用专用终结点
In production, all storage, database, messaging, and key management services must be
accessed via private endpoints with .
public_network_access_enabled = false在生产环境中,所有存储、数据库、消息传递和密钥管理服务必须通过专用终结点访问,且设置。
public_network_access_enabled = falseDiagnostic Settings for Every PaaS Resource
所有PaaS资源配置诊断设置
Every PaaS resource must have an sending logs to
a Log Analytics workspace. See for per-resource log categories.
azurerm_monitor_diagnostic_settingreferences/monitoring.md所有PaaS资源必须配置,将日志发送至Log Analytics工作区。各资源对应的日志类别请参考。
azurerm_monitor_diagnostic_settingreferences/monitoring.mdQuick Defaults by Resource Type
按资源类型划分的快速默认配置
Storage (azurerm_storage_account
) — see references/storage.md
azurerm_storage_accountreferences/storage.md存储(azurerm_storage_account
)— 详见references/storage.md
azurerm_storage_accountreferences/storage.mdhcl
https_traffic_only_enabled = true
min_tls_version = "TLS1_2"
allow_nested_items_to_be_public = false
shared_access_key_enabled = false
cross_tenant_replication_enabled = false
infrastructure_encryption_enabled = true
network_rules {
default_action = "Deny"
bypass = ["AzureServices"]
}
blob_properties {
delete_retention_policy { days = 30 }
container_delete_retention_policy { days = 30 }
versioning_enabled = true
}hcl
https_traffic_only_enabled = true
min_tls_version = "TLS1_2"
allow_nested_items_to_be_public = false
shared_access_key_enabled = false
cross_tenant_replication_enabled = false
infrastructure_encryption_enabled = true
network_rules {
default_action = "Deny"
bypass = ["AzureServices"]
}
blob_properties {
delete_retention_policy { days = 30 }
container_delete_retention_policy { days = 30 }
versioning_enabled = true
}Key Vault (azurerm_key_vault
) — see references/keyvault.md
azurerm_key_vaultreferences/keyvault.md密钥保管库(azurerm_key_vault
)— 详见references/keyvault.md
azurerm_key_vaultreferences/keyvault.mdhcl
soft_delete_retention_days = 90
purge_protection_enabled = true
enable_rbac_authorization = true
network_acls {
default_action = "Deny"
bypass = ["AzureServices"]
}hcl
soft_delete_retention_days = 90
purge_protection_enabled = true
enable_rbac_authorization = true
network_acls {
default_action = "Deny"
bypass = ["AzureServices"]
}SQL Server (azurerm_mssql_server
) — see references/databases.md
azurerm_mssql_serverreferences/databases.mdSQL服务器(azurerm_mssql_server
)— 详见references/databases.md
azurerm_mssql_serverreferences/databases.mdhcl
minimum_tls_version = "1.2"
public_network_access_enabled = false
azuread_administrator {
login_username = var.aad_admin_login
object_id = var.aad_admin_object_id
azuread_authentication_only = true
}Always add: +
azurerm_mssql_server_extended_auditing_policyazurerm_mssql_server_vulnerability_assessmenthcl
minimum_tls_version = "1.2"
public_network_access_enabled = false
azuread_administrator {
login_username = var.aad_admin_login
object_id = var.aad_admin_object_id
azuread_authentication_only = true
}Always add: +
azurerm_mssql_server_extended_auditing_policyazurerm_mssql_server_vulnerability_assessmentPostgreSQL Flexible (azurerm_postgresql_flexible_server
) — see references/databases.md
azurerm_postgresql_flexible_serverreferences/databases.mdPostgreSQL Flexible(azurerm_postgresql_flexible_server
)— 详见references/databases.md
azurerm_postgresql_flexible_serverreferences/databases.mdhcl
geo_redundant_backup_enabled = true
authentication {
active_directory_auth_enabled = true
password_auth_enabled = false
tenant_id = data.azurerm_client_config.current.tenant_id
}Always add log configuration resources: , , , .
log_checkpointslog_connectionslog_disconnectionsconnection_throttlinghcl
geo_redundant_backup_enabled = true
authentication {
active_directory_auth_enabled = true
password_auth_enabled = false
tenant_id = data.azurerm_client_config.current.tenant_id
}Always add log configuration resources: , , , .
log_checkpointslog_connectionslog_disconnectionsconnection_throttlingAKS (azurerm_kubernetes_cluster
) — see references/containers.md
azurerm_kubernetes_clusterreferences/containers.mdAKS(azurerm_kubernetes_cluster
)— 详见references/containers.md
azurerm_kubernetes_clusterreferences/containers.mdhcl
role_based_access_control_enabled = true
local_account_disabled = true
azure_policy_enabled = true
azure_active_directory_role_based_access_control {
managed = true
azure_rbac_enabled = true
}
microsoft_defender {
log_analytics_workspace_id = var.log_analytics_workspace_id
}hcl
role_based_access_control_enabled = true
local_account_disabled = true
azure_policy_enabled = true
azure_active_directory_role_based_access_control {
managed = true
azure_rbac_enabled = true
}
microsoft_defender {
log_analytics_workspace_id = var.log_analytics_workspace_id
}App Service / Function App — see references/appservice.md
references/appservice.md应用服务/函数应用 — 详见references/appservice.md
references/appservice.mdhcl
https_only = true
site_config {
minimum_tls_version = "1.2"
ftps_state = "Disabled"
remote_debugging_enabled = false
}
auth_settings_v2 {
auth_enabled = true
require_authentication = true
}hcl
https_only = true
site_config {
minimum_tls_version = "1.2"
ftps_state = "Disabled"
remote_debugging_enabled = false
}
auth_settings_v2 {
auth_enabled = true
require_authentication = true
}VMs — see references/compute-vms.md
references/compute-vms.md虚拟机 — 详见references/compute-vms.md
references/compute-vms.mdhcl
encryption_at_host_enabled = true
secure_boot_enabled = true
vtpm_enabled = true
disable_password_authentication = true # Linux onlyNever assign a public IP directly to a VM. Use Azure Bastion.
hcl
encryption_at_host_enabled = true
secure_boot_enabled = true
vtpm_enabled = true
disable_password_authentication = true # Linux onlyNever assign a public IP directly to a VM. Use Azure Bastion.
Redis, Service Bus, Event Hub, Cosmos DB, API Mgmt, Automation — see references/paas-misc.md
references/paas-misc.mdRedis、Service Bus、Event Hub、Cosmos DB、API管理、自动化 — 详见references/paas-misc.md
references/paas-misc.mdKey defaults: disable non-SSL ports, disable local auth, no public network access, TLS 1.2, managed identity, private endpoint.
Key defaults: disable non-SSL ports, disable local auth, no public network access, TLS 1.2, managed identity, private endpoint.
Prohibited Patterns — Reject and Flag These
禁止模式 — 需拒绝并标记以下内容
- on any storage account
https_traffic_only_enabled = false - on any storage account
allow_nested_items_to_be_public = true - on storage accounts used for state or sensitive data
shared_access_key_enabled = true - on any Key Vault
purge_protection_enabled = false - on any Key Vault
soft_delete_retention_days < 7 - on Key Vault in production
enable_rbac_authorization = false - on any SQL/PostgreSQL/MySQL/Cosmos DB without explicit CIDR allow-listing AND private endpoint
public_network_access_enabled = true - NSG rules: +
access = "Allow"+direction = "Inbound"orsource_address_prefix = "*"for ports 22, 3389, 5985, 5986"Internet" - on any AKS cluster
role_based_access_control_enabled = false - on AKS in production
local_account_disabled = false - on any ACR
admin_enabled = true - Service principals with where Azure managed identity is supported
client_secret - in any
role_definition_name = "Owner"without documented justificationazurerm_role_assignment - Resources deployed without the required tag set
- on any App Service or Function App
https_only = false - on any App Service/Function App
site_config { remote_debugging_enabled = true } - on any App Service/Function App
site_config { ftps_state = "AllAllowed" } - on any App Service
cors { allowed_origins = ["*"] } - on Redis Cache
enable_non_ssl_port = true - or
local_auth_enabled = trueon Service Bus/Event Hublocal_authentication_enabled = true - on Cosmos DB
local_authentication_disabled = false - on any
encrypted = falseazurerm_automation_variable_* - on any production VM
encryption_at_host_enabled = false - Hardcoded secrets or connection strings in Terraform variables without
sensitive = true - No version constraint on provider (must pin to at least
azurerm)~> X.Y
- on any storage account
https_traffic_only_enabled = false - on any storage account
allow_nested_items_to_be_public = true - on storage accounts used for state or sensitive data
shared_access_key_enabled = true - on any Key Vault
purge_protection_enabled = false - on any Key Vault
soft_delete_retention_days < 7 - on Key Vault in production
enable_rbac_authorization = false - on any SQL/PostgreSQL/MySQL/Cosmos DB without explicit CIDR allow-listing AND private endpoint
public_network_access_enabled = true - NSG rules: +
access = "Allow"+direction = "Inbound"orsource_address_prefix = "*"for ports 22, 3389, 5985, 5986"Internet" - on any AKS cluster
role_based_access_control_enabled = false - on AKS in production
local_account_disabled = false - on any ACR
admin_enabled = true - Service principals with where Azure managed identity is supported
client_secret - in any
role_definition_name = "Owner"without documented justificationazurerm_role_assignment - Resources deployed without the required tag set
- on any App Service or Function App
https_only = false - on any App Service/Function App
site_config { remote_debugging_enabled = true } - on any App Service/Function App
site_config { ftps_state = "AllAllowed" } - on any App Service
cors { allowed_origins = ["*"] } - on Redis Cache
enable_non_ssl_port = true - or
local_auth_enabled = trueon Service Bus/Event Hublocal_authentication_enabled = true - on Cosmos DB
local_authentication_disabled = false - on any
encrypted = falseazurerm_automation_variable_* - on any production VM
encryption_at_host_enabled = false - Hardcoded secrets or connection strings in Terraform variables without
sensitive = true - No version constraint on provider (must pin to at least
azurerm)~> X.Y
Review Checklist
审查检查清单
When reviewing a Terraform plan or module, work through this list:
Storage
- HTTPS-only, min TLS 1.2, no public blob access, shared key disabled, network deny-all default
- Soft delete (blob + container), versioning enabled
Key Vault
- Soft delete ≥ 90 days, purge protection, firewall deny-all, RBAC auth
- Key and secret expiry dates set; rotation policy configured
- Diagnostic setting with AuditEvent
SQL / Databases
- AAD-only admin, auditing policy with 90-day retention, TLS 1.2, no public access
- Vulnerability assessment enabled; threat detection alert policy
- PostgreSQL: log settings (checkpoints, connections, disconnections, throttling)
- Cosmos DB: public access disabled, local auth disabled
Containers
- AKS: RBAC, Azure AD integration, Defender profile, Azure Policy, local accounts disabled
- AKS: authorized IP ranges on API server; managed identity
- ACR: admin user disabled, public access disabled, private endpoint
Networking
- No wildcard source for management ports (22, 3389, 5985, 5986)
- DDoS Protection on production VNets
- NSG flow logs enabled (version 2, 90-day retention, traffic analytics)
- Azure Bastion deployed; no public IPs on VMs
App Service / Function Apps
- HTTPS-only, TLS 1.2, FTPS disabled, remote debugging off, auth enabled
- Managed identity, VNet integration, no CORS wildcard
VMs
- Encryption at host, Trusted Launch (Secure Boot + vTPM)
- SSH keys only (Linux), no public IP, MDE extension
- Backup policy enabled, patch management enabled
PaaS (misc)
- Redis: non-SSL port disabled, TLS 1.2, private endpoint
- Service Bus / Event Hub: TLS 1.2, local auth disabled, private endpoint
- API Mgmt: VNet integration, TLS 1.0/1.1 disabled
- Automation: all variables encrypted, no public access, managed identity
Monitoring
- Diagnostic settings on every PaaS resource
- Subscription activity log forwarded to Log Analytics
- CIS 5.2.x activity log alerts for policy, NSG, security, SQL firewall changes
- Log Analytics retention ≥ 365 days
Identity & IAM
- All Defender plans enabled at subscription level
- No Owner role assignments without justification
- Security contact configured in MDC
- Managed identity on every resource that calls Azure services
Terraform Patterns
- Provider version pinned ()
~> X.Y - committed
.terraform.lock.hcl - All secrets marked ; no hardcoded secrets
sensitive = true - State storage account hardened (HTTPS, TLS 1.2, no public access, no SAS keys)
- on critical resources (Key Vault, databases, Log Analytics, state storage)
prevent_destroy - Required tags on all resources
When reviewing a Terraform plan or module, work through this list:
Storage
- HTTPS-only, min TLS 1.2, no public blob access, shared key disabled, network deny-all default
- Soft delete (blob + container), versioning enabled
Key Vault
- Soft delete ≥ 90 days, purge protection, firewall deny-all, RBAC auth
- Key and secret expiry dates set; rotation policy configured
- Diagnostic setting with AuditEvent
SQL / Databases
- AAD-only admin, auditing policy with 90-day retention, TLS 1.2, no public access
- Vulnerability assessment enabled; threat detection alert policy
- PostgreSQL: log settings (checkpoints, connections, disconnections, throttling)
- Cosmos DB: public access disabled, local auth disabled
Containers
- AKS: RBAC, Azure AD integration, Defender profile, Azure Policy, local accounts disabled
- AKS: authorized IP ranges on API server; managed identity
- ACR: admin user disabled, public access disabled, private endpoint
Networking
- No wildcard source for management ports (22, 3389, 5985, 5986)
- DDoS Protection on production VNets
- NSG flow logs enabled (version 2, 90-day retention, traffic analytics)
- Azure Bastion deployed; no public IPs on VMs
App Service / Function Apps
- HTTPS-only, TLS 1.2, FTPS disabled, remote debugging off, auth enabled
- Managed identity, VNet integration, no CORS wildcard
VMs
- Encryption at host, Trusted Launch (Secure Boot + vTPM)
- SSH keys only (Linux), no public IP, MDE extension
- Backup policy enabled, patch management enabled
PaaS (misc)
- Redis: non-SSL port disabled, TLS 1.2, private endpoint
- Service Bus / Event Hub: TLS 1.2, local auth disabled, private endpoint
- API Mgmt: VNet integration, TLS 1.0/1.1 disabled
- Automation: all variables encrypted, no public access, managed identity
Monitoring
- Diagnostic settings on every PaaS resource
- Subscription activity log forwarded to Log Analytics
- CIS 5.2.x activity log alerts for policy, NSG, security, SQL firewall changes
- Log Analytics retention ≥ 365 days
Identity & IAM
- All Defender plans enabled at subscription level
- No Owner role assignments without justification
- Security contact configured in MDC
- Managed identity on every resource that calls Azure services
Terraform Patterns
- Provider version pinned ()
~> X.Y - committed
.terraform.lock.hcl - All secrets marked ; no hardcoded secrets
sensitive = true - State storage account hardened (HTTPS, TLS 1.2, no public access, no SAS keys)
- on critical resources (Key Vault, databases, Log Analytics, state storage)
prevent_destroy - Required tags on all resources