Linux VM에 대한 Azure Disk Encryption 샘플 스크립트

주의

이 문서에서는 EOL(수명 종료) 상태에 가까워진 Linux 배포판인 CentOS를 참조하세요. 이에 따라 사용 및 플랜을 고려하세요. 자세한 내용은 CentOS 수명 종료 지침을 참조하세요.

적용 대상: ✔️ Linux VM ✔️ 유연한 확장 집합

이 문서에서는 미리 암호화된 VHD 및 기타 작업을 준비하기 위한 샘플 스크립트를 제공합니다.

참고 항목

모든 스크립트는 달리 명시된 경우를 제외하면 AAD가 아닌 ADE 최신 버전을 참조합니다.

Azure Disk Encryption용 샘플 PowerShell 스크립트

  • 구독에서 암호화된 VM 모두 나열

    이 PowerShell 스크립트를 사용하여 구독에 있는 리소스 그룹 전체에서 모든 ADE 암호화 VM 및 확장 버전을 찾을 수 있습니다.

    아니면 cmdlet이 모든 ADE 암호화 VM(확장 버전 제외)을 표시합니다.

    $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 인스턴스 모두 나열

    이 PowerShell 스크립트를 사용하여 구독에 있는 모든 리소스 그룹에서 모든 ADE 암호화 VMSS 인스턴스 및 확장 버전을 찾을 수 있습니다.

  • 키 자격 증명 모음에서 VM 암호화에 사용된 디스크 암호화 비밀 모두 나열

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

Azure Disk Encryption 필수 구성 요소 PowerShell 스크립트 사용

Azure Disk Encryption에 대한 필수 구성 요소에 이미 익숙한 경우 Azure Disk Encryption 필수 구성 요소 PowerShell 스크립트를 사용할 수 있습니다. 이 PowerShell 스크립트 사용의 예는 VM 암호화 빠른 시작를 참조하세요. 줄 211에서 시작하는 스크립트의 섹션에서 주석을 제거하여 기존 리소스 그룹의 기존 VM에 대한 모든 디스크를 암호화할 수 있습니다.

다음 표는 PowerShell 스크립트에서 사용할 수 있는 매개 변수를 보여줍니다.

매개 변수 설명 필수입니까?
$resourceGroupName KeyVault가 속해 있는 리소스 그룹의 이름입니다. 이 이름을 가진 새 리소스 그룹이 없는 경우 생성됩니다. True
$keyVaultName 암호화 키가 배치된 KeyVault의 이름입니다. 이 이름을 가진 새 자격 증명 모음이 없는 경우 생성됩니다. True
$location KeyVault의 위치입니다. 암호화할 KeyVault 및 VM이 동일한 위치에 있는지 확인합니다. Get-AzLocation을 사용하여 위치 목록을 가져옵니다. True
$subscriptionId 사용할 Azure 구독의 식별자입니다. 구독 ID는 Get-AzSubscription을 사용하여 가져올 수 있습니다. True
$aadAppName KeyVault에 비밀을 쓰는 데 사용할 Microsoft Entra 애플리케이션의 이름입니다. 이 이름을 가진 새 애플리케이션이 없는 경우 생성됩니다. 이 앱이 이미 있는 경우 스크립트에 aadClientSecret 매개 변수를 전달합니다. False
$aadClientSecret 이전에 만든 Microsoft Entra 애플리케이션의 클라이언트 암호입니다. False
$keyEncryptionKeyName KeyVault의 선택적 키 암호화 키의 이름입니다. 이 이름을 가진 새 키가 없는 경우 생성됩니다. False

Microsoft Entra 앱 없이 VM을 암호화 또는 암호 해독

Microsoft Entra 앱으로 VM을 암호화 또는 암호 해독(이전 릴리스)

실행 중인 Linux VM에서 OS 드라이브 암호화

OS 디스크 암호화를 위한 필수 조건

  • VM은 Azure Disk Encryption가 지원되는 운영 체제에 나열된 것과 같이 OS 디스크 암호화와 호환되는 배포를 사용해야 합니다.
  • Azure Resource Manager의 Marketplace 이미지에서 VM을 만들어야 합니다.
  • 4GB 이상의 RAM이 있는 Azure VM(권장 크기는 7GB)이 있어야 합니다. 자세한 내용은 메모리 요구 사항을 참조하세요.
  • (RHEL 및 CentOS) SELinux를 사용하지 않도록 설정합니다. SELinux를 사용하지 않도록 설정하려면 VM에 대한 SELinux 사용자 및 관리자 가이드에서 "4.4.2. SELinux 사용 안 함"을 참조하세요.
  • SELinux를 사용하지 않도록 설정한 후 VM을 한 번 이상 다시 부팅합니다.

단계

  1. 이전에 지정한 배포판 중 하나를 사용하여 VM을 만듭니다.

  2. 필요에 따라 VM을 구성합니다. 모든(OS + 데이터) 드라이브를 암호화하려는 경우 데이터 드라이브를 지정하고 /etc/fstab에서 탑재할 수 있어야 합니다.

    참고 항목

    블록 디바이스 이름(예: /dev/sdb1)을 지정하는 대신, UUID=...를 사용하여 /etc/fstab에서 데이터 드라이브를 지정합니다. 암호화하는 동안 드라이브의 순서는 VM에서 변경됩니다. VM이 블록 디바이스의 특정 순서에 의존하는 경우 암호화 후 탑재하지 못합니다.

  3. SSH 세션에서 로그아웃합니다.

  4. OS를 암호화하려면 암호화를 사용하도록 설정할 때 volumeType을 All 또는 OS로 지정합니다.

    참고 항목

    systemd 서비스로 실행되지 않는 모든 사용자 공간 프로세스는 SIGKILL로 중지됩니다. VM을 다시 부팅합니다. 실행 중인 VM에서 OS 디스크 암호화를 사용할 경우 VM의 가동 중지 시간을 계획하세요.

  5. 다음 섹션의 지침에 따라 암호화 진행 상태를 주기적으로 모니터링합니다.

  6. Get-AzVmDiskEncryptionStatus에 “VMRestartPending”이 표시된 후 VM에 로그인하거나 포털, PowerShell 또는 CLI를 사용하여 VM을 다시 시작합니다.

    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
    

    VM을 다시 부팅하기 전에 VM의 부트 진단을 저장하는 것이 좋습니다.

OS 암호화 진행 상태 모니터링

OS 암호화 진행 상태를 모니터링하는 방법은 세 가지가 있습니다.

  • Get-AzVmDiskEncryptionStatus cmdlet을 사용하고 ProgressMessage 필드를 검사합니다.

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

    Premium 스토리지 지원 VM의 경우 VM이 "OS 디스크 암호화 시작됨"에 도달한 후 약 40~50분이 소요됩니다.

    WALinuxAgent에서 문제 #388으로 인해 일부 배포판에서 OsVolumeEncryptedDataVolumesEncryptedUnknown으로 표시됩니다. WALinuxAgent 2.1.5 버전 이상에서는 이 문제가 자동으로 수정됩니다. 출력에 Unknown이 표시되는 경우 Azure Resource Explorer를 사용하여 디스크 암호화 상태를 확인할 수 있습니다.

    Azure Resource Explorer로 이동한 후 왼쪽의 선택 패널에서 이 계층 구조를 확장합니다.

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

    InstanceView에서 아래로 스크롤하여 드라이브의 암호화 상태를 확인합니다.

    VM 인스턴스 보기

  • 부트 진단을 살펴봅니다. ADE 확장의 메시지에는 [AzureDiskEncryption]이라는 접두사가 붙습니다.

  • SSH를 통해 VM에 로그온하고 다음에서 확장 로그를 가져옵니다.

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

    OS 암호화가 진행 중인 동안에는 VM에 로그온하지 않는 것이 좋습니다. 다른 두 가지 방법이 실패한 경우에만 로그가 복사됩니다.

사전에 암호화된 Linux VHD 준비

미리 암호화된 VHD에 대한 준비는 배포에 따라 달라질 수 있습니다. Ubuntu, openSUSE, CentOS 7 준비에 대한 예제를 사용할 수 있습니다.

다음 단계를 수행하여 배포를 설치하는 도중에 암호화를 구성합니다.

  1. 디스크를 분할할 때 암호화된 볼륨 구성을 선택합니다.

    Ubuntu 16.04 설치 - 암호화된 볼륨 구성

  2. 암호화되지 않아야 하는 별도의 부트 드라이브를 만듭니다. 루트 드라이브를 암호화합니다.

    Ubuntu 16.04 설치 - 암호화할 디바이스 선택

  3. 암호를 제공합니다. 키 자격 증명 모음에 업로드한 암호입니다.

    Ubuntu 16.04 설치 - 암호 제공

  4. 분할을 완료합니다.

    Ubuntu 16.04 설치 - 분할 완료

  5. VM을 부팅하고 암호를 묻는 메시지가 표시되면 3단계에서 제공한 암호를 사용합니다.

    Ubuntu 16.04 설치 - 부팅 시 암호 제공

  6. 이 지침을 사용하여 Azure에 업로드하기 위한 VM을 준비합니다. 마지막 단계(VM 프로비전 해제)를 아직 실행하지 마세요.

다음 단계를 수행하여 Azure로 작업하는 암호화를 구성합니다.

  1. /usr/local/sbin/azure_crypt_key.sh 아래에 다음 스크립트의 콘텐츠를 사용하여 파일을 만듭니다. Azure에서 사용된 암호 파일 이름이므로 KeyFileName에 주의해야 합니다.

    #!/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. initramfs를 업데이트하는 update-initramfs -u -k all을 실행하여 keyscript를 적용합니다.

  6. 이제 VM을 프로비전 해제할 수 있습니다.

    Ubuntu 16.04 설치 - update-initramfs

  7. 다음 단계를 계속하여 Azure에 VHD를 업로드합니다.

Azure Storage 계정에 암호화된 VHD 업로드

DM-Crypt 암호화를 사용하도록 설정한 후에는 로컬 암호화된 VHD를 스토리지 계정에 업로드해야 합니다.

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

미리 암호화된 VM에 대한 비밀을 키 자격 증명 모음에 업로드

Microsoft Entra 앱(이전 릴리스)을 사용하여 암호화하는 경우 이전에 가져온 디스크 암호화 비밀을 키 자격 증명 모음에 비밀로 업로드해야 합니다. Key Vault에는 디스크 암호화 및 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 문자열로 인코딩된 후 키 자격 증명 모음으로 업로드됩니다. 또한 Key Vault에서 비밀을 만들 때 다음 태그가 설정되었는지 확인합니다.


 # 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

KEK를 사용하지 않고 OS 디스크를 연결하기 위해 다음 단계에서 $secretUrl을 사용합니다.

KEK로 암호화된 디스크 암호화 암호

비밀을 Key Vault에 업로드하기 전에 주요 암호화 키를 사용하여 선택적으로 암호화할 수 있습니다. 먼저 래핑 API를 사용하여 주요 암호화 키로 비밀을 암호화합니다. 이 래핑 작업의 출력은 base64 URL 인코딩 문자열로 Set-AzKeyVaultSecret cmdlet을 사용하여 비밀로 업로드할 수 있습니다.

    # 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 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$secretUrlKEK를 사용하여 OS 디스크를 연결하기 위해 다음 단계에서 사용합니다.

OS 디스크를 연결할 때 비밀 URL 지정

KEK 사용 안 함

OS 디스크를 연결하는 동안 $secretUrl을 전달해야 합니다. URL은 "KEK로 암호화되지 않은 디스크 암호화 비밀" 섹션에서 생성했습니다.

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

KEK 사용

OS 디스크를 연결할 때 $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