Veeam Azure Object Storage Automation

During my prior blog post, I had the requirement to spin up a lot of Azure Object Storage Repositories. As is usually the case, this quickly led me to Veeam Azure Object Storage Automation. I am pretty new to Azure automation, so this was an exciting topic. Please feel free to reach out if you are more experienced in Azure automation and see some enhancement opportunities.

Before starting my Veeam Azure Object Storage Automation journey, I first had to understand the process.

Very quickly I realized, the end-to-end process of creating a new Azure Blob Storage from scratch is pretty time-consuming and has some pitfalls that can also be a security problem. But the overall goal was not only creating the S3 Bucket, I also needed to add the newly created Azure Blob Storage to my Veeam Backup & Replication V12 inventory.

Veeam Azure Object Storage Automation - Veeam Backup & Replication V12 Repository
Veeam Azure Object Storage Automation - Veeam Backup & Replication V12 Backup

Veeam Azure Object Storage with PowerShell

My first try was automating the process with the Cmlets of the Az PowerShell Module. Theoretically, this works, but it requires a lot of additional steps to achieve a proper configuration.

#Install-Module -Name Az -Scope CurrentUser
Import-Module -Name Az
Connect-AzAccount

Import-Module -Name Veeam.Backup.PowerShell 
$VBRCredentials = Get-Credential -Message "VBR Credentials"
Connect-VBRServer -Server 192.168.70.146 -Credential $VBRCredentials

$resourceGroup = "veeamautomation"
$location = "germanywestcentral"
$accountName = "veeamautomationstorage"
$storageContainer = "veeamautomationstorageblob"

$AzResourceGroup = New-AzResourceGroup -Name $resourceGroup -Location $location
$AzStorageAccount = New-AzStorageAccount -ResourceGroupName $resourceGroup `
                    -Name $accountName `
                    -Location $location `
                    -SkuName Standard_LRS `
                    -Kind StorageV2 `
                    -AccessTier Hot 
$AzStorageAccount | Set-AzStorageAccount -AllowBlobPublicAccess $false
$AzStorageAccountKey = (Get-AzStorageAccountKey -ResourceGroupName $resourceGroup -Name $accountName ).Value[0]
Start-Sleep 5
$AzStorageContainer = $AzStorageAccount | New-AzStorageContainer -Name $storageContainer
# Disable Soft Delete
$ctx = New-AzStorageContext -StorageAccountName $accountName -StorageAccountKey $AzStorageAccountKey
Disable-AzStorageDeleteRetentionPolicy -Context $ctx
Disable-AzStorageContainerDeleteRetentionPolicy -ResourceGroupName $resourceGroup `
    -StorageAccountName $accountName
Disable-AzStorageBlobDeleteRetentionPolicy -ResourceGroupName $resourceGroup `
    -StorageAccountName $accountName
Update-AzStorageFileServiceProperty -ResourceGroupName $resourceGroup `
    -StorageAccountName $accountName `
    -EnableShareDeleteRetentionPolicy $false 
# Disable Versioning
Update-AzStorageBlobServiceProperty -ResourceGroupName $resourceGroup `
    -StorageAccountName $accountName `
    -IsVersioningEnabled $false
# Set TLS Version
Set-AzStorageAccount -ResourceGroupName $resourceGroup `
    -StorageAccountName $accountName `
    -MinimumTlsVersion TLS1_2
<#
$AzStorageContainer | Remove-AzStorageContainer
$AzStorageAccount | Remove-AzStorageAccount -Confirm:$false -Force
$AzResourceGroup | Remove-AzResourceGroup -Confirm:$false -Force
#>

# Connect to VBR
## Credentials
$VBRAzureBlobAccount = Add-VBRAzureBlobAccount -Name $AzStorageAccountName -SharedKey $AzStorageAccountKey
## Create Folder
$VBRAzureBlobService = Connect-VBRAzureBlobService -Account $VBRAzureBlobAccount -RegionType Global -ServiceType CapacityTier
$VBRAzureBlobContainer = Get-VBRAzureBlobContainer -Connection $VBRAzureBlobService
$VBRAzureBlobFolder = New-VBRAzureBlobFolder -Container $VBRAzureBlobContainer -Connection $VBRAzureBlobService -Name "veeamautomation"
## Add Repo
$VBRAzureBlobRepository = Add-VBRAzureBlobRepository -AzureBlobFolder $VBRAzureBlobFolder[0] -Connection $VBRAzureBlobService -Name "veeamautomation"
## Disconect
Disconnect-VBRAzureBlobService -Connection $VBRAzureBlobService
Get-VBRBackupRepository -Name "veeamautomation"

Annotations

  • Line 1-7: Load Modules and Connect (Veeam & Azure)
  • Line 14: Create Azure Resource Group
  • Line 15-20: Create Azure Storage Account
  • Line 21: Disable Blob Public Access for Azure Storage Account
  • Line 22: Get Azure Storage Account Key
  • Line 24: Create Azure Storage Container
  • Line 26-34: Disable Azure Storage Soft-Delete
  • Line 36-38: Disable Blob Versioning
  • Line 40-42: Set Storage Account to TLS Version 1.2
  • Line 51: Add Veeam Credentials for the Azure Storage Account
  • Line 53-55: Create a new Folder in the S3 Bucket Root
  • Line 57: Add a new Veeam Azure Object Storage Repository

Veeam Azure Object Storage with ARM template

After some research regarding the current state of Azure Automation, I moved over to an ARM template. Using the ARM templates has a lot of benefits over only PowerShell scrips or the Azure CLI.

  • Declarative syntax: ARM templates allow you to create and deploy an entire Azure infrastructure declaratively.
  • Orchestration: You don’t have to worry about the complexities of ordering operations. 
  • Built-in validation: Your template is deployed only after passing validation. 
  • Tracked deployments: In the Azure portal, you can review the deployment history and get information about the template deployment.
  • Freedom of choice regarding deployment

For more details, have look at “Why choose ARM templates?“.

#Install-Module -Name Az -Scope CurrentUser
Import-Module -Name Az
Connect-AzAccount

Import-Module -Name Veeam.Backup.PowerShell 
$VBRCredentials = Get-Credential -Message "VBR Credentials"
Connect-VBRServer -Server 192.168.70.146 -Credential $VBRCredentials

$resourceGroupName = "veeamautomation"
$location = "germanywestcentral"

# Create Ressources
## Resource Group
$AzResourceGroup = New-AzResourceGroup -Name $resourceGroupName -Location $location
## Storage Account
$AzResourceGroupDeployment = New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName `
    -TemplateFile ./arm/Veeam-AzureBlobtarget.json `
    -TemplateParameterFile ./arm/Veeam-AzureBlobtarget.parameters.json

$AzStorageAccountKey = (Get-AzStorageAccountKey -ResourceGroupName $resourceGroupName -Name $AzResourceGroupDeployment.Parameters.storageAccountName.Value ).Value[0]
$AzStorageAccountName = $AzResourceGroupDeployment.Parameters.storageAccountName.Value

# Remove-AzResourceGroup -Name $resourceGroupName

# Connect to VBR
## Credentials
$VBRAzureBlobAccount = Add-VBRAzureBlobAccount -Name $AzStorageAccountName -SharedKey $AzStorageAccountKey
## Create Folder
$VBRAzureBlobService = Connect-VBRAzureBlobService -Account $VBRAzureBlobAccount -RegionType Global -ServiceType CapacityTier
$VBRAzureBlobContainer = Get-VBRAzureBlobContainer -Connection $VBRAzureBlobService
$VBRAzureBlobFolder = New-VBRAzureBlobFolder -Container $VBRAzureBlobContainer -Connection $VBRAzureBlobService -Name "veeamautomationarm"
## Add Repo
$VBRAzureBlobRepository = Add-VBRAzureBlobRepository -AzureBlobFolder $VBRAzureBlobFolder[0] -Connection $VBRAzureBlobService -Name "veeamautomationarm"
## Disconect
Disconnect-VBRAzureBlobService -Connection $VBRAzureBlobService
Get-VBRBackupRepository -Name "veeamautomationarm"
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
      "storageAccountName": {
        "type": "string",
        "metadata": {
          "description": "Specifies the name of the Azure Storage account."
        }
      },
      "containerName": {
        "type": "string",
        "defaultValue": "logs",
        "metadata": {
          "description": "Specifies the name of the blob container."
        }
      },
      "location": {
        "type": "string",
        "defaultValue": "[resourceGroup().location]",
        "metadata": {
          "description": "Specifies the location in which the Azure Storage resources should be deployed."
        }
      }
    },
    "resources": [
      {
        "type": "Microsoft.Storage/storageAccounts",
        "apiVersion": "2022-05-01",
        "name": "[parameters('storageAccountName')]",
        "location": "[parameters('location')]",
        "sku": {
          "name": "Standard_LRS"
        },
        "kind": "StorageV2",
        "properties": {
          "accessTier": "Hot",
          "minimumTlsVersion": "TLS1_2",
          "supportsHttpsTrafficOnly": true,
          "publicNetworkAccess": "Enabled",
          "allowBlobPublicAccess": false,
          "allowSharedKeyAccess": true,
          "allowCrossTenantReplication": true,
          "defaultToOAuthAuthentication": false
        }
      },
      {
        "type": "Microsoft.Storage/storageAccounts/blobServices",
        "apiVersion": "2022-05-01",
        "name": "[concat(parameters('storageAccountName'), '/default')]",
        "properties": {
          "automaticSnapshotPolicyEnabled": false,
          "changeFeed": {
            "enabled": false
          },
          "containerDeleteRetentionPolicy": {
            "enabled": false
          },
          "deleteRetentionPolicy": {
            "enabled": false
          },
          "isVersioningEnabled": false,
          "restorePolicy": {
            "enabled": false
          }
        },
        "dependsOn": [
          "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
        ]

      },
      {
          "type": "Microsoft.Storage/storageAccounts/fileservices",
          "apiVersion": "2022-05-01",
          "name": "[concat(parameters('storageAccountName'), '/default')]",
          "properties": {
              "shareDeleteRetentionPolicy": {
                  "enabled": false
              }
          },
          "dependsOn": [
              "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]",
              "[concat(concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName')), '/blobServices/default')]"
          ]
      },
      {
        "type": "Microsoft.Storage/storageAccounts/blobServices/containers",
        "apiVersion": "2022-05-01",
        "name": "[format('{0}/default/{1}', parameters('storageAccountName'), parameters('containerName'))]",
        "dependsOn": [
          "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
        ]
      }
    ]
  }
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "storageAccountName": {
            "value": "veeamautomationstorage"
        },
        "containerName": {
            "value": "veeamautomationstorageblob"
        },
        "location": {
            "value": "germanywestcentral"
        }
    }
}

Annotations

PowerShell Script

  • Line 1-7: Load Modules and Connect (Veeam & Azure)
  • Line 14: Create Azure Resource Group
  • Line 15-20: Create Azure Storage Account
  • Line 16-48: Deploy ARM Template with properties file
  • Line 20: Get Azure Storage Account Key
  • Line 21: Get Azure Storage Account Name
  • Line 27: Add Veeam Credentials for the Azure Storage Account
  • Line 29-31: Create a new Folder in the S3 Bucket Root
  • Line 33: Add a new Veeam Azure Object Storage Repository

ARM Template

  • Line 1-25: Define Parameters
  • Line 27-45: Define Azure Storage Account
  • Line 47-71: Define Azure Blob Service
  • Line 72-85: Define Azure File Service

References

Leave a Reply