Примеры скриптов шифрования дисков Azure для виртуальных машин под управлением Linux

Это важно

Шифрование дисков Azure будет выведено из эксплуатации 15 сентября 2028 г. До этой даты вы можете продолжать использовать шифрование дисков Azure без нарушений. 15 сентября 2028 г. рабочие нагрузки с поддержкой ADE будут выполняться, но зашифрованные диски не смогут разблокироваться после перезагрузки виртуальной машины, что приведет к нарушению работы службы.

Используйте шифрование на узле для новых виртуальных машин или рассмотрите размеры конфиденциальных виртуальных машин с шифрованием дисков ОС для рабочих нагрузок конфиденциальных вычислений. Все виртуальные машины с поддержкой ADE (включая резервные копии) должны перенестися в шифрование на узле до даты выхода на пенсию, чтобы избежать прерывания работы службы. Дополнительные сведения см. в статье "Миграция из шифрования дисков Azure в шифрование на узле ".

Внимание

В этой статье упоминается CentOS — дистрибутив Linux, срок поддержки которого истёк (EOL). Думайте об использовании и планировании соответствующим образом. Для получения дополнительной информации см. рекомендации по завершению жизненного цикла CentOS.

Область применения: ✔️ Виртуальные машины Linux ✔️ Гибкие масштабируемые наборы

В этой статье приводятся примеры сценариев для подготовки предварительно зашифрованных виртуальных жестких дисков и других задач.

Примечание.

Все скрипты относятся к последней версии ADE, не связанной с Microsoft Entra ID, если не указано иное.

Примеры сценариев PowerShell для шифрования дисков Azure

  • Перечислите все зашифрованные виртуальные машины в вашей подписке

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

    Кроме того, эти командлеты отобразят все виртуальные машины, зашифрованные с помощью ADE (без версии расширения):

    $osVolEncrypted = {(Get-AzVMDiskEncryptionStatus -ResourceGroupName $_.ResourceGroupName -VMName $_.Name).OsVolumeEncrypted}
    $dataVolEncrypted= {(Get-AzVMDiskEncryptionStatus -ResourceGroupName $_.ResourceGroupName -VMName $_.Name).DataVolumesEncrypted}
    Get-AzVm | Format-Table @{Label="MachineName"; Expression={$_.Name}}, @{Label="OsVolumeEncrypted"; Expression=$osVolEncrypted}, @{Label="DataVolumesEncrypted"; Expression=$dataVolEncrypted}
    
  • Перечислите все зашифрованные экземпляры Масштабируемых наборов виртуальных машин в вашей подписке

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

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

    Get-AzKeyVaultSecret -VaultName $KeyVaultName | where {$_.Tags.ContainsKey('DiskEncryptionKeyFileName')} | format-table @{Label="MachineName"; Expression={$_.Tags['MachineName']}}, @{Label="VolumeLetter"; Expression={$_.Tags['VolumeLetter']}}, @{Label="EncryptionKeyURL"; Expression={$_.Id}}
    

Использование скрипта PowerShell для предварительных условий шифрования дисков Azure

Если вы уже знакомы с требованиями к шифрованию дисков Azure, вы можете использовать скрипт PowerShell для предварительных требований к шифрованию дисков Azure. Пример использования этого сценария PowerShell см. в статье Краткое руководство по шифрованию виртуальной машины. Вы можете удалить комментарии из раздела сценария, начиная со строки 211, чтобы шифровать все диски имеющихся виртуальных машин в имеющейся группе ресурсов.

В следующей таблице показаны параметры, которые можно использовать в скрипте PowerShell:

Параметр Описание Обязательный?
$resourceGroupName Имя группы ресурсов, к которой принадлежит KeyVault. Сценарий создает новую группу ресурсов с таким именем, если она не существует. Истина
$keyVaultName Имя хранилища ключей, в которое следует поместить ключи шифрования. Скрипт создает новое хранилище с таким именем, если хранилища с таким именем не существует. Истина
$location Расположение хранилища ключей. Убедитесь, что KeyVault и виртуальные машины, которые нужно зашифровать, находятся в одном регионе. Получите список местоположений с помощью команды Get-AzLocation. Истина
$subscriptionId Идентификатор используемой подписки Azure. Получите идентификатор подписки с помощью Get-AzSubscription. Истина
$aadAppName Имя приложения Microsoft Entra, которое записывает секреты в KeyVault. Скрипт создает новое приложение с таким именем, если приложения с таким именем не существует. Если это приложение уже есть, передайте параметр aadClientSecret в сценарий. Ложь
$aadClientSecret Секрет клиента приложения Microsoft Entra, которое было создано ранее. Ложь
$keyEncryptionKeyName Имя дополнительного ключа шифрования ключа в хранилище ключей. Скрипт создает новый ключ с таким именем, если он не существует. Ложь

Шифрование или расшифровка виртуальных машин без приложения Microsoft Entra

Шифрование или расшифровка виртуальных машин с помощью приложения Microsoft Entra (предыдущий выпуск)

Шифрование диска ОС на работающей виртуальной машине Linux

Предварительные требования для шифрования диска ОС

  • Виртуальная машина должна использовать дистрибутив, совместимый с шифрованием диска ОС. Список дистрибутивов см. в статье Операционные системы с поддержкой шифрования дисков Azure.
  • Виртуальная машина должна быть создана из образа Marketplace в Azure Resource Manager.
  • Виртуальная машина Azure по крайней мере с 4 ГБ ОЗУ (рекомендуемый размер — 7 ГБ). Дополнительные сведения см. в разделе "Требования к памяти".
  • (Для RHEL и CentOS.) Отключите SELinux. Чтобы отключить SELinux, ознакомьтесь с разделом "4.4.2. "Отключение SELinux" в разделе руководства пользователя и администратора SELinux на виртуальной машине.
  • После отключения SELinux перезагрузите виртуальную машину по крайней мере один раз.

Шаги

  1. Создайте виртуальную машину с помощью одного из дистрибутивов, указанных ранее.

  2. Настройте виртуальную машину в соответствии с потребностями. Если вы собираетесь включить шифрование всех дисков (диска ОС и дисков данных), то диски данных необходимо указать и подключить в файле /etc/fstab.

    Примечание.

    Чтобы указать диски данных в файле /etc/fstab, используйте значение UUID=... (в этом случае не нужно указывать имя блочного устройства, например /dev/sdb1). В процессе шифрования порядок дисков на виртуальной машине изменится. Если на виртуальной машине используется определенный порядок блочных устройств, то при их подключении после шифрования произойдет сбой.

  3. Выйдите из сеансов SSH.

  4. Чтобы зашифровать ОС, задайте при включении шифрования для параметра volumeType значение All или OS.

    Примечание.

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

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

  6. Как только командлет Get-AzVmDiskEncryptionStatus вернет значение "VMRestartPending", перезапустите виртуальную машину, войдя в систему, либо с помощью портала, PowerShell или CLI.

    C:\> Get-AzVmDiskEncryptionStatus  -ResourceGroupName $ResourceGroupName -VMName $VMName
    -ExtensionName $ExtensionName
    
    OsVolumeEncrypted          : VMRestartPending
    DataVolumesEncrypted       : NotMounted
    OsVolumeEncryptionSettings : Microsoft.Azure.Management.Compute.Models.DiskEncryptionSettings
    ProgressMessage            : OS disk successfully encrypted, reboot the VM
    

    Перед перезагрузкой сохраните диагностику загрузки виртуальной машины.

Мониторинг хода выполнения шифрования операционной системы

Мониторинг хода выполнения шифрования ОС можно выполнять тремя способами.

  • Используйте командлет Get-AzVmDiskEncryptionStatus и проверьте поле ProgressMessage.

    Get-AzVMDiskEncryptionStatus -ResourceGroupName $_.ResourceGroupName -VMName $_.Name
    
    OsVolumeEncrypted          : EncryptionInProgress
    DataVolumesEncrypted       : NotMounted
    OsVolumeEncryptionSettings : Microsoft.Azure.Management.Compute.Models.DiskEncryptionSettings
    ProgressMessage            : OS disk encryption started
    

    На виртуальных машинах с хранилищем класса Premium шифрование диска ОС длится 40–50 минут с момента появления сообщения "OS disk encryption started" (Начато шифрование диска ОС).

    Из-за проблемы GitHub #388 в WALinuxAgent OsVolumeEncrypted и DataVolumesEncrypted отображаются как Unknown в некоторых дистрибутивах. В WALinuxAgent 2.1.5 и более поздних версиях эта проблема исправляется автоматически. Если в выходных данных отображается Unknown, состояние шифрования дисков можно проверить с помощью обозревателя ресурсов Azure.

    Откройте обозреватель ресурсов Azure и на панели выбора слева разверните иерархическую структуру, как показано ниже.

    |-- subscriptions
       |-- [Your subscription]
            |-- resourceGroups
                 |-- [Your resource group]
                      |-- providers
                           |-- Microsoft.Compute
                                |-- virtualMachines
                                     |-- [Your virtual machine]
                                          |-- InstanceView
    

    В InstanceView прокрутите вниз, чтобы увидеть состояние шифрования дисков.

    Представление экземпляра виртуальной машины

  • Просмотрите диагностические данные загрузки. Сообщения из расширения ADE должны начинаться с [AzureDiskEncryption].

  • Войдите на виртуальную машину с помощью SSH и получите журнал расширений из:

    /var/log/azure/Microsoft.Azure.Security.AzureDiskEncryptionForLinux

    Не войдите на виртуальную машину во время выполнения шифрования ОС. Скопируйте журналы, только если другие два метода завершаются ошибкой.

Подготовка предварительно зашифрованного виртуального жесткого диска Linux

Подготовка предварительно зашифрованных виртуальных жестких дисков может отличаться в зависимости от дистрибутива. Доступны примеры подготовки Ubuntu, openSUSE и CentOS 7.

Настройте шифрование во время установки дистрибутива следующим образом.

  1. Во время настройки разделов дисков выберите Configure encrypted volumes (Настройка зашифрованных томов).

    Настройка Ubuntu 16.04 - Конфигурация зашифрованных томов

  2. Создайте отдельный загрузочный диск (незашифрованный). Зашифруйте корневой диск.

    Выбор устройств для шифрования при настройке Ubuntu 16.04

  3. Укажите парольную фразу. Вы передали эту парольную фразу в хранилище ключей.

    Указание парольной фразы при настройке Ubuntu 16.04

  4. Завершите разбиение на разделы.

    Завершение секционирования при настройке Ubuntu 16.04

  5. После загрузки виртуальной машины отобразится запрос парольной фразы. Введите парольную фразу, указанную на шаге 3.

    Указание парольной фразы во время загрузки при настройке Ubuntu 16.04

  6. Подготовьте виртуальную машину к передаче в Azure, следуя этим инструкциям. Не выполняйте пока последний шаг (удаление виртуальной машины).

Настройте шифрование для Azure, выполнив следующие шаги.

  1. Создайте файл в разделе /usr/local/sbin/azure_crypt_key.shс содержимым в следующем скрипте. Обратите внимание на параметр KeyFileName — это имя файла парольной фразы, используемое Azure.

    #!/bin/sh
    MountPoint=/tmp-keydisk-mount
    KeyFileName=LinuxPassPhraseFileName
    echo "Trying to get the key from disks ..." >&2
    mkdir -p $MountPoint
    modprobe vfat >/dev/null 2>&1
    modprobe ntfs >/dev/null 2>&1
    sleep 2
    OPENED=0
    cd /sys/block
    for DEV in sd*; do
    
        echo "> Trying device: $DEV ..." >&2
        mount -t vfat -r /dev/${DEV}1 $MountPoint >/dev/null||
        mount -t ntfs -r /dev/${DEV}1 $MountPoint >/dev/null
        if [ -f $MountPoint/$KeyFileName ]; then
                cat $MountPoint/$KeyFileName
                umount $MountPoint 2>/dev/null
                OPENED=1
                break
        fi
        umount $MountPoint 2>/dev/null
    done
    
      if [ $OPENED -eq 0 ]; then
        echo "FAILED to find suitable passphrase file ..." >&2
        echo -n "Try to enter your password: " >&2
        read -s -r A </dev/console
        echo -n "$A"
     else
        echo "Success loading keyfile!" >&2
    fi
    
  2. Измените настройки шифрования в /etc/crypttab. Он должен выглядеть так:

     xxx_crypt uuid=xxxxxxxxxxxxxxxxxxxxx none luks,discard,keyscript=/usr/local/sbin/azure_crypt_key.sh
    
  3. Добавьте в сценарий разрешения для исполняемого файла.

     sudo chmod +x /usr/local/sbin/azure_crypt_key.sh
    
  4. Редактируйте /etc/initramfs-tools/modules путем добавления строк:

     vfat
     ntfs
     nls_cp437
     nls_utf8
     nls_iso8859-1
    
  5. Выполните update-initramfs -u -k all и обновите initramfs, чтобы keyscript вступил в действие.

  6. Теперь виртуальную машину можно депровизировать.

    Обновление initramfs при настройке Ubuntu 16.04

  7. Перейдите к следующему шагу и передайте свой виртуальный жесткий диск в Azure.

Загрузка зашифрованного VHD в учетную запись Azure для хранения

После включения шифрования DM-Crypt локальный зашифрованный VHD нужно отправить в аккаунт хранения.

    Add-AzVhd [-Destination] <Uri> [-LocalFilePath] <FileInfo> [[-NumberOfUploaderThreads] <Int32> ] [[-BaseImageUriToPatch] <Uri> ] [[-OverWrite]] [ <CommonParameters>]

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

При шифровании с помощью приложения Microsoft Entra (предыдущего выпуска) секрет шифрования дисков, полученный ранее, должен быть отправлен в качестве секрета в хранилище ключей. Хранилище ключей должно включать шифрование дисков и разрешения для клиента Microsoft Entra.

 $AadClientId = "My-AAD-Client-Id"
 $AadClientSecret = "My-AAD-Client-Secret"

 $key vault = New-AzKeyVault -VaultName $KeyVaultName -ResourceGroupName $ResourceGroupName -Location $Location

 Set-AzKeyVaultAccessPolicy -VaultName $KeyVaultName -ResourceGroupName $ResourceGroupName -ServicePrincipalName $AadClientId -PermissionsToKeys all -PermissionsToSecrets all
 Set-AzKeyVaultAccessPolicy -VaultName $KeyVaultName -ResourceGroupName $ResourceGroupName -EnabledForDiskEncryption

Секрет дискового шифрования не шифруется с помощью KEK

Выполните командлет Set-AzKeyVaultSecret, чтобы настроить секрет в хранилище ключей. Парольную фразу можно закодировать в формате Base64, а затем отправить в хранилище ключей. Кроме того, убедитесь, что при создании секрета в хранилище ключей заданы следующие теги.


 # This is the passphrase that was provided for encryption during the distribution installation
 $passphrase = "contoso-password"

 $tags = @{"DiskEncryptionKeyEncryptionAlgorithm" = "RSA-OAEP"; "DiskEncryptionKeyFileName" = "LinuxPassPhraseFileName"}
 $secretName = [guid]::NewGuid().ToString()
 $secretValue = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($passphrase))
 $secureSecretValue = ConvertTo-SecureString $secretValue -AsPlainText -Force

 $secret = Set-AzKeyVaultSecret -VaultName $KeyVaultName -Name $secretName -SecretValue $secureSecretValue -tags $tags
 $secretUrl = $secret.Id

$secretUrl Используйте следующий шаг для подключения диска ОС без использования KEK.

Секрет дискового шифрования, зашифрованный с помощью KEK

Перед передачей секрета в хранилище ключей его можно дополнительно зашифровать с помощью ключа шифрования ключей. Используйте API обертки, чтобы сначала зашифровать секрет, используя ключ шифрования ключей. Эта операция обертывания возвращает строку, закодированную в URL-совместимой кодировке Base64, которую затем можно загрузить как секрет с помощью командлета Set-AzKeyVaultSecret.

    # This is the passphrase that was provided for encryption during the distribution installation
    $passphrase = "contoso-password"

    Add-AzKeyVaultKey -VaultName $KeyVaultName -Name "keyencryptionkey" -Destination Software
    $KeyEncryptionKey = Get-AzKeyVaultKey -VaultName $KeyVault.OriginalVault.Name -Name "keyencryptionkey"

    $apiversion = "2015-06-01"

    ##############################
    # Get Auth URI
    ##############################

    $uri = $KeyVault.VaultUri + "/keys"
    $headers = @{}

    $response = try { Invoke-RestMethod -Method GET -Uri $uri -Headers $headers } catch { $_.Exception.Response }

    $authHeader = $response.Headers["www-authenticate"]
    $authUri = [regex]::match($authHeader, 'authorization="(.*?)"').Groups[1].Value

    Write-Host "Got Auth URI successfully"

    ##############################
    # Get Auth Token
    ##############################

    $uri = $authUri + "/oauth2/token"
    $body = "grant_type=client_credentials"
    $body += "&client_id=" + $AadClientId
    $body += "&client_secret=" + [Uri]::EscapeDataString($AadClientSecret)
    $body += "&resource=" + [Uri]::EscapeDataString("https://vault.azure.net")
    $headers = @{}

    $response = Invoke-RestMethod -Method POST -Uri $uri -Headers $headers -Body $body

    $access_token = $response.access_token

    Write-Host "Got Auth Token successfully"

    ##############################
    # Get KEK info
    ##############################

    $uri = $KeyEncryptionKey.Id + "?api-version=" + $apiversion
    $headers = @{"Authorization" = "Bearer " + $access_token}

    $response = Invoke-RestMethod -Method GET -Uri $uri -Headers $headers

    $keyid = $response.key.kid

    Write-Host "Got KEK info successfully"

    ##############################
    # Encrypt passphrase by using KEK
    ##############################

    $passphraseB64 = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($Passphrase))
    $uri = $keyid + "/encrypt?api-version=" + $apiversion
    $headers = @{"Authorization" = "Bearer " + $access_token; "Content-Type" = "application/json"}
    $bodyObj = @{"alg" = "RSA-OAEP"; "value" = $passphraseB64}
    $body = $bodyObj | ConvertTo-Json

    $response = Invoke-RestMethod -Method POST -Uri $uri -Headers $headers -Body $body

    $wrappedSecret = $response.value

    Write-Host "Encrypted passphrase successfully"

    ##############################
    # Store secret
    ##############################

    $secretName = [guid]::NewGuid().ToString()
    $uri = $KeyVault.VaultUri + "/secrets/" + $secretName + "?api-version=" + $apiversion
    $secretAttributes = @{"enabled" = $true}
    $secretTags = @{"DiskEncryptionKeyEncryptionAlgorithm" = "RSA-OAEP"; "DiskEncryptionKeyFileName" = "LinuxPassPhraseFileName"}
    $headers = @{"Authorization" = "Bearer " + $access_token; "Content-Type" = "application/json"}
    $bodyObj = @{"value" = $wrappedSecret; "attributes" = $secretAttributes; "tags" = $secretTags}
    $body = $bodyObj | ConvertTo-Json

    $response = Invoke-RestMethod -Method PUT -Uri $uri -Headers $headers -Body $body

    Write-Host "Stored secret successfully"

    $secretUrl = $response.id

Используйте $KeyEncryptionKey и $secretUrl на следующем шаге для подключения диска ОС с помощью KEK.

Укажите секретный URL-адрес при подключении ОС-диска

Без использования KEK

При подключении диска ОС необходимо передать $secretUrl. URL-адрес создается в разделе "Секрет шифрования дисков, не зашифрованный с помощью KEK".

    Set-AzVMOSDisk `
            -VM $VirtualMachine `
            -Name $OSDiskName `
            -SourceImageUri $VhdUri `
            -VhdUri $OSDiskUri `
            -Linux `
            -CreateOption FromImage `
            -DiskEncryptionKeyVaultId $KeyVault.ResourceId `
            -DiskEncryptionKeyUrl $SecretUrl

Использование KEK

При подключении диска ОС передайте $KeyEncryptionKey и $secretUrl. URL-адрес создается в разделе "Секрет шифрования дисков, зашифрованный с помощью KEK".

    Set-AzVMOSDisk `
            -VM $VirtualMachine `
            -Name $OSDiskName `
            -SourceImageUri $CopiedTemplateBlobUri `
            -VhdUri $OSDiskUri `
            -Linux `
            -CreateOption FromImage `
            -DiskEncryptionKeyVaultId $KeyVault.ResourceId `
            -DiskEncryptionKeyUrl $SecretUrl `
            -KeyEncryptionKeyVaultId $KeyVault.ResourceId `
            -KeyEncryptionKeyURL $KeyEncryptionKey.Id