You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terraform使用yamldecode加载YAML时无法访问queryFrequency属性问题

问题:Terraform批量加载Sentinel规则时无法访问YAML中的queryFrequency/queryPeriod字段

使用azurerm_sentinel_alert_rule_scheduled资源批量启用Sentinel分析规则,通过yamldecode加载本地YAML文件。其他字段如severity、description、tactics都能正常访问,但queryFrequency和queryPeriod字段报错提示不存在,移除对应配置后代码可正常运行。


相关Terraform代码

locals {
  yaml_files = fileset("D:\\Terraform\\RG_LAW_SENTINEL\\AnalyticsYaml\\", "*.yaml")
  yaml_data  = [for f in local.yaml_files : yamldecode(file("D:\\Terraform\\RG_LAW_SENTINEL\\AnalyticsYaml\\${f}"))]
}

resource "azurerm_sentinel_alert_rule_scheduled" "test1" {
  for_each                   = { for f in local.yaml_data : f.name => f }
  name                       = each.value.name
  log_analytics_workspace_id = azurerm_sentinel_log_analytics_workspace_onboarding.sentinel-terraform.workspace_id
  display_name               = each.value.name
  severity                   = each.value.severity
  description                = each.value.description
  tactics                    = each.value.tactics
  query_frequency            = each.value.queryFrequency
  query                      = <<QUERY
  ${each.value.query}
QUERY

  event_grouping {
    aggregation_method = "AlertPerResult"

  }

  incident_configuration {
    create_incident = "true"

    grouping {
      enabled                = "true"
      lookback_duration      = "P1D"
      entity_matching_method = "AllEntities"

    }
  }

}

YAML示例文件

id: bb616d82-108f-47d3-9dec-9652ea0d3bf6
name: Account Created and Deleted in Short Timeframe
description: |
  'Search for user principal name (UPN) events. Look for accounts created and then deleted in under 24 hours. Attackers may create an account for their use, and then remove the account when no longer needed.
  Ref : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#short-lived-account'
severity: High
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - SigninLogs
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - InitialAccess
relevantTechniques:
  - T1078.004
tags:
  - AADSecOpsGuide
query: |
  let queryfrequency = 1h;
  let queryperiod = 1d;
  AuditLogs
  | where TimeGenerated > ago(queryfrequency)
  | where OperationName =~ "Delete user"
  //extend UserPrincipalName = tostring(TargetResources[0].userPrincipalName)
  | mv-apply TargetResource = TargetResources on 
    (
        where TargetResource.type == "User"
        | extend UserPrincipalName = extract(@'([a-f0-9]{32})?(.*)', 2, tostring(TargetResource.userPrincipalName))
    )
  | extend DeletedByUser = tostring(InitiatedBy.user.userPrincipalName), DeletedByIPAddress = tostring(InitiatedBy.user.ipAddress)
  | extend DeletedByApp = tostring(InitiatedBy.app.displayName)
  | project Deletion_TimeGenerated = TimeGenerated, UserPrincipalName, DeletedByUser, DeletedByIPAddress, DeletedByApp, Deletion_AdditionalDetails = AdditionalDetails, Deletion_InitiatedBy = InitiatedBy, Deletion_TargetResources = TargetResources
  | join kind=inner (
      AuditLogs
      | where TimeGenerated > ago(queryperiod)
      | where OperationName =~ "Add user"      
      | mv-apply TargetResource = TargetResources on 
        (
            where TargetResource.type == "User"
            | extend UserPrincipalName = trim(@'"',tostring(TargetResource.userPrincipalName))
        )
      | project-rename Creation_TimeGenerated = TimeGenerated
  ) on UserPrincipalName
  | extend TimeDelta = Deletion_TimeGenerated - Creation_TimeGenerated
  | where  TimeDelta between (time(0s) .. queryperiod)
  | extend CreatedByUser = tostring(InitiatedBy.user.userPrincipalName), CreatedByIPAddress = tostring(InitiatedBy.user.ipAddress)
  | extend CreatedByApp = tostring(InitiatedBy.app.displayName)
  | project Creation_TimeGenerated, Deletion_TimeGenerated, TimeDelta, UserPrincipalName, DeletedByUser, DeletedByIPAddress, DeletedByApp, CreatedByUser, CreatedByIPAddress, CreatedByApp, Creation_AdditionalDetails = AdditionalDetails, Creation_InitiatedBy = InitiatedBy, Creation_TargetResources = TargetResources, Deletion_AdditionalDetails, Deletion_InitiatedBy, Deletion_TargetResources
  | extend timestamp = Deletion_TimeGenerated, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: Name
      - identifier: UPNSuffix
        columnName: UPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: DeletedByIPAddress
version: 1.0.3
kind: Scheduled

报错信息

Error: Unsupported attribute
│
│   on analytics_mass.tf line 16, in resource "azurerm_sentinel_alert_rule_scheduled" "test1":
│   16:   query_frequency             = each.value.queryFrequency
│     ├────────────────
│     │ each.value is object with 11 attributes
│
│ This object does not have an attribute named "queryFrequency".

解决方案

问题核心是部分YAML文件缺失queryFrequency/queryPeriod字段,或字段名存在大小写/拼写差异。Terraform遍历所有YAML解析对象时,只要有一个对象缺少目标字段就会触发报错。下面是两种可行的解决方式:

方式1:为缺失字段设置默认值

在本地变量yaml_data中,用merge函数为每个YAML对象补充默认值,YAML本身有该字段时会覆盖默认值:

locals {
  yaml_files = fileset("D:\\Terraform\\RG_LAW_SENTINEL\\AnalyticsYaml\\", "*.yaml")
  yaml_data  = [for f in local.yaml_files : merge(
    yamldecode(file("D:\\Terraform\\RG_LAW_SENTINEL\\AnalyticsYaml\\${f}")),
    {
      queryFrequency = "1h" # 默认查询频率
      queryPeriod = "1d"    # 默认查询周期
    }
  )]
}

方式2:过滤缺少必要字段的YAML文件

如果不想为缺失字段设置默认值,可在for_each中只保留包含目标字段的对象:

resource "azurerm_sentinel_alert_rule_scheduled" "test1" {
  for_each                   = { 
    for f in local.yaml_data : f.name => f 
    if contains(keys(f), "queryFrequency") && contains(keys(f), "queryPeriod")
  }
  # 其余配置保持不变
}

额外检查

确认所有YAML文件中的字段名是queryFrequency和queryPeriod(注意大小写),避免出现全小写或拼写错误的情况。


内容的提问来源于stack exchange,提问作者Oskar Kazmierczyk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:24:52