.Net Core 5.0 - Sql Azure + เข้ารหัสเสมอ + Managed Identity
ฉันมี 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" />
คำตอบ
ปรากฎว่าเป็นไปไม่ได้ที่จะอ่านข้อมูลที่ถอดรหัสใน. 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);
}
ฉันสามารถใช้รหัสนี้ที่ใช้ให้ 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);
เรียกมันจากการเริ่มต้นของคุณกำหนดค่าวิธีการ