模板中的 Azure Bicep 多个范围

Nay*_*Van 7 azure-resource-manager azure-bicep

使用 terraform 很长时间后,我决定开始学习 azure bicep。到目前为止,我正在努力掌握逻辑。到目前为止,我已经尝试了存储帐户和密钥库的部署。我在这里所做的事情如下。

  • 创建存储帐户
  • 使用现有密钥保管库将存储帐户连接字符串存储为机密
  • 根据存储帐户名称创建密钥

这正如我所期望的那样。

所以我想向前迈出一步。这就是我有点困惑的地方。

我想做的是使用相同的二头肌模板来创建一个新的秘密,但在不同的资源组中创建到不同的密钥保管库中。

现在,根据我对 azure 文档的理解,该模板带有默认值scope,在我的具体情况下,它以我的默认订阅为目标,并从终端运行我的二头肌模板,我使用命令

az deployment group create -f ./template.bicep -g <resource-group-name>
Run Code Online (Sandbox Code Playgroud)

这是我的模板:

// Default values I'm using to test 
param keyVaultName string = '<keyvault-name>'
param managedIdentityName string = 'test-managed-identity'

param tenantCodes array = [
  'elhm'
  'feor'
]

// I'm using prefix so I dont need to create additional arrays
var keyVaultKeyPrefix = 'Client-Key-'
var storagePrefix = 'sthrideveur'

// Get a reference to key vault
resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
  name: keyVaultName
}

// Create a managed identity
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: managedIdentityName
  location: resourceGroup().location
}

// Grant permissions to key vault
resource accessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2019-09-01' = {
  name: '${keyVault.name}/add'
  properties: {
    accessPolicies: [
      {
        tenantId: subscription().tenantId
        objectId: managedIdentity.properties.principalId
        permissions: {
          // minimum required permissions
          keys: [
            'get'
            'unwrapKey'
            'wrapKey'
          ]
        }
      }
    ]
  }
}

// Create key vault keys
resource keyVaultKeys 'Microsoft.KeyVault/vaults/keys@2021-06-01-preview' = [for tenantCode in tenantCodes: {
  name: '${keyVault.name}/${keyVaultKeyPrefix}${tenantCode}'
  properties: {
    keySize: 2048
    kty: 'RSA'
    // storage key should only needs these operations
    keyOps: [
      'unwrapKey'
      'wrapKey'
    ]
  }
}]

// Create storage accounts
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' = [for tenantCode in tenantCodes: {
  name: '${storagePrefix}${tenantCode}'
  location: resourceGroup().location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_RAGRS'
  }
  // Assign the identity
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${managedIdentity.id}': {}
    }
  }
  properties: {
    allowCrossTenantReplication: true
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: false
    allowSharedKeyAccess: true
    networkAcls: {
      bypass: 'AzureServices'
      virtualNetworkRules: []
      ipRules: []
      defaultAction: 'Allow'
    }
    supportsHttpsTrafficOnly: true
    encryption: {
      identity: {
        // specify which identity to use
        userAssignedIdentity: managedIdentity.id
      }
      keySource: 'Microsoft.Keyvault'
      keyvaultproperties: {
        keyname: '${keyVaultKeyPrefix}${tenantCode}'
        keyvaulturi: keyVault.properties.vaultUri
      }
      services: {
        file: {
          keyType: 'Account'
          enabled: true
        }
        blob: {
          keyType: 'Account'
          enabled: true
        }
      }
    }
    accessTier: 'Cool'
  }
}]

// Store the connectionstrings in KV if specified
resource storageAccountConnectionStrings 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = [ for (name, i) in tenantCodes :{
  name: '${keyVault.name}/${storagePrefix}${name}'
  properties: {
    value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount[i].name};AccountKey=${listKeys(storageAccount[i].id, storageAccount[i].apiVersion).keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
  }
}]
Run Code Online (Sandbox Code Playgroud)

根据此处的文档https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deploy-to-resource-group?tabs=azure-cli

当我需要定位特定资源组时,我可以使用资源中的范围,因此我创建了以下内容:

resource keyvaultApi 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
  name: keyVaultApiName
  scope: resourceGroup('secondresourcegroup')
}
Run Code Online (Sandbox Code Playgroud)

到目前为止没有错误,但是当我必须创建托管身份资源时,问题发生了。

resource keyvaultApi 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
  name: keyVaultApiName
  scope: resourceGroup('secondresourcegroup')
}

resource managedIdentityTwo 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: managedIdentityNameTwo
  location: resourceGroup().location
}

resource accessPolicyApi 'Microsoft.Media/videoAnalyzers/accessPolicies@2021-11-01-preview' = {
  name: '${keyvaultApi.name}/add'
  properties: {
    accessPolicies: [
      {
        tenantId: subscription().tenantId
        objectId: managedIdentityTwo.properties.principalId
        permissions: {
          // minimum required permissions
          keys: [
            'get'
            'unwrapKey'
            'wrapKey'
          ]
        }
      }
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

在密钥保管库中,我可以声明范围,但对于底层资源(例如访问策略等),我无法声明范围。那么二头肌如何理解这些资源需要针对特定​​的资源组和特定的密钥保管库?

因为当我运行终端命令时,我针对的是特定的资源组,所以我不太明白如何使用一个模板来相应地针对不同的资源组和资源。

我希望我已经表达清楚了我的观点,如果我没有表达清楚,请随时向我询问更多信息。

非常感谢您的时间和帮助

更新:当我尝试按原样运行代码时,出现以下错误:

{"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"NotFound","message":"{\r\n  \"error\": {\r\n    \"code\": \"ParentResourceNotFound\",\r\n    \"message\": \"Can not perform requested operation on nested resource. Parent resource 'secondkeyvault' not found.\"\r\n  }\r\n}"}]}}

Run Code Online (Sandbox Code Playgroud)

更新:所以我按照 Daniel 的指导,在第二个模板中部署了第二个模板所需的代码,如下所示:

template2.二头肌

param deploymentIdOne string = newGuid()
param deploymentIdTwo string = newGuid()
output deploymentIdOne string = '${deploymentIdOne}-${deploymentIdTwo}'
output deploymentIdTwo string = deploymentIdTwo

// Default values I'm using to test 
param keyVaultApiName string = 'secondkeyvaultapi'
param managedIdentityNameTwo string = 'second-second-identity'
var keyVaultKeyPrefixTw = 'Client-Key-'
param tenantCodes array = [
  'tgrf'
]
resource keyvaultApi 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
  name: keyVaultApiName
}

resource managedIdentityTwo 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: managedIdentityNameTwo
  location: resourceGroup().location
}

resource accessPolicyApi 'Microsoft.KeyVault/vaults/accessPolicies@2019-09-01' = {
  name: '${keyvaultApi.name}/add'
  properties: {
    accessPolicies: [
      {
        tenantId: subscription().tenantId
        objectId: managedIdentityTwo.properties.principalId
        permissions: {
          // minimum required permissions
          keys: [
            'get'
            'unwrapKey'
            'wrapKey'
          ]
        }
      }
    ]
  }
}

// Store the connectionstrings in KV if specified
resource clientApiKeys 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = [ for name in tenantCodes :{
  name: '${keyvaultApi.name}/${keyVaultKeyPrefixTw}${name}'
  properties: {
    value: '${deploymentIdOne}-${deploymentIdTwo}'
  }
}]
Run Code Online (Sandbox Code Playgroud)

在我的主模板中我添加了模块:

module clientKeyApi 'template2.bicep' = {
  name: 'testfrgs'
  scope: 'secondresourcegroup'
}
Run Code Online (Sandbox Code Playgroud)

但有件事我并不是100%清楚。如何覆盖for我在 template2.bicep 中声明的所有循环和参数名称,但模块需要一个 scope subscription,如果我声明了范围,这不会覆盖默认值吗?

抱歉大家提出了新手问题,我正在尝试打破我的思维模式,更好地理解二头肌是如何工作的。

任何解释都会令人惊奇且有帮助的

Dan*_*ann 14

您无法scope在资源上指定,但可以在模块上指定。您需要将向 keyvault 添加访问策略的资源转换为单独的模块,然后scope在该模块上指定。您还可以确定部署的范围subscription,但随后您还需要将针对特定资源组的所有内容分解为模块。

这是由 ARM 部署的工作方式决定的。ARM 部署的默认范围是资源组级别。您无法将资源指向不同的资源组,因为它超出了部署范围。

然而,模块作为子部署运行,因此可以具有不同的范围集。

在这种情况下,Terraform 更加简单,因为它直接调用 Azure API,而不是使用 ARM 部署模型。Terraform 不关心部署范围,因为它不使用它们。