.NETCore5.0-SQLAzure+;始终加密+;托管标识
我有一个带有加密列的Azure SQL Db(始终使用Azure KeyVault加密)。我可以从SSMS访问这个数据库,我可以看到解密的数据 我还有一个用.Net Core 5.0制作的web应用程序,它被部署到Azure应用程序服务中。应用程序服务已启用托管标识,并且具有该SQL Db的enc/dec密钥的密钥库具有访问策略设置,以允许此应用程序服务解密数据 该web应用程序与托管标识一起工作,因为我可以看到,检索未加密的数据时不会出现任何问题 此外,连接字符串不包括.NETCore5.0-SQLAzure+;始终加密+;托管标识,azure,.net-core,azure-sql-database,azure-keyvault,always-encrypted,Azure,.net Core,Azure Sql Database,Azure Keyvault,Always Encrypted,我有一个带有加密列的Azure SQL Db(始终使用Azure KeyVault加密)。我可以从SSMS访问这个数据库,我可以看到解密的数据 我还有一个用.Net Core 5.0制作的web应用程序,它被部署到Azure应用程序服务中。应用程序服务已启用托管标识,并且具有该SQL Db的enc/dec密钥的密钥库具有访问策略设置,以允许此应用程序服务解密数据 该web应用程序与托管标识一起工作,因为我可以看到,检索未加密的数据时不会出现任何问题 此外,连接字符串不包括列加密设置=已启用。以下
列加密设置=已启用代码>。以下是连接字符串:
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;
}
}
内部静态类AzureSqlConnection
{
私有静态布尔值初始化;
私有静态void InitKeyVaultProvider(ILogger记录器)
{
/*
*从这里-https://github.com/dotnet/SqlClient/blob/master/release-notes/add-ons/AzureKeyVaultProvider/1.2/1.2.0.md
*及-https://github.com/dotnet/SqlClient/blob/master/doc/samples/AzureKeyVaultProviderExample.cs
*
*/
尝试
{
//初始化AKV提供程序
SqlColumnEncryptionAzureKeyVaultProvider SqlColumnCryptionAzureKeyVaultProvider=
新的SqlColumnEncryptionAzureKeyVaultProvider(AzureActiveDirectoryAuthenticationCallback);
//注册AKV提供者
SqlConnection.RegisterColumnCryptionKeyStoreProviders(
新字典(1,StringComparer.OrdinalIgnoreCase)
{
{SqlColumnEncryptionAzureKeyVaultProvider.ProviderName,SqlColumnEncryptionAzureKeyVaultProvider}
});
_isInitialized=true;
}
捕获(例外情况除外)
{
logger.LogError(例如,“无法注册SqlColumnEncryptionAzureKeyVaultProvider”);
投掷;
}
}
内部静态异步任务GetSqlConnection(字符串连接字符串、ILogger记录器)
{
如果(!\u已初始化)初始化KeyVault提供程序(记录器);
尝试
{
SqlConnection conn=新的SqlConnection(connectionString);
/*
*这是托管标识(不总是加密)
* https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi#modify-aspnet核心
*
*/
#如果!调试
conn.AccessToken=等待新的AzureServiceTokenProvider()。GetAccessTokenAsync(“https://database.windows.net/");
logger.LogInformation($“令牌:{conn.AccessToken}”);
#恩迪夫
等待连接OpenAsync();
返回连接;
}
捕获(例外情况除外)
{
logger.LogError(例如,“无法建立到SQL Server的连接”);
投掷;
}
}
专用静态异步任务AzureActiveDirectoryAuthenticationCallback(字符串权限、字符串资源、字符串范围)
{
返回等待新AzureServiceTokenProvider()。GetAccessTokenAsync(“https://database.windows.net/");
//AuthenticationContext?authContext=新的AuthenticationContext(授权);
//ClientCredential clientCred=新的ClientCredential(s_clientId,s_clientSecret);
//AuthenticationResult=等待authContext.AcquireTokenAsync(资源,clientCred);
//如果(结果==null)
//{
//抛出新的InvalidOperationException($“检索{resource}的访问令牌失败”);
//}
//返回result.AccessToken;
}
}
这段代码不会抛出任何异常,它适用于非加密查询。但对于加密查询,我会得到以下错误:
未能解密列加密密钥。密钥存储提供程序名称无效:“AZURE\u密钥库”。密钥存储提供程序名称必须表示系统密钥存储提供程序或已注册的自定义密钥存储提供程序。有效的系统密钥存储提供程序名称为:“MSSQL\U证书存储”、“MSSQL\U CNG\U存储”、“MSSQL\U CSP\U提供程序”。有效(当前已注册)的自定义密钥存储提供程序名称为:。请验证数据库中“主密钥定义”列中的密钥存储提供程序信息,并验证应用程序中使用的所有自定义密钥存储提供程序都已正确注册。未能解密列加密密钥。密钥存储提供程序名称无效:“AZURE\u密钥库”。密钥存储提供程序名称必须表示系统密钥存储提供程序或已注册的自定义密钥存储提供程序。有效的系统密钥存储提供程序名称为:“MSSQL\U证书存储”、“MSSQL\U CNG\U存储”、“MSSQL\U CSP\U提供程序”。有效(当前已注册)的自定义密钥存储提供程序名称为:。请验证数据库中“主密钥定义”列中的密钥存储提供程序信息,并验证应用程序中使用的所有自定义密钥存储提供程序都已正确注册
密钥库提供程序似乎未注册
我应该怎么做才能查询加密数据
使用的软件包
事实证明,当使用MSI时,无法读取.NET 5中的解密数据。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);
}
公共静态异步任务KeyVaultAuthenticationCallback(字符串权限、字符串资源、字符串s
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);
}
private static async Task<string> AzureActiveDirectoryAuthenticationCallback(string authority, string resource, string scope)
{
return await Task.Run(() => new ManagedIdentityCredential().GetToken(new TokenRequestContext(new string [] {"https://vault.azure.net/.default"})).Token);
}
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new DefaultAzureCredential());
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> providers = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>
{
{ SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider }
};
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);