Bagikan melalui


Tutorial: Mengamankan Azure Remote Rendering dan penyimpanan model

Dalam tutorial ini, Anda akan mempelajari cara:

  • Azure Blob Storage aman yang berisi model Azure Remote Rendering
  • Mengautentikasi dengan ID Microsoft Entra untuk mengakses instans Azure Remote Rendering Anda
  • Menggunakan kredensial Azure untuk autentikasi Azure Remote Rendering

Prasyarat

Mengapa keamanan tambahan diperlukan

Status aplikasi saat ini dan aksesnya ke sumber daya Azure Anda terlihat seperti ini:

Initial security

Baik "AccountID + AccountKey" dan "URL + SAS Token" pada dasarnya menyimpan nama pengguna dan kata sandi bersama-sama. Misalnya, jika "AccountID + AccountKey" terekspos, akan sepele bagi penyerang untuk menggunakan sumber daya ARR Anda tanpa izin Anda dengan biaya Anda.

Mengamankan konten Anda di Azure Blob Storage

Azure Remote Rendering dapat dengan aman mengakses konten Azure Blob Storage Anda dengan konfigurasi yang benar. Lihat Cara Menggunakan: Menautkan akun penyimpanan untuk mengonfigurasi instans Azure Remote Rendering dengan akun penyimpanan blob Anda.

Saat menggunakan penyimpanan blob tertaut, Anda menggunakan metode yang sedikit berbeda untuk memuat model:

var loadModelParams = new LoadModelFromSasOptions(modelPath, modelEntity);
var task = ARRSessionService.CurrentActiveSession.Connection.LoadModelFromSasAsync(loadModelParams);

Baris di atas menggunakan versi FromSas dari param dan tindakan sesi. Mereka harus dikonversi ke versi non-SAS:

var loadModelParams = LoadModelOptions.CreateForBlobStorage(storageAccountPath, blobName, modelPath, modelEntity);
var task = ARRSessionService.CurrentActiveSession.Connection.LoadModelAsync(loadModelParams);

Mari kita modifikasi RemoteRenderingCoordinator untuk memuat model kustom, dari akun penyimpanan blob yang ditautkan.

  1. Jika Anda belum melakukannya, selesaikan cara: Tautkan akun penyimpanan untuk memberikan izin instans ARR Anda untuk mengakses instans Azure Blob Storage Anda.

  2. Tambahkan metode LoadModel yang dimodifikasi berikut ke RemoteRenderingCoordinator tepat di bawah metode LoadModel saat ini:

    /// <summary>
    /// Loads a model from blob storage that has been linked to the ARR instance
    /// </summary>
    /// <param name="storageAccountName">The storage account name, this contains the blob containers </param>
    /// <param name="blobName">The blob container name, i.e. arroutput</param>
    /// <param name="modelPath">The relative path inside the container to the model, i.e. test/MyCustomModel.arrAsset</param>
    /// <param name="parent">The parent Transform for this remote entity</param>
    /// <param name="progress">A call back method that accepts a float progress value [0->1]</param>
    /// <returns></returns>
    public async Task<Entity> LoadModel(string storageAccountName, string blobName, string modelPath, UnityEngine.Transform parent = null, Action<float> progress = null)
    {
        //Create a root object to parent a loaded model to
        var modelEntity = ARRSessionService.CurrentActiveSession.Connection.CreateEntity();
    
        //Get the game object representation of this entity
        var modelGameObject = modelEntity.GetOrCreateGameObject(UnityCreationMode.DoNotCreateUnityComponents);
    
        //Ensure the entity will sync its transform with the server
        var sync = modelGameObject.GetComponent<RemoteEntitySyncObject>();
        sync.SyncEveryFrame = true;
    
        //Parent the new object under the defined parent
        if (parent != null)
        {
            modelGameObject.transform.SetParent(parent, false);
            modelGameObject.name = parent.name + "_Entity";
        }
    
        //Load a model that will be parented to the entity
        var loadModelParams = LoadModelOptions.CreateForBlobStorage($"{storageAccountName}.blob.core.windows.net", blobName, modelPath, modelEntity);
        var loadModelAsync = ARRSessionService.CurrentActiveSession.Connection.LoadModelAsync(loadModelParams, progress);
        var result = await loadModelAsync;
        return modelEntity;
    }
    

    Kode ini identik dengan metode asli LoadModel , namun kami telah mengganti versi SAS dari panggilan metode dengan versi non-SAS.

    Input storageAccountName tambahan dan blobName juga telah ditambahkan ke argumen. Kami menyebut metode LoadModel baru ini dari metode lain yang mirip dengan metode LoadTestModel pertama yang kami buat di tutorial pertama.

  3. Tambahkan metode berikut ke RemoteRenderingCoordinator tepat setelah LoadTestModel

    private bool loadingLinkedCustomModel = false;
    
    [SerializeField]
    private string storageAccountName;
    public string StorageAccountName {
        get => storageAccountName.Trim();
        set => storageAccountName = value;
    }
    
    [SerializeField]
    private string blobContainerName;
    public string BlobContainerName {
        get => blobContainerName.Trim();
        set => blobContainerName = value;
    }
    
    [SerializeField]
    private string modelPath;
    public string ModelPath {
        get => modelPath.Trim();
        set => modelPath = value;
    }
    
    [ContextMenu("Load Linked Custom Model")]
    public async void LoadLinkedCustomModel()
    {
        if (CurrentCoordinatorState != RemoteRenderingState.RuntimeConnected)
        {
            Debug.LogError("Please wait for the runtime to connect before loading the test model. Try again later.");
            return;
        }
        if (loadingLinkedCustomModel)
        {
            Debug.Log("Linked Test model already loading or loaded!");
            return;
        }
        loadingLinkedCustomModel = true;
    
        // Create a parent object to use for positioning
        GameObject testParent = new GameObject("LinkedCustomModel");
        testParent.transform.position = new Vector3(0f, 0f, 3f);
    
        await LoadModel(StorageAccountName, BlobContainerName, ModelPath, testParent.transform, (progressValue) => Debug.Log($"Loading Test Model progress: {Math.Round(progressValue * 100, 2)}%"));
    }
    

    Kode ini menambahkan tiga variabel string tambahan ke komponen RemoteRenderingCoordinator Anda. Screenshot that highlights the Storage Account Name, Blob Container Name, and Model Path of the RemoteRenderingCoordinator component.

  4. Tambahkan nilai Anda ke komponen RemoteRenderingCoordinator. Setelah mengikuti Mulai cepat untuk konversi model, nilai Anda harus:

    • Nama Akun Penyimpanan: Nama akun penyimpanan Anda, nama unik global yang Anda pilih untuk akun penyimpanan Anda. Dalam mulai cepat ini adalah arrtutorialstorage, nilai Anda berbeda.
    • Nama Kontainer Blob: arroutput, Kontainer Penyimpanan Blob
    • Jalur Model: Kombinasi "outputFolderPath" dan "outputAssetFileName" yang didefinisikan dalam file arrconfig.json. Dalam mulai cepat, ini adalah "outputFolderPath":"converted/robot", "outputAssetFileName": "robot.arrAsset". Yang akan menghasilkan nilai Jalur Model dari "converted/robot/robot.arrAsset", nilai Anda berbeda.

    Tip

    Jika Anda menjalankan skrip Conversion.ps1, tanpa argumen "-UseContainerSas", skrip akan menampilkan semua nilai di atas untuk token SAS Anda, bukan token SAS. Linked Model

  5. Untuk saat ini, hapus atau nonaktifkan GameObject TestModel, untuk memberikan ruang bagi model kustom Anda untuk dimuat.

  6. Mainkan scene dan sambungkan ke sesi jarak jauh.

  7. Buka menu konteks di RemoteRenderingCoordinator dan pilih Muat Model Kustom Tertaut. Load linked model

Langkah-langkah ini telah meningkatkan keamanan aplikasi dengan menghapus token SAS dari aplikasi lokal.

Status aplikasi saat ini dan aksesnya ke sumber daya Azure Anda terlihat seperti ini:

Better security

Kami memiliki satu lagi "kata sandi", AccountKey, untuk dihapus dari aplikasi lokal. Ini dapat dilakukan menggunakan autentikasi Microsoft Entra.

Autentikasi Microsoft Entra

Autentikasi Microsoft Entra memungkinkan Anda menentukan individu atau grup mana yang menggunakan ARR dengan cara yang lebih terkontrol. ARR telah membangun dukungan untuk menerima Token Akses alih-alih menggunakan Kunci Akun. Anda dapat menganggap Token Akses sebagai kunci terbatas waktu dan spesifik pengguna, yang hanya membuka bagian tertentu dari sumber daya tertentu yang dimintanya.

Skrip RemoteRenderingCoordinator memiliki delegasi bernama ARRCredentialGetter, yang memegang metode yang mengembalikan objek SessionConfiguration, yang digunakan untuk mengonfigurasi manajemen sesi jarak jauh. Kita dapat menetapkan metode yang berbeda untuk ARRCredentialGetter, memungkinkan kita untuk menggunakan alur masuk Azure, menghasilkan objek SessionConfiguration yang berisi Token Akses Azure. Token Akses ini akan khusus untuk pengguna yang masuk.

  1. Ikuti Cara: Mengonfigurasi autentikasi - Autentikasi untuk aplikasi yang disebarkan, yang melibatkan pendaftaran aplikasi Microsoft Entra baru dan mengonfigurasi akses ke instans ARR Anda.

  2. Setelah mengonfigurasi aplikasi Microsoft Entra baru, periksa aplikasi Microsoft Entra Anda terlihat seperti gambar berikut:

    Aplikasi Microsoft Entra -> AutentikasiApp authentication

    Aplikasi Microsoft Entra -> Izin APIApp APIs

  3. Setelah mengonfigurasi akun Azure Remote Rendering, periksa konfigurasi Anda terlihat seperti gambar berikut:

    ARR -> AccessControl (IAM)ARR Role

    Catatan

    Peran Pemilik tidak cukup untuk mengelola sesi melalui aplikasi klien. Untuk setiap pengguna yang ingin Anda berikan kemampuan untuk mengelola sesi, Anda harus menyediakan peran Klien Remote Rendering. Untuk setiap pengguna yang ingin Anda kelola sesi dan mengonversi model, Anda harus menyediakan peran Administrator Remote Rendering.

Dengan sisi Azure hal-hal di tempat, kita sekarang perlu memodifikasi bagaimana kode Anda terhubung ke layanan ARR. Kami melakukannya dengan menerapkan instans BaseARRAuthentication, yang mengembalikan objek SessionConfiguration baru. Dalam hal ini, info akun dikonfigurasi dengan Token Akses Azure.

  1. Buat skrip baru bernama AADAuthentication dan ganti kodenya dengan yang berikut:

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License. See LICENSE in the project root for license information.
    
    using Microsoft.Azure.RemoteRendering;
    using Microsoft.Identity.Client;
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using UnityEngine;
    
    public class AADAuthentication : BaseARRAuthentication
    {
        [SerializeField]
        private string activeDirectoryApplicationClientID;
        public string ActiveDirectoryApplicationClientID
        {
            get => activeDirectoryApplicationClientID.Trim();
            set => activeDirectoryApplicationClientID = value;
        }
    
        [SerializeField]
        private string azureTenantID;
        public string AzureTenantID
        {
            get => azureTenantID.Trim();
            set => azureTenantID = value;
        }
    
        [SerializeField]
        private string azureRemoteRenderingDomain;
        public string AzureRemoteRenderingDomain
        {
            get => azureRemoteRenderingDomain.Trim();
            set => azureRemoteRenderingDomain = value;
        }
    
        [SerializeField]
        private string azureRemoteRenderingAccountID;
        public string AzureRemoteRenderingAccountID
        {
            get => azureRemoteRenderingAccountID.Trim();
            set => azureRemoteRenderingAccountID = value;
        }
    
        [SerializeField]
        private string azureRemoteRenderingAccountDomain;
        public string AzureRemoteRenderingAccountDomain
        {
            get => azureRemoteRenderingAccountDomain.Trim();
            set => azureRemoteRenderingAccountDomain = value;
        }    
    
        public override event Action<string> AuthenticationInstructions;
    
        string authority => "https://login.microsoftonline.com/" + AzureTenantID;
    
        string redirect_uri = "https://login.microsoftonline.com/common/oauth2/nativeclient";
    
        string[] scopes => new string[] { "https://sts.mixedreality.azure.com//.default" };
    
        public void OnEnable()
        {
            RemoteRenderingCoordinator.ARRCredentialGetter = GetARRCredentials;
            this.gameObject.AddComponent<ExecuteOnUnityThread>();
        }
    
        public async override Task<SessionConfiguration> GetARRCredentials()
        {
            var result = await TryLogin();
            if (result != null)
            {
                Debug.Log("Account signin successful " + result.Account.Username);
    
                var AD_Token = result.AccessToken;
    
                return await Task.FromResult(new SessionConfiguration(AzureRemoteRenderingAccountDomain, AzureRemoteRenderingDomain, AzureRemoteRenderingAccountID, "", AD_Token, ""));
            }
            else
            {
                Debug.LogError("Error logging in");
            }
            return default;
        }
    
        private Task DeviceCodeReturned(DeviceCodeResult deviceCodeDetails)
        {
            //Since everything in this task can happen on a different thread, invoke responses on the main Unity thread
            ExecuteOnUnityThread.Enqueue(() =>
            {
                // Display instructions to the user for how to authenticate in the browser
                Debug.Log(deviceCodeDetails.Message);
                AuthenticationInstructions?.Invoke(deviceCodeDetails.Message);
            });
    
            return Task.FromResult(0);
        }
    
        public override async Task<AuthenticationResult> TryLogin()
        {
            var clientApplication = PublicClientApplicationBuilder.Create(ActiveDirectoryApplicationClientID).WithAuthority(authority).WithRedirectUri(redirect_uri).Build();
            AuthenticationResult result = null;
            try
            {
                var accounts = await clientApplication.GetAccountsAsync();
    
                if (accounts.Any())
                {
                    result = await clientApplication.AcquireTokenSilent(scopes, accounts.First()).ExecuteAsync();
    
                    return result;
                }
                else
                {
                    try
                    {
                        result = await clientApplication.AcquireTokenWithDeviceCode(scopes, DeviceCodeReturned).ExecuteAsync(CancellationToken.None);
                        return result;
                    }
                    catch (MsalUiRequiredException ex)
                    {
                        Debug.LogError("MsalUiRequiredException");
                        Debug.LogException(ex);
                    }
                    catch (MsalServiceException ex)
                    {
                        Debug.LogError("MsalServiceException");
                        Debug.LogException(ex);
                    }
                    catch (MsalClientException ex)
                    {
                        Debug.LogError("MsalClientException");
                        Debug.LogException(ex);
                        // Mitigation: Use interactive authentication
                    }
                    catch (Exception ex)
                    {
                        Debug.LogError("Exception");
                        Debug.LogException(ex);
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.LogError("GetAccountsAsync");
                Debug.LogException(ex);
            }
    
            return null;
        }
    }
    

Catatan

Kode ini sama sekali tidak lengkap dan tidak siap untuk aplikasi komersial. Misalnya, minimal Anda mungkin ingin menambahkan kemampuan untuk keluar juga. Ini dapat dilakukan menggunakan metode Task RemoveAsync(IAccount account) yang disediakan oleh aplikasi klien. Kode ini hanya ditujukan untuk penggunaan tutorial, implementasi Anda akan spesifik untuk aplikasi Anda.

Kode pertama mencoba untuk mendapatkan token diam-diam menggunakan AquireTokenSilent. Ini berhasil jika pengguna sebelumnya telah mengautentikasi aplikasi ini. Jika tidak berhasil, beralihlah ke strategi yang lebih melibatkan pengguna.

Untuk kode ini, kami menggunakan alur kode perangkat untuk mendapatkan Token Akses. Alur ini memungkinkan pengguna untuk masuk ke akun Azure mereka di komputer atau perangkat seluler dan memiliki token yang dihasilkan dikirim kembali ke aplikasi HoloLens.

Bagian terpenting dari kelas ini dari perspektif ARR adalah baris ini:

return await Task.FromResult(new SessionConfiguration(AzureRemoteRenderingAccountDomain, AzureRemoteRenderingDomain, AzureRemoteRenderingAccountID, "", AD_Token, ""));

Di sini, kami membuat objek SessionConfiguration baru menggunakan domain penyajian jarak jauh, ID akun, domain akun, dan token akses. Token ini kemudian digunakan oleh layanan ARR untuk meng-kueri, membuat, dan menggabungkan sesi penyajian jarak jauh selama pengguna diotorisasi berdasarkan izin berbasis peran yang dikonfigurasi sebelumnya.

Status aplikasi saat ini dan aksesnya ke sumber daya Azure Anda terlihat seperti ini:

Even better security

Karena Kredensial Pengguna tidak disimpan di perangkat (atau dalam hal ini bahkan dimasukkan pada perangkat), risiko paparan mereka rendah. Sekarang perangkat menggunakan Token Akses khusus pengguna dan terbatas waktu untuk mengakses ARR, yang menggunakan kontrol akses (IAM) untuk mengakses Azure Blob Storage. Kedua langkah ini telah menghapus "kata sandi" dari kode sumber dan meningkatkan keamanan secara besar-besaran. Namun, ini bukan keamanan yang paling tersedia, memindahkan model dan manajemen sesi ke layanan web akan meningkatkan keamanan lebih lanjut. Pertimbangan keamanan ekstra dibahas dalam bab Kesiapan Komersial.

Menguji autentikasi Microsoft Entra

Di Editor Unity, ketika Microsoft Entra auth aktif, Anda perlu mengautentikasi setiap kali Anda meluncurkan aplikasi. Pada perangkat, langkah autentikasi terjadi pertama kali dan hanya diperlukan lagi ketika token kedaluwarsa atau tidak valid.

  1. Tambahkan komponen autentikasi Microsoft Entra ke RemoteRenderingCoordinator GameObject.

    Microsoft Entra auth component

Catatan

Jika Anda menggunakan proyek yang telah selesai dari repositori sampel ARR, pastikan untuk mengaktifkan komponen autentikasi Microsoft Entra dengan mengklik kotak centang di samping judulnya.

  1. Isi nilai Anda untuk ID Klien dan ID Penyewa. Nilai-nilai ini dapat ditemukan di Halaman Gambaran Umum Pendaftaran Aplikasi Anda:

    • ID Klien Aplikasi Direktori Aktif adalah ID Aplikasi (klien) yang ditemukan di pendaftaran aplikasi Microsoft Entra Anda (lihat gambar di bawah).
    • ID Penyewa Azure adalah ID Direktori (penyewa) yang ditemukan di pendaftaran aplikasi Microsoft Entra Anda (lihat gambar di bawah).
    • Azure Remote Rendering Domain adalah domain yang sama dengan yang pernah Anda gunakan di Remote Rendering Domain RemoteRenderingCoordinator.
    • ID Akun Azure Remote Rendering adalah ID Akun yang sama dengan yang telah Anda gunakan untuk RemoteRenderingCoordinator.
    • Domain Akun Azure Remote Rendering adalah Domain Akun yang sama dengan yang pernah Anda gunakan di RemoteRenderingCoordinator.

    Screenshot that highlights the Application (client) ID and Directory (tenant) ID.

  2. Tekan Putar di Editor Unity dan setuju untuk menjalankan sesi. Karena komponen autentikasi Microsoft Entra memiliki pengontrol tampilan, komponen tersebut secara otomatis terhubung untuk menampilkan perintah setelah panel modal otorisasi sesi.

  3. Ikuti instruksi yang ditemukan di panel di sebelah kanan AppMenu. Anda akan melihat sesuatu yang mirip dengan ini: Illustration that shows the instruction panel that appears to the right of the AppMenu.

    Setelah memasukkan kode yang disediakan di perangkat sekunder Anda (atau browser pada perangkat yang sama) dan masuk menggunakan kredensial Anda, Token Akses akan dikembalikan ke aplikasi yang meminta, dalam hal ini, Editor Unity.

Setelah titik ini, semua yang ada dalam aplikasi harus dilanjutkan secara normal. Periksa Konsol Unity untuk setiap kesalahan jika Anda tidak mengalami tahapan seperti yang diharapkan.

Buat ke perangkat

Jika Anda membuat aplikasi menggunakan MSAL ke perangkat, Anda perlu menyertakan file di folder Aset proyek Anda. Ini membantu kompilator membangun aplikasi dengan benar menggunakan Microsoft.Identity.Client.dll yang disertakan dalam Aset Tutorial.

  1. Tambahkan file baru di Aset bernama link.xml

  2. Tambahkan HTML berikut ke file:

    <linker>
        <assembly fullname="Microsoft.Identity.Client" preserve="all"/>
        <assembly fullname="System.Runtime.Serialization" preserve="all"/>
        <assembly fullname="System.Core">
            <type fullname="System.Linq.Expressions.Interpreter.LightLambda" preserve="all" />
        </assembly>
    </linker>
    
  3. Simpan perubahan

Ikuti langkah-langkah yang ditemukan di Mulai cepat: Terapkan sampel Unity ke HoloLens - Bangun proyek sampel, untuk membangun ke HoloLens.

Langkah berikutnya

Sisa set tutorial ini berisi artikel konseptual untuk membuat aplikasi siap produksi yang menggunakan Azure Remote Rendering.