Transparent Data Encryption (TDE) is one of the easiest ways of encrypting your data at rest. In the previous posts we looked at what TDE is and how it works.
In this post we go through the steps of setting TDE up. You can set up TDE when you first create a database (which we will look at in this post), or you can apply it to an existing database (which we’ll cover in posts I’ve got coming up). In the latter case, once TDE has been enabled it will encrypt your existing data in the background. In either case the steps are the same.
Creating the Keys and Certificate
The first step in setting up TDE is to create the required keys and certificate. We’re going to focus on the default encryption hierarchy we’ve already looked at where we have the Service Master Key (SMK) at the top level, which protects the Database Master Key (DMK) in the master database, in turn protecting a certificate and associated asymmetric key pair, also in the master database. Finally, at the bottom we have the Database Encryption Key (DEK) in the user database which is protected by the certificate’s asymmetric key.
The SMK always exists for a SQL Server instance, so we just need to create the objects underneath it in the hierarchy. If you are planning on using Extensible Key Management (EKM) for managing your keys, then some of these steps are unnecessary. We’ll cover EKM later on.
Creating the Database Master Key (DMK)
First of all you must have a DMK. This lives in the master database and you can only have one per instance of SQL Server. You can create a DMK with the following SQL command (substitute your own password):
CREATE MASTER KEY
ENCRYPTION BY PASSWORD = 'UseAStrongPasswordHere!£$7';
We’ve already mentioned that the DMK is encrypted by the SMK, so it’s reasonable to ask why in this command we must also specify encryption by a password. What happens when you create the DMK is that a key is generated, two encrypted copies of that key are then created and stored in the master database, one encrypted by the SMK, and one by the password specified (both encrypted using the AES_256 algorithm). Having the copy encrypted by the password is necessary where you might need to restore a backup of the master database (including the DMK) to a separate SQL Server instance where the original SMK will not be available. In general, you don’t need to do this to recover a TDE enabled database to a separate SQL Server instance as long as you have backups of the certificate and private key, however you may use the DMK for purposes other than TDE.
It is recommended you backup the DMK. In most cases this backup is not useful in the context of TDE, but as mentioned you may have other objects not related to TDE that depend on the DMK so it is good practice. Backing up the DMK is a single command:
BACKUP MASTER KEY TO FILE = 'C:\Test\MyDMK'
ENCRYPTION BY PASSWORD = 'UseAnotherStrongPasswordHere!£$7';
Creating the Certificate
Next, we need to create a certificate for use by TDE. We do that with the following code:
CREATE CERTIFICATE MyTDECert
WITH SUBJECT = 'Certificate used for TDE in the TestTDE database';
This command tells SQL Server to generate a self-signed certificate and associated public\private key pair which can be used for asymmetric encryption. The private key will automatically be encrypted by the DMK. As mentioned previously, you can create a separate certificate for each database you wish to protect with TDE – or you could share the certificate between multiple databases. Having a separate certificate for each database minimizes the attack area if someone gets access to one of them, but you may choose to share the certificate between multiple databases on the same instance for ease of management. Make sure you give your certificate a meaningful and unique name as you may want at some point to migrate it to another server which might already have other certificates used for TDE. You wouldn’t want them to have the same name, and it is useful to easily be able to identify what each is for – for instance you may want to include a suffix to represent the environment the certificate belongs to.
These objects are absolutely critical in being able to encrypt and decrypt your data, so it is essential that you back them up. That can be achieved with the following SQL:
BACKUP CERTIFICATE MyTDECert
TO FILE = 'C:\Test\MyTDECert.cer'
WITH PRIVATE KEY
FILE = 'C:\Test\MyTDECert_PrivateKeyFile.pvk',
ENCRYPTION BY PASSWORD = 'UseAStrongPasswordHereToo!£$7'
This creates two backup files, one for the certificate and one for the private key. The private key is backed up encrypted by the password supplied. These files, and the password used to protect the private key, need to be stored securely. It is impossible to over-stress how important this is. The most common pitfall people fall into with TDE is needing to recover or restore a TDE-protected database and not knowing where to find these backups or what the password is. Particularly where the person who set TDE has left the organization. If the backup has not been taken, cannot be found, or you don’t have the password it was protected with, then you have the potential to permanently lose all data that has been protected by TDE. If you enter a new organization or role where you are responsible for TDE-protected databases, you should make sure you know where these items are stored or take your own backups if they can’t be produced.
We have seen a few cases in this post where we need to use a password to protect an object. If your organization doesn’t already use one, then you should consider using a password manager such as KeePass (many others exist) to manage your passwords securely and safely.
Creating the Database Encryption Key (DEK)
The DEK is what is actually used to encrypt and decrypt data stored in your TDE-protected database. The DEK is stored in the database itself (in the database root record) but is stored encrypted by the private key we created in the previous step. The DEK is a single key used for symmetric encryption, the same key is used to both encrypt and decrypt data. A symmetric key is used in this case as symmetric encryption is much faster than asymmetric, and we want our transparent encryption activities to occur with a minimum of overhead and latency.
Before we create the DEK we need a database we are going to protect with TDE. If you haven’t already created the TestTDE database then you can do so with the following SQL:
CREATE DATABASE TestTDE;
Now we can go ahead and create the DEK.
CREATE DATABASE ENCRYPTION KEY WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER CERTIFICATE MyTDECert;
You can see we specify the algorithm – AES (Advanced Encryption Standard) with a 256-bit key is recommended. We also specify the certificate to be used which will identify the public/private key pair to be used to encrypt the DEK.
Unlike the other keys, you don’t need to backup the DEK as it is automatically included in any backups you take of the database itself.
Encrypting the Database
Encrypting the database is the simple action of turning encryption on for the database.
ALTER DATABASE TestTDE SET ENCRYPTION ON;
In this case we have just created a new empty database so there is no data to encrypt and the action is instantaneous. As we then start to add tables and data the data will be automatically encrypted as it is written to disk for the first time. Similarly, any backups taken, Full Log or Differential, will automatically be encrypted as they are written to disk.
In sys.databases you can see which databases have TDE turned on by looking at the is_encrypted column, you can query that as follows:
WHERE is_encrypted = 1;
We can see the results of the query in this image:
We can see that both our TestTDE database and tempdb get encrypted. As discussed previously tempdb gets encrypted when any other database uses TDE. We can view more details about our TDE encrypted databases by looking at the sys.dm_database_encryption_keys view. Let’s query that view and look at some columns of interest.
FROM sys.dm_database_encryption_keys k
INNER JOIN sys.databases d
ON k.database_id = d.database_id;
This image shows what I see if I executed this query before I turned encryption on.
We can see information about the DEK. We also see the encryption_state column which describes the current state of the database. The possible values you’ll see are:
- Encryption in progress
- Key change in progress
- Decryption in progress
- Protection change in progress (this occurs where the object protecting the DEK is being changed)
The below image shows what we see if we execute the query after encryption has been enabled:
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 an encryption state change is occurring. So, if the encryption state was 2 (encryption in progress) – then we would see a value here while the database was in the process of being encrypted. Here my database contained no data, so it was 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 shortly.
The query we’ve just looked at will work on all versions of SQL Server. From SQL 2019 however we have a few extra columns of information available to us in the sys.dm_database_encryption_keys view. In particular there is the column encryption_state_desc that give us a plaintext description of the encryption state.
That’s all there is to setting TDE up, in the next post we’ll look at an extra step you may wish to take to improve the security of your data.
This post is part of a comprehensive series on SQL Server Encryption. Subscribe to my blog for updates as new posts are published or you can buy my book through the link in the sidebar to get it all in one go.
And if you’re embarking on an encryption project (or anything else to do with SQL Server) and want some help, I’m available for consulting – please get in touch or check out my services page to find out what I can do for you.