SQL Server 2019 Enterprise - High Availability with Master Key - sql-server

I have a SQL Server 2019 Enterprise HA system that has a encrypted master key, and every time that I have to fail over to the secondary database (or vice n versa) I have to run this script in order to have the Secondary working after the failover.
DROP SYMMETRIC KEY DataProtectionKey
DROP CERTIFICATE DataProtection
DROP MASTER KEY
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'My_encryption_key'
CREATE CERTIFICATE DataProtection WITH SUBJECT = 'Data Protection'
CREATE SYMMETRIC KEY DataProtectionKey WITH ALGORITHM = AES_256 ENCRYPTION BY CERTIFICATE DataProtection
USE [MYDATABASE]
GO
ALTER MASTER KEY FORCE REGENERATE 
WITH ENCRYPTION BY PASSWORD = 'My_encryption_key'
GO
I also tried to use this other script after failing over to see if I could finally insert the Master Key and solve for all the issue.
USE [MYDATABASE]
GO
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'My_encryption_key';
ALTER MASTER KEY DROP ENCRYPTION BY SERVICE MASTER KEY
ALTER MASTER KEY ADD ENCRYPTION BY SERVICE MASTER KEY
CLOSE MASTER KEY;
Unfortunately, every time that I fail over the DB, I have to run one of the two scripts.
There is any way that I could do this once for all ?
Thank you

You can try to create the certificate on primary, backup, and restore on secondary.
This code is from my repo created for a demo for AlwaysOn with docker.
Primary
-- PRIMARY
USE [master]
GO
-- Create masterkey
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'P#ssw0rd!';
GO
-- Create certificate
CREATE CERTIFICATE ao_certificate WITH SUBJECT = 'ao_certificate';
GO
BACKUP CERTIFICATE ao_certificate
TO FILE = '/var/opt/mssql/shared/ao_certificate.cert'
WITH PRIVATE KEY (
FILE = '/var/opt/mssql/shared/ao_certificate.key',
ENCRYPTION BY PASSWORD = 'P#ssw0rd!'
);
GO
Secondary
-- SECONDARY
USE [master]
GO
-- Create master key
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'P#ssw0rd!';
GO
-- create certificate with private key created on primary server and saved to shared location
CREATE CERTIFICATE ao_certificate
FROM FILE = '/var/opt/mssql/shared/ao_certificate.cert'
WITH PRIVATE KEY (
FILE = '/var/opt/mssql/shared/ao_certificate.key',
DECRYPTION BY PASSWORD = 'P#ssw0rd!'
)
GO

Yes, and the fix is relatively simple. Take a backup of the service master key (SMK) from the secondary replica and restore it to the primary replica. This will re-encrypt anything already encrypted with the existing SMK with the restored SMK. And since the SMK is now the same between both replicas, the failover will be seamless.
The reason that the direction is from secondary to primary is that the re-encryption performs writes (albeit not many) into your user database which is allowed only on the primary replica.

A colleague from my team found a better solution for this issue.
On the primary DB, I will call DBS1 backup the master key using the encryption password that you used to create the DB:
BACKUP SERVICE MASTER KEY TO FILE = 'D:\Backup\dbs1_service_master_key.key' ENCRYPTION BY PASSWORD = 'Wh#t3v3r_P#$$w0rd';
Promote the secondary DB to primary on the HA (failover), so you can run the script below:
USE [YOURDATABASE]
GO
open master key decryption by password = 'Wh#t3v3r_P#$$w0rd'
Alter Master Key Add encryption by Service Master Key
GO
Copy the service master key that you backed up on the primary DBS1 and copy in a location on DBS2.
Still on the "secondary" DBS that now is primary on the HA group, restore the certificate:
RESTORE SERVICE MASTER KEY FROM FILE = 'D:\Backup\dbs1_service_master_key.key' DECRYPTION BY PASSWORD = 'Wh#t3v3r_P#$$w0rd';

Related

SQL Server "Cannot find the symmetric key 'DataFilePasswordKey'" though I created it and I'm a db_owner

In SQL Server 2019 Enterprise, I have Dev, Test, and Production instances of a database on separate servers. I am in the db_owner role on all three. I've created master key, certificate, and symmetric key on each for the purpose of encrypting one column in one table.
CREATE MASTER KEY ENCRYPTION
BY PASSWORD = '[password]'
GO
CREATE CERTIFICATE DataFileCert
WITH SUBJECT = 'Data File Info';
GO
CREATE SYMMETRIC KEY DataFileKey
WITH ALGORITHM = AES_256
ENCRYPTION BY CERTIFICATE DataFileCert;
GO
Following this, on the Dev and Test servers, I can run this with no problem:
OPEN SYMMETRIC KEY DataFileKey
DECRYPTION BY CERTIFICATE DataFileCert;
On Production, I get the error "Cannot find the symmetric key 'DataFileKey', because it does not exist or you do not have permission.".
I can see both the certificate and the symmetric key in the Object Explorer. I can also DROP both the key and the certificate and am then able to start over. So I know it exists, and I even have permission to drop it.
Given these circumstances--that I'm the one who created the master key, the certificate, and the symmetric key, and that I'm in the db_owner role on all three instances--what could be going on here?
Check to make sure your user has both of:
GRANT VIEW DEFINITION ON CERTIFICATE :: DataFileCert TO [userName]
GRANT VIEW DEFINITION ON SYMMETRIC KEY :: DataFileKey TO [userName]
On the certificate you used to create the key, and the key itself.

How to back multiple master database key DEK on SQL with TDE Enable

I have an SQL instance with multiple data bases. Each of them are TDE encrypted.
I know that all data bases use the same service master key, SMK, to encrypt tempdb. I have back up the SMK using:
BACKUP SERVICE MASTER KEY
TO FILE = 'tmp-path.key'
ENCRYPTION BY PASSWORD = 'temp-password';
Now, how do I back up the distinct database master key, DMK? Each data base use a different one, but the SQL statement doesn't allow to specify which one to back up. Next, is the command I'm running.
BACKUP MASTER KEY
TO FILE = 'tmep-path.key'
ENCRYPTION BY PASSWORD = 'temp-passowrd'
I though that by:
use [specific-db];
GO
It will back up an specific one, but the command won't run. You need to be on master, to run the command.
Thanks
The way TDE is configured in SQL Server is as follow:
Create Master key in master database
Create Certificate using the master key
Create Database Encryption key using the certificate
There are only two things you need to/can backup here:
Master Encryption Key - The script you have shown in your question will do that.
BACKUP MASTER KEY
TO FILE = 'tmep-path.key'
ENCRYPTION BY PASSWORD = 'temp-passowrd'
Certificate - You can either create a separate Certificate for each database to be encrypted or a single certificate to encrypt all database, You will create and backup the certificate as follow:
-- Create Certificate
USE Master;
GO
CREATE CERTIFICATE TDE_MyDB_Cert
WITH SUBJECT = 'My TDE Certificate for MyDB user database'
GO
This certificate is protected by the service master key.
-- Encrypt Database using the Certificate
USE [MyDB]
GO
CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_128
ENCRYPTION BY SERVER CERTIFICATE TDE_MyDB_Cert
GO
Now you need to backup the certificate with the private key for the database which you would do, doing:
USE master;
GO
BACKUP CERTIFICATE TDE_MyDB_Cert
TO FILE = 'C:\TDE_MyDB_Cert_File.cer'
WITH PRIVATE KEY (FILE = 'C:\TDE_MyDB_Cert_PKey.pvk' ,
ENCRYPTION BY PASSWORD = 'S0M34tR0nGP#$$w)rd' )
GO
TDE_MyDB_Cert_File.cer Is the certificate backup
TDE_MyDB_Cert_PKey.pvk is the backup for Private key for the database

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.

Encryption with an AlwaysOn cluster

I have a database that was moved off of an old SQL Server 2008R2 instance and into a SQL Server 2012 AlwaysOn cluster. There are several fields within the database that are encrypted using SQL Servers built-in encryption features (master key, cert, symmetric key.)
I have run the following commands on my QA AO instance (the same steps that had been run on the old server):
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'password'
CREATE CERTIFICATE myCert
WITH SUBJECT = 'password'
CREATE SYMMETRIC KEY myKeyName
WITH ALGORITHM = TRIPLE_DES
ENCRYPTION BY CERTIFICATE myCert
Additionally I had to run the following commands to correctly decrypt the data:
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'password'
ALTER MASTER KEY ADD ENCRYPTION BY SERVICE MASTER KEY
When I run this command I then see all of the data decrypted:
OPEN SYMMETRIC KEY myKeyName
DECRYPTION BY CERTIFICATE myCert
select TOP 1000 userid, CONVERT(nVARCHAR(255),DECRYPTBYKEY(password)) from users
CLOSE SYMMETRIC KEY myKeyName
So far so good. However, if I run these same steps on my production AO cluster this query:
select TOP 1000 userid, CONVERT(nVARCHAR(255),DECRYPTBYKEY(password)) from users
returns NULL for the password. To make this a little bit more maddening, this statement (run in the context of the QA environment) decrypts everything from both databases just fine:
OPEN SYMMETRIC KEY myKeyName
DECRYPTION BY CERTIFICATE myCert
SELECT TOP 1000
userid,
CONVERT(nVARCHAR(255),DECRYPTBYKEY(password))
FROM users
SELECT TOP 1000
userid,
CONVERT(nVARCHAR(255),DECRYPTBYKEY(password))
FROM PRODUCTIONAO.prod_database.dbo.users
CLOSE SYMMETRIC KEY myKeyName
I am not sure why this would work on my QA instance, but not on my production instance. Any help would be greatly appreciated!
The reason your last query works is due to the fact that you're using the QA instance's key/cert to do the decryption of the production data. In QA you can auto-decrypt the cert with the database master key (DMK) since it's encrypted by the QA service master key (SMK) as follows:
Service Master Key (QA)
Database Master Key (QA)
Certificate (QA)
Symmetric Key (QA)
Data (Prod)
In prod, you have a different SMK so the only option to open the DMK is by using the password. It seems that you ran the following in the QA environment but not in prod:
/* Add service master key encryption to the database master key */
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'password'
ALTER MASTER KEY ADD ENCRYPTION BY SERVICE MASTER KEY
Try this in prod:
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'password'
OPEN SYMMETRIC KEY myKeyName
DECRYPTION BY CERTIFICATE myCert
select TOP 1000 userid, CONVERT(nVARCHAR(255),DECRYPTBYKEY(password)) from users
CLOSE SYMMETRIC KEY myKeyName
If that returns data, you need to add the SMK encryption to your DMK in production (the first script). The other option is backing up the SMK from the source instance and restoring it on the secondary. I'd only recommend this in HA use-cases where the instances are fail-over partners and both are in the same environment. Sharing SMKs between QA and prod is a bad practice.
When a database master key is created, the server saves 2 versions of key. One version is encrypted by the master service key and by default is used by the server. The second version is encrypted by the password that you supply to the server when you create the database master key. This version usually is not used. When you move your database into a different environment (production in your case), the new server has a different master service key. Since it is not the service key that was used to encrypt the database’s master key, it also can’t be used in order to open the database’s master key. This is where you should use the version that was encrypted with your password. You need to open the master key using your password, then encrypt it using the new service key and close it. After you do that, the database’s master key can work with the master service key, so you don’t need to do it again.
steps/code:
open master key decryption by password = 'WriteYouOriginalPasswordHere'
alter master key add encryption by service master key
close master key

EncryptByKey function does not work after restore

I've restored my database to a new server and now the EncryptByKey function does not work properly. Any ideas?
You probably broke the encryption key hierarchy as the service master key encryption of your database master key is now gone. Open the database master key using the original encryption password and add the new server service master key encryption:
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'password';
ALTER MASTER KEY ADD ENCRYPTION BY SERVICE MASTER KEY;

Resources