.Net Core 5.0 - Sql Azure + เข้ารหัสเสมอ + Managed Identity

Dec 11 2020

ฉันมี Azure SQL Db พร้อมคอลัมน์ที่เข้ารหัส (เข้ารหัสด้วย Azure KeyVault เสมอ) ฉันสามารถเข้าถึงฐานข้อมูลนี้จาก SSMS และฉันสามารถดูข้อมูลที่ถอดรหัสได้

ฉันยังมีเว็บแอปที่สร้างด้วย. Net Core 5.0 ซึ่งปรับใช้กับ Azure App Service บริการแอปได้เปิดใช้งาน Managed Identity และ Key Vault ที่มี enc / dec คีย์สำหรับ SQL Db นั้นมีการตั้งค่านโยบายการเข้าถึงเพื่ออนุญาตให้บริการแอปนี้ถอดรหัสข้อมูล

เว็บแอปทำงานร่วมกับข้อมูลประจำตัวที่มีการจัดการเนื่องจากฉันเห็นว่าข้อมูลที่ไม่เข้ารหัสจะถูกดึงมาโดยไม่มีปัญหาใด ๆ

Column Encryption Setting=enabled;นอกจากนี้ยังมีสายเชื่อมต่อไม่รวมถึง นี่คือสตริงการเชื่อมต่อ:

Server=tcp:server.database.windows.net,1433;Database=somedb;Column Encryption Setting=enabled;

ปัญหาคือฉันไม่พบตัวอย่างใด ๆ ที่มีการตั้งค่าประเภทนี้ SqlColumnEncryptionAzureKeyVaultProviderผมพบว่าบางอย่างและฉันเข้าใจว่าฉันจำเป็นต้องลงทะเบียน นี่คือรหัสของฉันเพื่อรับ SqlConnection:

    internal static class AzureSqlConnection
    {
        private static bool _isInitialized;

        private static void InitKeyVaultProvider(ILogger logger)
        {
            /*
             * from here - https://github.com/dotnet/SqlClient/blob/master/release-notes/add-ons/AzureKeyVaultProvider/1.2/1.2.0.md
             *      and  - https://github.com/dotnet/SqlClient/blob/master/doc/samples/AzureKeyVaultProviderExample.cs
             *
             */

            try
            {
                // Initialize AKV provider
                SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider =
                    new SqlColumnEncryptionAzureKeyVaultProvider(AzureActiveDirectoryAuthenticationCallback);

                // Register AKV provider
                SqlConnection.RegisterColumnEncryptionKeyStoreProviders(
                    new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>(1, StringComparer.OrdinalIgnoreCase)
                    {
                        {SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, sqlColumnEncryptionAzureKeyVaultProvider}
                    });

                _isInitialized = true;
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Could not register SqlColumnEncryptionAzureKeyVaultProvider");
                throw;
            }
        }

        internal static async Task<SqlConnection> GetSqlConnection(string connectionString, ILogger logger)
        {
            if (!_isInitialized) InitKeyVaultProvider(logger);

            try
            {
                SqlConnection conn = new SqlConnection(connectionString);
                /*
                         * This is Managed Identity (not Always Encrypted)
                         *  https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi#modify-aspnet-core
                         *
                         */
#if !DEBUG
                conn.AccessToken = await new AzureServiceTokenProvider().GetAccessTokenAsync("https://database.windows.net/");
                logger.LogInformation($"token: {conn.AccessToken}"); #endif await conn.OpenAsync(); return conn; } catch (Exception ex) { logger.LogError(ex, "Could not establish a connection to SQL Server"); throw; } } private static async Task<string> AzureActiveDirectoryAuthenticationCallback(string authority, string resource, string scope) { return await new AzureServiceTokenProvider().GetAccessTokenAsync("https://database.windows.net/"); //AuthenticationContext? authContext = new AuthenticationContext(authority); //ClientCredential clientCred = new ClientCredential(s_clientId, s_clientSecret); //AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred); //if (result == null) //{ // throw new InvalidOperationException($"Failed to retrieve an access token for {resource}");
            //}

            //return result.AccessToken;
        }
    }

รหัสนี้ไม่มีข้อยกเว้นใด ๆ และใช้ได้กับการสืบค้นที่ไม่เข้ารหัส แต่สำหรับข้อความค้นหาที่เข้ารหัสฉันได้รับข้อผิดพลาดต่อไปนี้:

ถอดรหัสคีย์เข้ารหัสคอลัมน์ไม่สำเร็จ ชื่อผู้ให้บริการที่เก็บคีย์ไม่ถูกต้อง: 'AZURE_KEY_VAULT' ชื่อผู้ให้บริการที่เก็บคีย์ต้องแสดงถึงผู้ให้บริการที่เก็บคีย์ระบบหรือผู้ให้บริการที่เก็บคีย์แบบกำหนดเองที่ลงทะเบียน ชื่อผู้ให้บริการที่เก็บคีย์ระบบที่ถูกต้องคือ: 'MSSQL_CERTIFICATE_STORE', 'MSSQL_CNG_STORE', 'MSSQL_CSP_PROVIDER' ชื่อผู้ให้บริการที่เก็บคีย์แบบกำหนดเองที่ถูกต้อง (จดทะเบียนในปัจจุบัน) คือ: โปรดตรวจสอบข้อมูลผู้ให้บริการที่เก็บคีย์ในคำจำกัดความของคีย์หลักของคอลัมน์ในฐานข้อมูลและตรวจสอบว่าผู้ให้บริการที่เก็บคีย์แบบกำหนดเองทั้งหมดที่ใช้ในแอปพลิเคชันของคุณได้รับการลงทะเบียนอย่างถูกต้อง ถอดรหัสคีย์เข้ารหัสคอลัมน์ไม่สำเร็จ ชื่อผู้ให้บริการที่เก็บคีย์ไม่ถูกต้อง: 'AZURE_KEY_VAULT' ชื่อผู้ให้บริการที่เก็บคีย์ต้องแสดงถึงผู้ให้บริการที่เก็บคีย์ระบบหรือผู้ให้บริการที่เก็บคีย์แบบกำหนดเองที่ลงทะเบียนชื่อผู้ให้บริการที่เก็บคีย์ระบบที่ถูกต้องคือ: 'MSSQL_CERTIFICATE_STORE', 'MSSQL_CNG_STORE', 'MSSQL_CSP_PROVIDER' ชื่อผู้ให้บริการที่เก็บคีย์แบบกำหนดเองที่ถูกต้อง (จดทะเบียนในปัจจุบัน) คือ: โปรดตรวจสอบข้อมูลผู้ให้บริการที่เก็บคีย์ในคำจำกัดความของคีย์หลักของคอลัมน์ในฐานข้อมูลและตรวจสอบว่าผู้ให้บริการที่เก็บคีย์แบบกำหนดเองทั้งหมดที่ใช้ในแอปพลิเคชันของคุณได้รับการลงทะเบียนอย่างถูกต้อง

ดูเหมือนว่าผู้ให้บริการ key vault ไม่ได้ลงทะเบียน

ฉันควรทำอย่างไรเพื่อให้สามารถค้นหาข้อมูลที่เข้ารหัสได้

แพ็คเกจที่ใช้

    <PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.6.0" />
    <PackageReference Include="Microsoft.Data.SqlClient" Version="2.1.0" />
    <PackageReference Include="Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider" Version="1.2.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />

คำตอบ

2 alvipeo Jan 25 2021 at 23:15

ปรากฎว่าเป็นไปไม่ได้ที่จะอ่านข้อมูลที่ถอดรหัสใน. NET 5 เมื่อใช้ MSI มีข้อบกพร่องในแพ็คเกจ MS และบริการแอปไม่ได้รับอนุญาต

คุณต้องใช้บริการหลัก งานนี้เหมือนมีเสน่ห์!

อัปเดต

ต้องขอขอบคุณวิศวกร MS ที่เสนอวิธีแก้ปัญหาในการทำงาน:

public static async Task<string> KeyVaultAuthenticationCallback(string authority, string resource, string scope)
{
     return await Task.Run(() => new ManagedIdentityCredential().GetToken(new TokenRequestContext(new string [] {"https://vault.azure.net/.default"})).Token);
     /********************** Alternatively, to use User Assigned Managed Identity ****************/
     // var clientId = {clientId_of_UserAssigned_Identity};
     // return await Task.Run(() => new ManagedIdentityCredential(clientId).GetToken(new TokenRequestContext(new string [] {"https://vault.azure.net/.default"})).Token);
}
SpinDoctor Apr 10 2021 at 04:19

ฉันสามารถใช้รหัสนี้ที่ใช้ให้ TokenCredential กับผู้ให้บริการ SqlColumnEncryption DefaultAzureCredential ส่งคืนข้อมูลประจำตัวที่มีการจัดการเมื่อปรับใช้เป็น App Service:

            SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new DefaultAzureCredential());
            Dictionary<string, SqlColumnEncryptionKeyStoreProvider> providers = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>
            {
                { SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider }
            };
            SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);

เรียกมันจากการเริ่มต้นของคุณกำหนดค่าวิธีการ