Transparent Data Encryption (TDE) is one of the easiest ways of encrypting your data at rest. In my prevous post we looked at what TDE is and how it works: What is Transparent Data Encryption?
In this post we go through the steps of setting it up.
You can set up TDE when you first create a database, or you can apply it to an existing database. In the latter case, once TDE has been enabled it will set to work encrypting your existing data in the background.
In either case the steps are the same. We’ll run through those quickly before going into more detail.
First you must have a Database Master Key (DMK) in the Master database, and a certificate that will be used by TDE:
USE MASTER; CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'UseAStrongPasswordHere!£$7'; CREATE CERTIFICATE MyTDECert WITH SUBJECT = 'Certificate used for TDE in the TestTDE database';
This certificate is critical to you being able to access data encrypted by TDE, so you should make sure you back it up:
BACKUP CERTIFICATE MyTDECert TO FILE = 'C:\MyTDECert' WITH PRIVATE KEY ( FILE = 'C:\MyTDECert_PrivateKeyFile', ENCRYPTION BY PASSWORD = 'UseAStrongPasswordHereToo!£$7' );
Then, in the database being encrypted with TDE you must create a Database Encryption Key (DEK) and specify the certificate:
USE TestTDE; CREATE DATABASE ENCRYPTION KEY WITH ALGORITHM = AES_256 ENCRYPTION BY SERVER CERTIFICATE MyTDECert;
Finally, you turn encryption on:
ALTER DATABASE TestTDE SET ENCRYPTION ON;
And that’s all there is to it in practice.
A potential problem is that it is easy to set this up without really understanding it. Maybe that’s fine in many cases, but can you be sure that there’s nothing that can go wrong and have confidence that whatever the scenario, you will be able to get your data back? And can you be sure that your data is properly protected.
To gain that level of surety and to have confidence, I think it’s best to understand this in a bit more detail. In particular, I think it’s good to understand why each step is required and how the objects created are used.
So let’s go through those steps again in more detail.
Creating the Database Master Key (DMK)
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'UseAStrongPasswordHere!£$7';
A DMK is used to protect other keys that are created in the database. It does this by encrypting them and only the encrypted value is stored. You can only have one DMK in a database.
The DMK itself is also stored encrypted, you can see when we created it we specified a password to encrypt it by. SQL Server also makes separate copy of the key encrypted by the Service Master Key (SMK). The SMK is the root level Key in SQL Server. This additional copy of the DMK means that SQL can access the actual value of your DMK without you having to specify the password again.
Creating the Certificate
CREATE CERTIFICATE MyTDECert WITH SUBJECT = 'Certificate used for TDE in the TestTDE database';
The certificate is going to be used in the next step down – to protect the Database Encryption Key (DEK) in your TDE enabled database. When you create a certificate, it contains an asymmetric key that can be used for encryption. An asymmetric key includes a public key that can be used to encrypt data and a private key that must be used if you want to decrypt data – that private key gets automatically protected (encrypted) by the DMK.
A logical question to ask is why we need the certificate? Why couldn’t we just protect the DEK in our TDE enabled database with the DMK from the master database directly?
Imagine the scenario that you need to migrate your database to another SQL Server instance. We can do this but we will need also to migrate the object that was used to protect/encrypt the DEK – which is itself stored in the database.
If TDE used the DMK to protect that then we would need to migrate the DMK to the new instance. But what if the new instance already had a DMK in the master database and objects that it was used to protect – such as other databases using TDE. At this point we would be stuck, we can’t migrate our DMK without overwriting the one that’s there, so we would have a choice, enable encryption for the migrated database but break it fore the existing ones, or vice versa.
Neither is a good option, but by having a certificate we can migrate that happily as we can have as many certificates as we want.
This also gives us the option that where we have multiple databases encrypted by TDE we could use a separate certificate for each. That means if one certificate is breached the others could remain protected.
This does raise a good point though that you may want one day to migrate your certificate, so call it something more meaningful and unique than “MyTDECert”.
Backing up the certificate
BACKUP CERTIFICATE MyTDECert TO FILE = 'C:MyTDECert' WITH PRIVATE KEY ( FILE = 'C:MyTDECert_PrivateKeyFile', ENCRYPTION BY PASSWORD = 'UseAStrongPasswordHereToo!£$7' );
We backup the certificate in case we ever need to move or restore our database to a different server or SQL instance. It’s critical if we want to be able to access our encrypted data.
When you back it up, you specify a password to encrypt the key. What happens is SQL grabs the stored version of the Private Key (which is encrypted by the DMK) decrypts it, then re-encrypts it with the password. This means that you would be able to restore it to a different SQL instance where the DMK didn’t exist.
This covers us against the scenarios explained above regarding why we use a certificate rather than just relying on the DMK. It should also make it clear that if we need to migrate or recover the database all we need is:
- The database backup
- The certificate and key backups and the password used when creating them
Creating the Database Encryption Key (DEK)
CREATE DATABASE ENCRYPTION KEY WITH ALGORITHM = AES_256 ENCRYPTION BY SERVER CERTIFICATE MyTDECert;
In this, almost the final step, we create the actual key that will be used to encrypt the data. It’s stored in the database, but encrypted by the key associated with the certificate created in the previous step. The DEK is a symmetric key, i.e. the same value is used to encrypt or decrypt data.
It’s logical to ask why we don’t just use the private key from the certificate to encrypt the data directly. This is a bit more difficult to justify than the previous scenario with the DMK versus use of a certificate. It is certainly feasible that TDE could have been implemented this way.
One consideration is that the certificate is created with an asymmetric key – these are easier to work with in some ways as we only need the public key to encrypt data so can keep the private key concealed most of the time. Asymmetric encryption however is slower that symmetric encryption so to reduce the performance impact of TDE we want to use a symmetric key.
The concept of a DEK was new in SQL 2008 and created specifically for TDE. It makes sense that if we are to have a separate DEK then it should be stored in the database itself. That way migration/recovery is eased as it minimises the number of objects required.
It’s worth noting that you can only have one DEK in each database.
ALTER DATABASE TestTDE SET ENCRYPTION ON;
In sys.databases you can see which databases have TDE turned on by looking at the is_encrypted column:
SELECT name FROM sys.databases WHERE is_encrypted = 1;
We can find more details in the sys.dm_database_encryption_keys server view. Let’s query looking at some particular columns of interest:
SELECT d.name, k.encryption_state, k.encryptor_type, k.key_algorithm, k.key_length, k.percent_complete FROM sys.dm_database_encryption_keys k INNER JOIN sys.databases d ON k.database_id = d.database_id;
Here’s what I see after I created my DEK but before I enable encryption:
We can see information about the DEK. We also see encryption state which describes the current state of the database. The main values you’ll see are:
1 = Unencrypted
2 = Encryption in Progress
3 = Encrypted
If I now enable encryption on this database and run the query again:
We see that both my database and the TempDB database are now encrypted.
We also see the percent_complete column, which confusingly says zero. This column only has meaning when a state change is occurring. So, if the encryption state was 2 – then we would see a value here whilst the database was in the process of being encrypted. Here my database only had one row, so it was fairly instantaneous to flip encryption on.
This column becomes relevant when we are encrypting an existing database that has a reasonable amount of data, we’ll look at that next: