ごった煮

色々な事を書いてます

Bicep の条件付きデプロイで App Service へ Key Vault の権限を付与する

状況に応じて App Service へ Key Vault の権限を付与する Bicep を書いていたところ、ちょっと詰まったので備忘録

何がしたいのか?

App Service 作成時、パラメータで Key Vault の名前が渡された時だけ Key Vault の権限を設定したい

うまく動かなかった Bicep

keyVaultName が空じゃない場合のみ、アクセスポリシーをデプロイしたいという気持ちで書いたので、次のようにしてみました。

resource kvAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = if(!empty(keyVaultName)) {
  name: '${keyVaultName}/add'
  properties: {
    accessPolicies: [
      {
        objectId: app.identity.principalId
        tenantId: app.identity.tenantId
        permissions: {
          secrets: [
            'get'
            'list'
          ]
          keys: [
            'get'
            'list'
          ]
          certificates: [
            'get'
            'list'
          ]
        } 
      }
    ]
  }
}

何で詰まったのか

ARM テンプレート上で Key Vault の名前を使ってリソースを組み立てようとするので、 Key Vault 名が空だとフォーマットエラーになるようです。

アクセスポリシーは、子要素なので、通常 KeyVault名/add のようになるところが、/add と組み立てられるため、フォーマットエラーとして認識されます。

A nested resource type must have identical number of segments as its resource name. A root resource type must have segment length one greater than its resource name.

ARM テンプレートは、次のように展開されます。

            {
              "condition": "[not(empty(parameters('keyVaultName')))]",
              "type": "Microsoft.KeyVault/vaults/accessPolicies",
              "apiVersion": "2022-07-01",
              "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]",
              "properties": {
                "accessPolicies": [
                  {
                    "objectId": "[reference(resourceId('Microsoft.Web/sites', format('app-{0}-{1}-{2}-{3}', parameters('workload'), parameters('tenant'), parameters('env'), parameters('location'))), '2022-03-01', 'full').identity.principalId]",
                    "tenantId": "[reference(resourceId('Microsoft.Web/sites', format('app-{0}-{1}-{2}-{3}', parameters('workload'), parameters('tenant'), parameters('env'), parameters('location'))), '2022-03-01', 'full').identity.tenantId]",
                    "permissions": {
                      "secrets": [
                        "get",
                        "list"
                      ]
                    }
                  }
                ]
              },
              "dependsOn": [
                "[resourceId('Microsoft.Web/sites', format('app-{0}-{1}-{2}-{3}', parameters('workload'), parameters('tenant'), parameters('env'), parameters('location')))]"
              ]
            },

解決策

module に実装を押し込みました。

モジュールは次の通り

param keyVaultName string
param objectId string
param tenantId string
@allowed([
  'get'
  'list'
  'all'
  'backup'
  'delete'
  'purge'
  'recover'
  'restore'
  'set'
])
param secrets array
@allowed([
  'get'
  'list'
  'all'
  'backup'
  'create'
  'decrypt'
  'delete'
  'encrypt'
  'getrotationpolicy'
  'import'
  'list'
  'purge'
  'recover'
  'release'
  'restore'
  'rotate'
  'setrotationpolicy'
  'sign'
  'unwrapKey'
  'update'
  'verify'
  'wrapKey'
])
param keys array
@allowed([
  'get'
  'list'
  'all'
  'backup'
  'create'
  'delete'
  'deleteissuers'
  'getissuers'
  'import'
  'listissuers'
  'managecontacts'
  'manageissuers'
  'purge'
  'recover'
  'restore'
  'setissuers'
  'update'
])
param certificates array

resource kvAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = {
  name: '${keyVaultName}/add'
  properties: {
    accessPolicies: [
      {
        objectId: objectId
        tenantId: tenantId
        permissions: {
          secrets: secrets
          keys: keys
          certificates: certificates
        }
      }
    ]
  }
}

これだと、ARM テンプレートに展開された際に、モジュール呼び出し時の name が name プロパティに差し込まれるのでフォーマットエラーにならないようです。

※ ほんとにこれが根本原因なのかは、ちょっと自信ない

まとめ

Bicep は、結構はまりどころが多いですが、慣れると便利