Share via


Linux VM 用の Azure Disk Encryption のサンプル スクリプト

注意

この記事では、間もなくサポート終了 (EOL) 状態になる Linux ディストリビューションである CentOS について説明します。 適宜、使用と計画を検討してください。 詳細については、「CentOS のサポート終了に関するガイダンス」を参照してください。

適用対象: ✔️ Linux VM ✔️ フレキシブルなスケール セット

この記事では、事前に暗号化された VHD の準備およびその他のタスクのためのサンプル スクリプトを提供します。

Note

すべてのスクリプトでは、特に明記されている場合を除き、非 AAD の最新バージョンの ADE が参照されます。

Azure Disk Encryption 用の PowerShell スクリプトのサンプル

  • サブスクリプション内の暗号化された VM をすべて一覧表示する

    この PowerShell スクリプトを使用して、サブスクリプションに存在するすべてのリソース グループの ADE で暗号化されたすべての VM と拡張バージョンを見つけることができます。

    また、これらのコマンドレットを使用すると、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 の暗号化のクイック スタートに関するページを参照してください。 既存のリソース グループ内の既存の VM のすべてのディスクを暗号化するために、スクリプトの 211 行目から始まるセクションのコメントを削除することができます。

次の表は、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 ディスクを暗号化するための前提条件

手順

  1. 上記のディストリビューションのいずれかを使用して、VM を作成します。

  2. ニーズに応じて VM を構成します。 すべてのドライブ (OS およびデータ) を暗号化する場合は、/etc/fstab にデータ ドライブを指定してマウントできるようにする必要があります。

    注意

    /etc/fstab にデータ ドライブを指定するには、ブロック デバイス名 (たとえば、/dev/sdb1 など) ではなく、UUID=... を使用してください。 暗号化中には、ドライブの順序が 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 のブート診断を保存することをお勧めします。

OS 暗号化の進行状況の監視

OS 暗号化の進行状況を監視するには、次の 3 つの方法があります。

  • 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
    

    VM が "OS disk encryption started (OS ディスクの暗号化が開始されました)" 状態に達するまで、Premium ストレージを使用する VM でおよそ 40 分から 50 分かかります。

    WALinuxAgent での問題 #388 により、一部のディストリビューションでは、OsVolumeEncryptedDataVolumesEncryptedUnknown と表示されます。 WALinuxAgent バージョン 2.1.5 以降では、この問題は自動的に修正されます。 出力に Unknown が含まれている場合は、Azure リソース エクスプローラーを使用して、ディスクの暗号化状態を確認できます。

    Azure リソース エクスプローラーに移動し、左側の選択パネルで次の階層を展開します。

    |-- 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 にサインインしないでください。 ログのコピーは、他の 2 つの方法が失敗した場合にのみ行ってください。

事前に暗号化された Linux VHD を準備する

事前に暗号化された VHD の準備は、ディストリビューションによって異なる場合があります。 Ubuntu、openSUSE、および CentOS 7 の準備に関する例を利用できます。

次の手順に従って、ディストリビューションのインストール時に暗号化を構成します。

  1. ディスクをパーティション分割するときに [Configure encrypted volumes] を選択します。

    Ubuntu 16.04 のセットアップ - 暗号化するボリュームの構成

  2. 独立したブート ドライブを作成します。このドライブは暗号化しません。 ルート ドライブを暗号化します。

    Ubuntu 16.04 のセットアップ - 暗号化するデバイスの選択

  3. パスフレーズを指定します。 これは、キー コンテナーにアップロードしたパスフレーズです。

    Ubuntu 16.04 のセットアップ - パスフレーズの指定

  4. パーティション分割を終了します。

    Ubuntu 16.04 のセットアップ - パーティション分割の終了

  5. VM を起動し、パスフレーズの入力を求められたら、手順 3 で指定したパスフレーズを入力します。

    Ubuntu 16.04 のセットアップ - ブート時のパスフレーズ指定

  6. こちらの手順に従って、VM を Azure にアップロードするための準備をします。 最後の手順 (VM のプロビジョニング解除) はまだ実行しないでください。

次の手順を行って、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 の crypt 構成を変更します。 次のようになります。

     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. これで、VM をプロビジョニング解除できるようになります。

    Ubuntu 16.04 のセットアップ - update-initramfs

  7. 次の手順に進み、Azure にご利用の VHD をアップロードします。

暗号化された VHD を Azure ストレージ アカウントにアップロードする

DM-Crypt 暗号化を有効にした後、ローカル環境で暗号化された VHD をストレージ アカウントにアップロードする必要があります。

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

事前に暗号化された VM 用のシークレットをご自分のキー コンテナーにアップロードする

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 文字列としてエンコードされた後、キー コンテナーにアップロードされます。 また、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 コマンドレットを使用してシークレットとしてアップロードできます。

    # 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

KEK を使用して OS ディスクをアタッチする場合は、次の手順で $KeyEncryptionKey$secretUrl を使用します。

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