Migrating Data from a SQL Server Encrypted Table to SQL Azure using Azure Data Factory Copy data - sql-server

I am having difficulties with Azure Data Factory migrating data from an encrypted table. I was wondering what I have missed as I can't find a way to attach a certificate in the pipeline to extract the data.
I have a Link Service connection that connects successfully, but I am guessing it is possibly here that the certificate needs to be added for the decrypting on the data.
In 'Copy Data' the Source dataset, the Linked service connects to the database fine. But the Table, preview data Fails.
I get a 22301 error. The detail is as follows:
A database operation failed with the following error:
Failed to decrypt column ...
Failed to decrypt a column encryption key using key store provider: 'MSSQL_CERTIFICATE_STORE'. The last 10 bytes of the encrypted column encryption key are: '...'.
Certificate with thumbprint '...' not found in certificate store 'My' in certificate location 'CurrentUser'. Verify the certificate path in the column master key definition in the database is correct, and the certificate has been imported correctly into the certificate location/store.
Parameter name: masterKeyPath
Failed to decrypt column ...
Failed to decrypt a column encryption key using key store provider: 'MSSQL_CERTIFICATE_STORE'. The last 10 bytes of the encrypted column encryption key are: '...'.
Certificate with thumbprint '...' not found in certificate store 'My' in certificate location 'CurrentUser'. Verify the certificate path in the column master key definition in the database is correct, and the certificate has been imported correctly into the certificate location/store.
Parameter name: masterKeyPath, SqlErrorNumber=0,Class=11,State=0,
Certificate with thumbprint '...' not found in certificate store 'My' in certificate location 'CurrentUser'. Verify the certificate path in the column master key definition in the database is correct, and the certificate has been imported correctly into the certificate location/store.
Parameter name: masterKeyPath
Activity ID: ...
I have no idea what this means, is there someone who can explain what the problem is and how I can rectify this I would be extremely grateful.
What I am trying to achieve, with very little success is to migrate the data from the encrypted data table in one database unencrypted to another. I want to use an Azure Data factory pipeline and make redundant SSIS.
Many thanks
I have tried using the solution, however I am now getting this error.
Error 2200.
User configuration issue
Failure happened on 'Source' side.
ErrorCode=SqlOperationFailed,'Type=Microsoft.DataTransfer.Common.Shared.HybridDeliveryException,Message=A database operation failed with the following error: 'Failed to decrypt column 'Firstname'.
Failed to decrypt a column encryption key using key store provider: 'AZURE_KEY_VAULT'. Verify the properties of the column encryption key and its column master key in your database. The last 10 bytes of the encrypted column encryption key are: '##-##-##-##-##-##-##-##-##-##'.
Could not find any resources appropriate for the specified culture or the neutral culture.
Make sure "Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider.Strings.resources" was correctly embedded or linked into assembly "Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider" at compile time, or that all the satellite assemblies required are loadable and fully signed.',Source=,''Type=System.Data.SqlClient.SqlException,Message=Failed to decrypt column 'Firstname'.
Failed to decrypt a column encryption key using key store provider: 'AZURE_KEY_VAULT'. Verify the properties of the column encryption key and its column master key in your database. The last 10 bytes of the encrypted column encryption key are: '##-##-##-##-##-##-##-##-##-##'.
Could not find any resources appropriate for the specified culture or the neutral culture.
Make sure "Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider.Strings.resources" was correctly embedded or linked into assembly "Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider" at compile time, or that all the satellite assemblies required are loadable and fully signed.,Source=.Net SqlClient Data Provider,SqlErrorNumber=0,Class=11,ErrorCode=-2146232060,State=0,Errors=[{Class=11,Number=0,State=0,Message=Failed to decrypt column 'Firstname'.,},{Class=11,Number=0,State=0,Message=Failed to decrypt a column encryption key using key store provider: 'AZURE_KEY_VAULT'. Verify the properties of the column encryption key and its column master key in your database.
The last 10 bytes of the encrypted column encryption key are: 'AE-1D-E5-C1-60-F0-2F-42-3C-C1'.,},{Class=11,Number=0,State=0,Message=Could not find any resources appropriate for the specified culture or the neutral culture.
Make sure "Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider.Strings.resources" was correctly embedded or linked into assembly "Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider" at compile time, or that all the satellite assemblies required are loadable and fully signed.,},],''Type=System.Resources.MissingManifestResourceException,Message=Could not find any resources appropriate for the specified culture or the neutral culture.
Make sure "Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider.Strings.resources" was correctly embedded or linked into assembly "Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider" at compile time, or that all the satellite assemblies required are loadable and fully signed.,Source=mscorlib,'
I'm really not sure what that all means, and from constant searching I have no solution to the problem. Why is this made so difficult, surely its just a handshake. It is very frustrating, I'm going to have to write a blog after I find the solution, I can't find anyone that has come across this issue before that wants to write about it.
Here is the setting up of ADF...
The Source SetUp
Fails to read the table data, Fails with Error 22301
SSMS Keys for Encryption
Master Key
Column Key
Key in Azure Key Vault
Link Service for Azure SQL Database
Link Service for SQL Server Database the encrypted data is here. It is supplied by a third party, i have no control over this.
The encrypted data is in the SQL Server Database, I want to decrypt this and save it to a table in my Azure SQL Database.
The columns are encrypted like so:
[Firstname] nvarchar COLLATE Danish_Norwegian_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [ColumnEncryptionKey], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL,

To transfer Encrypted data from data factory you have to use the Azure key vault:
Open the SQL Server Management Studio and connect with the server.
Expand Database >> security >> Always Encrypted keys >> New Column master key.
Give the master key a name, Choose the Azure Key Vault as your key storage location, login into your account, choose your Azure subscription, choose the Azure key vault, generate the key, and then click "ok."
Expand Database >> security >> Always Encrypted keys >> New Column Encryption key.
Name your column encryption key, choose the master key and click on ok.
Encrypt columns
To Encrypt a column or columns, right-click on the Table, click on "Encrypt Columns" and select single or multiple columns as per your requirement to encrypt.
Access policies
To add an access policy, open your Azure portal, navigate to the Azure key vault, select the settings tab's access policies link, and then click + Add access policy. Select the principal, which is your Azure data factory name, before choosing the important rights. Click on Add after selecting Secret Permissions, followed by Certificate Permissions.
linked service configuration
Create linked service, Name linked service, select Azure subscription, select the server name, select the database name, select the authentication type, provide the user name and password, select always encrypted select keystore authentication type as System Assigned Managed Identity and then click ok create.
Create pipeline select source and sink and run the pipeline
Reference: Using Always Encrypted

Related

Failed to decrypt a column encryption key using key store provider: 'AZURE_KEY_VAULT'

I've used Always encrypted for a database table column on a DB on Azure. I've gone through this article - https://learn.microsoft.com/en-us/azure/sql-database/sql-database-always-encrypted-azure-key-vault - followed it very carefully. I have encrypted the columns, and that was done successfully. I can see that the column is encrypted.
When I try to follow the same article to now try to view the data from an application, I get error stating:
Failed to decrypt a column encryption key using key store provider:
'AZURE_KEY_VAULT'. Verify the properties of the column encryption key
and its column master key in your database. The last 10 bytes of the
encrypted column encryption key are: '54-36-01-E0-5C-A1-82-80-B1-B4'.
This is the error in the code, but then after I let that error go, I get:
Access denied. Caller was not found on any access policy. Caller:
appid=afd26169-bbac-4a45-ad3c-2b4492d19c6e;oid=dabbc750-5601-442b-9809-3a17f74d5aa2;numgroups=0;iss=https://sts.windows.net/bd8eb048-c497-4576-80eb-99e763b83ffd/
Vault: AWKeyVault2;location=eastus2
It's worth noting that when I use SSMS, and I set the connection string options to Column Encryption Setting=Enabled, I can see the decrypted data in SSMS.
For the most part, I think it's a permissions problem, but I'm at a loss. I've given the App Registration full access to the Azure Subscription. I've generated a 'Secret' for the App Registration also, and using that in the application. If I can see the data from SSMS, I think it means the encryption was successful, so it must be something to do with the fact that the application just cannot get to the key in the azure key vault. What am I missing?
OK, so figured this out. It definitely was a permissions thing. In order to completely verify that you have the correct permissions, go to Key Vault Blade:
Select Access Policies from the Key Vault resource blade menu on theleft
Click the "add new" link/button at the top
Select Principal to select the application that you are using (i.e. the app registration from which you got the client ID from)
From the Key permissions drop down, make sure you give it "Decrypt", "Sign", "Get", "UnwrapKey" permissions
Make sure to save changes
This is one of the last things - you still have to make sure your app registration has the correct permissions for your subscription.
Maybe a little late to the party, but I recently publihed an article about the topic and it might help better: https://www.codeproject.com/Articles/5355073/Full-Tutorial-on-using-Always-Encrypted-with-Azure
Basically, there is a mix of settings and coding that will allow you to use Always Encrypted with Azure Key Vault and it is not only related Azure settings and permissions.
You need to register your Web App in Azure Active Directory, take the according Application ID, then create a new Secret for it, take the Secret value - then write some code to authenticate to AKV using these two.
But that is also with a bit of skepsis - please read the article.

Always encrypted database

We need to configure Always Encrypted feature for all databases. We wanted to create common Column Master Key in Master database so that we can link CMK to all databases on server. But we are not able to link CMK created in master DB to all databases. We need to create individually create master key in each database. Is there any way to create a CMK in master database and refer to all databases on the server.
Column Master Key is per-database object, i.e. you can't share it between databases. However, it is nothing more than metadata, i.e. a pointer where the actual key (certificate) is stored. With Always Encrypted the database do not have access to the actual encryption keys. They are stored in external key store (Windows Certificate Store, Azure Key Vault). So what you need to do is to replicate (copy) the existing certificate by registering it in the rest of the databases. Just script the existing CMK as CREATE COLUMN MASTER KEY statement and execute it in each of the databases:
CREATE COLUMN MASTER KEY [CMK_Auto1]
WITH
(
KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE',
KEY_PATH = N'CurrentUser/my/2CC027B4FCA85D4244B528E8CA5F73D1EBB18C69'
)
GO
This will create a new CMK in each database, but all of them will use the same certificate to encrypt the data. Then encrypt the columns you want using the existing CMK, which you created with the script above.

Why my app user couldn't find always encrypted certificate?

Using SQL Server 2017 I followed this article to apply Always Encrypt tech:
https://www.codeproject.com/Articles/1110564/Always-Encrypted-feature-in-SQL-Server
Which is simply says:
Create Column Master key.
Create Column Encryption key.
Encrypt the
columns using the latter.
The certificate that being used for step 1. was generated using the wizard and saved in:
Key Store: Windows Certificate Store - Local Machine
I created very simple console app that is using EF to try to get data from the table that I encrypted the column in.
I added to connection string this: column encryption setting=Enabled.
When I try to get the data:
using (MyEntities en = new MyEntities())
{
var x = en.TableHasColEnc.ToList();
}
I get this error:
'Failed to decrypt column 'X'.
Failed to decrypt a column encryption key using key store provider: 'MSSQL_CERTIFICATE_STORE'. The last 10 bytes of the encrypted column encryption key are: 'XX-XX-XX-XX-XX-XX-XX-XX-XX-XX'.
Certificate with thumbprint '...' not found in certificate store 'My' in certificate location 'LocalMachine'. Verify the certificate path in the column master key definition in the database is correct, and the certificate has been imported correctly into the certificate location/store.
Parameter name: masterKeyPath'
What I got that the user that is running this app is not able to access that location to get the certificate, but why ?
If I ran the app as Admin it'll work normally.
I opened mmc and checked Certificates (Local Computer) and found the certificate that has been used in step 1. and it looks like it's correctly in local machine not current user.
Why I'm getting this error and how to solve it ?
This answer helped me to solve the problem:
How to give ASP.NET access to a private key in a certificate in the certificate store?
The idea is to grant the user who's gonna run the app (or in case of web app the IIS application pool user) the permission to be able to read private keys.
In the correct answer explains how to grant IIS user the permission, you can do the same for who ever is running your app.
UPDATE
If your app is on one server and the DB is on another (so your Encryption Certificate most probably on DB's server) you need to export and then import that certificate from DB's server to your app server and give the user who is running your app the permission to use the private key of this certificate.

SQL Server DMK password

Where is the SQL Server Database master key (DMK) password stored? Is it stored in master database? in registry?. If the hacker gets hold of the mdf files will he be able to get the password that was used to create DMK?
In the SQL Server there is Encryption Hierarchy - everything is encrypted by something. You can create one Database Mater Key in each database in order to protect the certificates, assymetric and symetric keys in it - the DMK is used to encrypted them.
Database master keys are protected by the Service Master Key. The
Service Master Key is created by SQL Server setup and is encrypted
with the Windows Data Protection API (DPAPI).
Let's say we have a database backup and restore it to our local instance. If I try to read some of the ecnrypted data, without knowing the DMK password in order to encrypt the certificate I am getting the following error:
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'I_DO_NOT_KNOW_THE_PASS';
SELECT *, CAST(DecryptByAsymKey(AsymKey_ID(N'smGK_АSymmetricKey_01'), BufferEncryptedEmail) AS NVARCHAR(444))
FROM SecurityUsersAssimetricKey
CLOSE MASTER KEY
Msg 15313, Level 16, State 1, Line 1 The key is not encrypted using
the specified decryptor.
So, in my case (when the DMK is encrtpyed by password), I can only read the ecnrypted data knowing the password:
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'smGK_MasterKeyPassword';
SELECT *, CAST(DecryptByAsymKey(AsymKey_ID(N'smGK_АSymmetricKey_01'), BufferEncryptedEmail) AS NVARCHAR(444))
FROM SecurityUsersAssimetricKey
CLOSE MASTER KEY
In order to protect the whole data, you can check howbackup encryption is made.
If backup encryption is applied, the backup is encrypted using certificate. Without this certificated, the backup cannot be restored. You can store this certificate anywhere you like. Generally, you are right for the brute force - if the database is restored, you can try to brute force the DMK, when you have it, you can read all encrypted columns. But when you cannot restore the database using its backup, you can do nothing.

Restore Service Master Key w/Existing Encryption Data

I recently implemented database encryption using Symmetric/Asymmetric keys and have the Database Master Key (DMK) encrypted by password. Now if I'm understand the encryption hierarchy correctly, the DMK password will then be stored in the master database and is encrypted by the Service Master Key (SMK). My goal is to copy the database to another server to serve as a "test environment". In order to do so, I'll need to restore a copy of the Service Master Key on the destination server in order to properly encrypt/decrypt the data. I just want make sure that I'm reading the documentation correctly regarding the RESTORE MASTER KEY command. When I restore the SMK, any encrypted data on the destination server will first be decrypted by the current SMK and then re-encrypted using the new SMK. Is it safe to assume that no other database should be adversely affected if they have encryption?
Looking at the syntax for CREATE DATABASE ENCRYPTION KEY, the database master key (DMK) is encrypted by either a server-level certificate or a server-level asymmetric key. In order to restore that database on another server, the certificate or asymmetric key that protects the DMK needs to be present in the master database at the destination. Once you have that, you should be good to go.
If this is a cross-environment restore (e.g. prod → dev), I like to re-encrypt the key with an encryptor that doesn't exist at the source. It's a little added protection that ensures that the restore happens one way (i.e. you can't overwrite prod with dev).

Resources