Автоматизируйте шифрование дисков Azure для виртуальных машин Windows

 Существует два метода шифрования-в состоянии покоя для виртуальных машин. Эти методы - шифрование служб хранения данных и шифрование дисков Azure. Я не буду вдаваться в подробности относительно различий и того, что такое шифрование в покое, поскольку все это очень хорошо задокументировано здесь.

Высокий уровень заключается в том, что шифрование службы хранения данных (которое включено по умолчанию и не может быть отключено) шифрует ваши данные в состоянии покоя. Azure Disk Encryption шифрует ОС и диски данных в состоянии покоя. Подробнее о различиях здесь.

Цель этой статьи-предоставить сценарий и продемонстрировать различные сценарии, в которых мой сценарий может быть использован для предоставления автоматизированного метода, который может зашифровать вашу ОС и диски данных, а также автоматически создать хранилище ключей, если таковое не существует, включая конфигурацию политики доступа.

Смотрите код внизу этого поста.

Первые четыре строки кода-это единственные переменные, которые вам придется изменить. Эти четыре переменные являются:

$keyVaultName = "KeyVaultName"
$keyVaultrgName = "KeyVaultRGName"
$vmRgName = "VMName"
$vmName = "VMRGName"

$keyVaultName должно содержать имя вашего хранилища ключей. Хранилище ключей должно быть включено для шифрования диска и иметь политику доступа, предоставляющую вашей учетной записи возможность работать с ключами.
$keyVaultrgName должно содержать имя группы ресурсов, в которой находится хранилище ключей.
$vmRgName должно содержать имя группы ресурсов, в которой находится виртуальная машина, для которой вы хотите включить шифрование.
$vmName должно быть именем вашей виртуальной машины, для которой вы хотите включить шифрование.

ОЧЕНЬ ВАЖНО: Как всегда, перед попыткой шифрования диска Azure необходимо сначала создать резервную копию виртуальной машины. Таким образом, если что-то пойдет не так с вашей виртуальной машиной во время процесса шифрования, она будет восстановлена.

Давайте рассмотрим несколько сценариев, в которых этот сценарий работает.

Сценарий 1-виртуальная машина не существует

Мои переменные выглядят так:

$keyVaultName = "ShudKeyVault"
$keyVaultrgName = "ShudKeyVault"
$vmRgName = "vmblog00"
$vmName = "vmblog00"

Виртуальная машина vmblog00 не существует.


После запуска Enable-AzureDiskEncryption, ps1 скрипт обнаруживает, что виртуальная машина не существует, по крайней мере, не в указанной группе ресурсов. Поэтому сценарий завершается.

Сценарий 2-виртуальная машина существует, но не работает

Мои переменные выглядят так:

$keyVaultName = "ShudKeyVault"
$keyVaultrgName = "ShudKeyVault"
$vmRgName = "vmblog01"
$vmName = "vmblog01"

Виртуальная машина vmblog01 действительно существует и находится в группе ресурсов, также называемой vmblog01. Эта виртуальная машина в настоящее время остановлена и освобождена, как показано ниже.


После запуска Enable-AzureDiskEncryption, ps1 скрипт обнаруживает, что виртуальная машина существует, но также обнаруживает, что виртуальная машина не запущена. Поэтому сценарий завершается.

Сценарий 3-виртуальная машина запущена и хранилище ключей существует

Мои переменные выглядят так же, как и Сценарий 2. Единственная разница здесь заключается в том, что виртуальная машина работает сейчас.

$keyVaultName = "ShudKeyVault"
$keyVaultrgName = "ShudKeyVault"
$vmRgName = "vmblog01"
$vmName = "vmblog01" 

Мы видим, что ShudKeyVault существует в группе ресурсов ShudKeyVault.


Если мы посмотрим на политику доступа для этого хранилища ключей, то увидим, что шифрование диска включено и моя учетная запись пользователя имеет доступ к управлению ключами.


После запуска Enable-AzureDiskEncryption, ps1,скрипт обнаруживает, что виртуальная машина существует, обнаруживает, что хранилище ключей существует. Поэтому скрипт создает новый ключ в формате [vmname]-[5 случайных цифр]. В нашем примере генерируется имя ключа vmblog01-44643. Затем диски шифруются с помощью этого ключа.

После некоторого ожидания шифрования наши диски теперь зашифрованы. У нас не было никаких дисков данных, поэтому мы видим, что только диск ОС был зашифрован, а подготовка дисплеев ProgressMessage прошла успешно.


Взглянув на ключи хранилища ключей, мы можем увидеть наш ключ vmblog01-44643.




Сценарий 4-виртуальная машина запущена, а хранилище ключей не существует

Мои переменные теперь совершенно другие. У нас есть новая виртуальная машина, а также хранилище ключей, которое не существует.

$keyVaultName = "ShudKeyVault02"
$keyVaultrgName = "ShudKeyVault02"
$vmRgName = "vmblog02"
$vmName = "vmblog02"

Мы видим, что ShudKeyVault02 не существует в группе ресурсов ShudKeyVault02.



Мы также видим, что виртуальная машина vmblog02 существует и работает.




После запуска Enable-AzureDiskEncryption, ps1 скрипт обнаруживает, что виртуальная машина существует, а хранилище ключей не существует. Поэтому скрипт спрашивает вас, Хотите ли вы создать новое хранилище ключей. Он просит у вас y (для ДА) или n (для Нет). Если мы выберем любой другой символ, такой как буква k, сценарий попросит снова. Если вы выберете n, сценарий завершится. Смотрите следующие скриншоты для примеров обоих вариантов.





Давайте снова запустим Enable-AzureDiskEncryption. ps1. на этот раз мы выберем y для Yes. Произойдет следующее: В группе ресурсов ShudKeyVault02 будет создано хранилище ключей с именем ShudKeyVault02. Хранилище ключей будет включено для шифрования диска. Политика доступа к хранилищу ключей будет создана с помощью существующего пользователя, вошедшего в систему и получившего полные разрешения на управление ключами.





И если мы посмотрим на разрешения хранилища ключей, то увидим, что новое хранилище ключей включено для шифрования диска, а существующий пользователь имеет полные разрешения для управления ключами.


Как и в случае с оригинальным ключом хранилища ключей, который был создан, он находится в формате [vmname]-[5 случайных цифр]. Для этого сценария генерируется имя ключа vmblog02-97815. Затем диски шифруются с помощью этого ключа.


Сценарий 5-виртуальная машина уже зашифрована

Мои переменные выглядят так:

$keyVaultName = "ShudKeyVault"
$keyVaultrgName = "ShudKeyVault"
$vmRgName = "vmblog01"
$vmName = "vmblog01"

Поскольку мы уже зашифровали виртуальную машину vmblog01 ранее в этой статье с помощью ShudKeyVault, мы ожидаем получить сообщение о том, что виртуальная машина уже зашифрована и сценарий завершается. Это обнаружение происходит, если виртуальная машина все еще существует и находится в рабочем состоянии. Если виртуальная машина не существует, результаты в сценарии 1 будет происходить. Если виртуальная машина не запущена, результаты в сценарии 2 будет происходить.

После запуска Enable-AzureDiskEncryption, ps1,скрипт действительно обнаруживает, что виртуальная машина уже зашифрована, и скрипт завершается.


код

Как и было обещано, код выглядит следующим образом... Дайте мне знать в комментариях, если у вас есть какие-либо вопросы.

$keyVaultName = "ShudKeyVault02"
$keyVaultrgName = "ShudKeyVault02"
$vmRgName = "vmblog02"
$vmName = "vmblog02"

try 
{
    Write-Host "Verifying Virtual Machine Exists... " -ForegroundColor Yellow
    $VMStatus = Get-AzVM -VMName $vmName -ResourceGroupName $vmRgName -Status -ErrorAction Stop
    $VMInfo = Get-AzVM -VMName $vmName -ResourceGroupName $vmRgName -ErrorAction Stop
    $VMRegion = $VMInfo.Location
    Write-Host "Verified Virtual Machine $vmName exists. Virtual Machine is located in the $VMRegion Azure Region." -ForegroundColor Green

    Write-Host " "
    Write-Host "Verifying Virtual Machine is Running... " -ForegroundColor Yellow
    # Need to ensure Virtual Machine is in a running state in order to be encrypted.
    $VMPowerState = $VMStatus.Statuses[1].DisplayStatus
    
    if ($VMPowerState -ne "VM running")
    {
        Write-Host "ERROR: Virtual Machine $vmName is not running. Cannot proceed with encryption. Terminating Script." -ForegroundColor Red
        exit
    }
    else
    {
        Write-Host "Verified Virtual Machine $vmName is running." -ForegroundColor Green
    }

    Write-Host " "
    Write-Host "Verifying Virtual Machine is not already encrypted... " -ForegroundColor Yellow    
    # Need to ensure the Virtual Machine is not already encrypted.
    $VMEncryptstatus = Get-AzVmDiskEncryptionStatus -ResourceGroupName $vmRgName -VMName $vmName
    $VMOSEncryptstatus = $VMEncryptstatus.OSVolumeEncrypted
    $VMDataEncryptstatus = $VMEncryptstatus.DataVolumesEncrypted
    if (($VMOSEncryptstatus -eq "Encrypted") -or ($VMDataEncryptstatus -eq "Encrypted"))
    {
        Write-Host "ERROR: The Virtual Machine is already encrypted.  Script Terminating." -ForegroundColor Red
        exit
    }
    else 
    {
        Write-Host "Verified Virtual Machine $vmName is not already encrypted." -ForegroundColor Green    
    }
    
}
catch 
{
    Write-Host "ERROR: The Virtual Machine $vmName does not exist. Terminating Script." -ForegroundColor Red
    exit
}

try 
{
    <#
        Checking for the existence of the Key Vault.  If key vault not found,
        an opportunity to create a new key vault with the same name is provided.  
        If you choose to create a new key vault, it will be created in the same region
        the Virtual Machine lives in.  This is why the Virtual Machine Check is before 
        the Key Vault Check.
    #>
    Write-Host " "
    Write-Host "Verifying Key Vault Exists... " -ForegroundColor Yellow
    $keyVault = Get-AzKeyVault -VaultName $keyVaultName -ResourceGroupName $keyVaultrgName
    if ($keyVault)
    {
        Write-Host "Verified Key Vault $keyVaultName exists." -ForegroundColor Green
        $diskEncryptionKeyVaultUrl = $keyVault.VaultUri;
        $keyVaultResourceId = $keyVault.ResourceId;
    }
    else 
    {
        throw "ERROR: The Key Vault $keyVaultName does not exist."    
    }
}
catch 
{
    Write-Host $_ -ForegroundColor Red

    Write-Host " "
    Write-Host "Providing opportunity to create a new Key Vault..." -ForegroundColor Yellow
    Write-Host "Would you like to create a new Key Vault with the name of $($keyVaultName)?" -ForegroundColor White

    $YesOrNo = Read-Host "Please enter your response (y/n)"
    while("y","n" -notcontains $YesOrNo )
    {
        $YesOrNo = Read-Host "Please enter your response (y/n)"
    }
    if ($YesOrNo -eq "y")
    {
        try
        {
            Write-Host " "
            Write-Host "Creating Resource Group with the name of $keyVaultrgName in the $VMRegion Azure Region to store the Key Vault $keyVaultName" -ForegroundColor Yellow
            $CheckResourceGroupExists = Get-AZResourceGroup -Name $keyVaultrgName -ErrorAction SilentlyContinue
            if ($CheckResourceGroupExists)
            {
                Write-Host "Resource Group $keyVaultrgName already exists." -ForegroundColor Green
            }
            else 
            {
                New-AzResourceGroup -Name $keyVaultrgName -Location $VMRegion | Out-Null
                Write-Host "Resource Group $keyVaultrgName successfully created." -ForegroundColor Green
                Start-Sleep 3
            }
            
            Write-Host " "
            Write-Host "Creating New Key Vault with the name of $keyVaultName in the $VMRegion Azure Region." -ForegroundColor Yellow
            $keyVault = New-AzKeyVault -VaultName $keyVaultName -ResourceGroupName $keyVaultrgName -Location $VMRegion -ErrorAction Stop
            Write-Host "Key Vault $keyVaultName successfully created." -ForegroundColor Green
            Start-Sleep 3
            $diskEncryptionKeyVaultUrl = $keyVault.VaultUri;
            $keyVaultResourceId = $keyVault.ResourceId;
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Host "ERROR: Key Vault could not be created." -ForgroundColor Red
            Write-Host "ERROR MESSAGE: $ErrorMessage" -ForegroundColor Red
        }

        try 
        {
            Write-Host " "
            Write-Host "Configuring Key Vault Access Policy to enable Disk Encryption." -ForegroundColor Yellow
            Set-AzKeyVaultAccessPolicy -VaultName $keyVaultName -ResourceGroupName $keyVaultrgName -EnabledForDiskEncryption -ErrorAction Stop
            Write-Host "Key Vault Policy successfully enabled for disk encryption." -ForegroundColor Green


            $SignedInAdmin = (Get-AzContext).Account.ID
            $objID=(Get-AzADUser -UserPrincipalName $SignedInAdmin).Id
            Write-Host " "
            Write-Host "Configuring Key Vault Access Policy to enable user $SignedInAdmin full permissions for key usage." -ForegroundColor Yellow
            Set-AzKeyVaultAccessPolicy -VaultName $keyVaultName `
                -ResourceGroupName $keyVaultrgName `
                -ObjectId $objID `
                -PermissionsToKeys create,delete,list,get,verify,encrypt,wrapkey `
                -ErrorAction Stop
            Write-Host "Successfully configured Key Vault Access Policy to enable user $SignedInAdmin full permissions for key usage." -ForegroundColor Green
        }
        catch 
        {
            $ErrorMessage = $_.Exception.Message
            Write-Host "Error setting access policies on the Key Vault $keyVaultName.  Please update Key Vault Policy manually and re-run script."
            Write-Host "ERROR MESSAGE: $ErrorMessage" -ForegroundColor Red
        }
    }
    else 
    {
        Write-Host "ERROR: The Key Vault $keyVaultName does not exist.  Terminating Script." -ForegroundColor Red    
        exit
    }
}

<#
    Extra Check and Balance that the Virtual Machine Exists. Not completely necessary due to
    the earlier try/catch.
#>
if ($VMStatus)
{
    # Set the Key Vault Key Name using the Virtual Machine Name followed by _ followed by 5 random digits.
    $keyVaultKeyName = $vmName + "-" + (get-random -minimum 10000 -max 99999)

    try 
    {
        Write-Host " "
        Write-Host "Adding Key Vault Key $keyVaultKeyName to the $keyVaultName Key Vault." -ForegroundColor Yellow
        Add-AzKeyVaultKey -VaultName $keyVaultName `
        -Name $keyVaultKeyName `
        -Destination "Software" `
        -ErrorAction Stop | Out-Null
        Write-Host "Successfully created the $keyVaultKeyName key in the $keyVaultName Key Vault." -ForegroundColor Green
    }
    catch 
    {
        $ErrorMessage = $_.Exception.Message
        Write-Host "ERROR: Could not add the $keyVaultKeyName to the $keyVaultName Key Vault. Terminating Script." -ForegroundColor Red
        Write-Host "ERROR MESSAGE: $ErrorMessage" -ForegroundColor Red
        exit
    }

    try 
    {
        Write-Host " "
        Write-Host "Verifying the Key Vault Key $keyVaultKeyName is instantiated and the key identifier is captured." -ForegroundColor Yellow
        $keyEncryptionKeyUrl = (Get-AzKeyVaultKey -VaultName $keyVaultName -Name $keyVaultKeyName -ErrorAction Stop).Key.kid
        Write-Host "Key Vault Key Identifier for Key Vault Key $keyVaultKeyName successfully captured." -ForegroundColor Green
    }
    catch 
    {
        Write-Host "ERROR: Could not obtain the Key Encryption Key URL. Terminating Script." -ForegroundColor Red
    }

    try
    {
        Write-Host " "
        Write-Host "###########################################" -ForegroundColor Yellow
        Write-Host "Beginning Disk Encryption utilizing the following resources: " -ForegroundColor Yellow
        Write-Host "VMName: $VMName" -ForegroundColor Yellow
        Write-Host "VMResourceGroupName: $vmRgName" -ForegroundColor Yellow
        Write-Host "KeyVaultName: $keyVaultName" -ForegroundColor Yellow
        Write-Host "KeyVaultResourceGroupName: $keyVaultrgName" -ForegroundColor Yellow
        Write-Host "KeyVaultKeyName: $keyVaultKeyName" -ForegroundColor Yellow
        Write-Host " "
        Write-Host "Please be patient as the Virtual Machine ($vmName)'s disks are encrypted." -ForegroundColor Yellow
        Write-Host "###########################################" -ForegroundColor Yellow

        Set-AzVMDiskEncryptionExtension -ResourceGroupName $vmRgName `
        -VMName $vmName `
        -DiskEncryptionKeyVaultUrl $diskEncryptionKeyVaultUrl `
        -DiskEncryptionKeyVaultId $keyVaultResourceId `
        -KeyEncryptionKeyUrl $keyEncryptionKeyUrl `
        -KeyEncryptionKeyVaultId $keyVaultResourceId `
        -Force `
        -ErrorAction Stop | Out-Null
    }
    catch
    {
        $ErrorMessage = $_.Exception.Message
        Write-Host "Failed to enable disk encryption on $vmName. Terminating Script." -ForegroundColor Red
        Write-Host "ERROR MESSAGE: $ErrorMessage" -ForegroundColor Red
        exit
    }
}
else 
{
    <#
        Extra Check and Balance that the Virtual Machine Exists. Not completely necessary due to
        the earlier try/catch.
    #>
    Write-Host "ERROR: The Virtual Machine $vmName does not exist. Terminating Script." -ForegroundColor Red
    exit  
}

Write-Host " "
Write-Host "Verifying Encryption Status..." -ForegroundColor Yellow
do 
{
    $VMEncryptstatus = Get-AzVmDiskEncryptionStatus -ResourceGroupName $vmRgName -VMName $vmName
    $EncryptionProgress = $VMEncryptstatus.ProgressMessage
    $VMEncryptstatus
    Start-Sleep 10
} until ($EncryptionProgress -like "*Provisioning succeeded*")