Home > Net >  Bicep Loop over key vault keys and encrypt storage account
Bicep Loop over key vault keys and encrypt storage account

Time:10-23

I have a bit of a huge blocker here about the implementation logic.

I am working with bicep to create those resources.

  • storage accounts
  • key vault
  • pass storage accounts connection string to key vault secrets
  • create a key in key vault and encrypt storage account with that key.

The first Three steps are done. if I declare 2 storage accounts, it will create automatically 2 secrets connection strings and 2 keys. All the pairing (storage name and connection string) they match.

Now the issue I am facing is the following, to start with, this is my code.

param tenantCode array = [
  'dsec'
  'sdre'
]

var storageName = [for item in tenantCode :{
  name: string('sthrideveur${item}')
}]


var connectionStringSecretName = [for connection in storageName :{
  name: '${connection.name}'
  
}]

output connectionStringSecretName array= [for connection in storageName :{
  name: '${connection.name}'
  
}]






resource storage_Accounts 'Microsoft.Storage/storageAccounts@2021-06-01' = [ for name in storageName :{
  name: '${name.name}'
  location: 'westeurope'
  sku: {
    name: 'Standard_RAGRS'
  }
  kind: 'StorageV2'
  properties: {
    allowCrossTenantReplication: true
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: false
    allowSharedKeyAccess: true
    networkAcls: {
      bypass: 'AzureServices'
      virtualNetworkRules: []
      ipRules: []
      defaultAction: 'Allow'
    }
    supportsHttpsTrafficOnly: true
    encryption: {
      services: {
        file: {
          keyType: 'Account'
          enabled: true
        }
        blob: {
          keyType: 'Account'
          enabled: true
        }
      }
      keySource: 'Microsoft.Storage'
      keyvaultproperties: { 
        keyname: '${tenantKey[0]}'
        keyvaulturi: keyVault.id
      }
    }
    accessTier: 'Cool'
  }
}]

resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
  name : 'XXX'
}

// Store the connection string in KV if specified
resource storageAccountConnectionString 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = [for name in storageName :{
  name: '${keyVault.name}/${name.name}'
  properties: {
    value: 'DefaultEndpointsProtocol=https;AccountName=${storage_Accounts[0].name};AccountKey=${listKeys('${storage_Accounts[0].id}', '${storage_Accounts[0].apiVersion}').keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
  }
}]

resource tenantKey 'Microsoft.KeyVault/vaults/keys@2021-06-01-preview' = [for tenant in tenantCode : {
  name: '${keyVault.name}/Client-Key-${tenant}'
  properties: {
    keySize: 2048
    kty: 'RSA'
  }
  
}]

I have 2 storage account I want to create. And the keys, contains the storage code. What I want to do and I am having problem to implement, is how to match the correct key with the correct storage account. In this specific case, I have to codes as follow:

dsec
sdre

The bicep script will create 2 storage accounts and secrets named accordingly:

sthrideveurdsec
sthrideveursdre

AND 2 secrets with the same name
sthrideveurdsec
sthrideveursdre

AND 2 Keys named
Client-Key-dsec
Client-Key-sdre

What I would to do, is to encrypt the storage account DSEC with key DSEC and the storage SDRE with the key SDRE. But as I am new to bicep I am having some problem to implement this.

If anyone can help me to understand how to achieve this correct pairing I would be grateful.

UPDATE: After testing Thomas solution, this is the error I am getting:

{"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":"BadRequest","message":"{\r\n  \"error\": {\r\n    \"code\": \"KeyVaultPolicyError\",\r\n    \"message\": \"Keyvault policy recoverable is not set\"\r\n  }\r\n}"},{"code":"BadRequest","message":"{\r\n  \"error\": {\r\n    \"code\": \"KeyVaultPolicyError\",\r\n    \"message\": \"Keyvault policy recoverable is not set\"\r\n  }\r\n}"}]}}

CodePudding user response:

I'm assuming the key vault is created and uses access policies.

If you'd like to create the storage with customer-managed keys, the storage needs to get access to key vault before it is created so I'm using a user assigned identity in my sample.

Here are the steps:

  • Create a managed identity and grant key permissions on key vault
  • Create the two keys in key vault
  • Create the storage, assign the managed identity and use the key for encryption
// Default values I'm using to test 
param keyVaultName string = 'kvthomastest'
param managedIdentityName string = 'mi-storage-encryption-thomas-test'

param tenantCodes array = [
  'dsec'
  'sdre'
]

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

// 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'
  }
}]
  • Related