.Net Core 5.0-Sql Azure +常に暗号化+マネージドID

Dec 11 2020

暗号化された列を持つAzureSQL Dbがあります(常にAzure KeyVaultで暗号化されています)。SSMSからこのデータベースにアクセスでき、復号化されたデータを確認できます。

Azure AppServiceにデプロイされた.NetCore5.0で作成されたWebアプリもあります。アプリサービスではManagedIdentityがオンになっており、そのSQLDbのenc / decキーを持つKeyVaultには、このアプリサービスがデータを復号化できるようにするアクセスポリシー設定があります。

暗号化されていないデータが問題なく取得されていることがわかるので、WebアプリはマネージドIDで動作します。

また、接続文字列にはが含まれます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」です。有効な(現在登録されている)カスタムキーストアプロバイダー名は次のとおりです。データベースの列マスターキー定義のキーストアプロバイダー情報を確認し、アプリケーションで使用されるすべてのカスタムキーストアプロバイダーが正しく登録されていることを確認してください。

キーボールトプロバイダーが登録されていないようです。

暗号化されたデータのクエリを機能させるにはどうすればよいですか?

使用したパッケージ

    <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

MSIが使用されている場合、.NET5で復号化されたデータを読み取ることは不可能であることが判明しました。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

SqlColumnEncryptionプロバイダーにTokenCredentialを提供するを使用するこのコードを使用することができました。DefaultAzureCredentialは、App Serviceとしてデプロイされると、マネージIDを返します。

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

スタートアップから呼び出します。Configureメソッド。