A few weeks ago, I wrote Part 1 and 2 of this series, which was a beginner’s guide to Always Encrypted. In part 3, I am going to go over what road blocks I ran into when trying to implement this solution for a client. The goal of the project was to prevent the DBA from being able to view salary information, while still allowing the application to function without issue.
We were able to encrypt the data easily, but the entire process was not without issues. We had to remove default constraint values to get it to implemented. Always Encrypted does not currently support constraints. Fortunately, the defaulted zero value they had in place was easily fixed and we were off and running. Select statements from SSMS were returning encrypted values, and the application was able to read the encrypted values and returned the real values.
The real challenges started when the client began to test their application code. The first thing we hit was triggers.
The table had several insert triggers associated with the columns that were now encrypted. Since the data was now encrypted the insert triggers would fail. Again, we lucked out and they were able to recode somethings in order to remove the triggers. Of course, since troubles always come in threes, this was no different. First the constraint problem, then the triggers, then we hit the biggest road block that halted our Always Encrypted implementation.
SELECT SUM(Salary) as TotalSalary from Table
Always encrypted does not currently support aggregations. Unfortunately, this is salary data and the code is full of aggregations. There was no way around, and it was not feasible at this point to move the aggregations to the application side. Sadly, we had to abandon this solution and purpose another route. The good news is that this issue will be fixed in the next version of SQL Server. You can learn about secure enclaves technology here.
In researching different possible roadblocks of Always Encrypted I came across as great blog post by Aaron Bertrand (B|T) where he lists several gotcha’s, if you are looking to implement Always Encrypted, I highly recommend starting by reading his post to discover what kind of issues you may run into.
Additionally, here is the official list directly from MSDN of what Is not supported.
Always Encrypted is not supported for the columns with the below characteristics (for example, the Encrypted WITH clause cannot be used in CREATE TABLE/ALTER TABLE for a column, if any of the following conditions apply to the column)
- Columns using one of the following datatypes: xml, timestamp/rowversion, image, ntext, text, sql_variant, hierarchyid, geography, geometry, alias, user defined-types.
- FILESTREAM columns
- Columns with the IDENTITY property
- Columns with ROWGUIDCOL property
- String (varchar, char, etc.) columns with non-bin2 collations
- Columns that are keys for nonclustered indices using a randomized encrypted column as a key column (deterministic encrypted columns are fine)
- Columns that are keys for clustered indices using a randomized encrypted column as a key column (deterministic encrypted columns are fine)
- Columns that are keys for fulltext indices containing encrypted columns both randomized and deterministic
- Columns referenced by computed columns (when the expression does unsupported operations for Always Encrypted)
- Sparse column set
- Columns that are referenced by statistics
- Columns using alias type
- Partitioning columns
- Columns with default constraints
- Columns referenced by unique constraints when using randomized encryption (deterministic encryption is supported)
- Primary key columns when using randomized encryption (deterministic encryption is supported)
- Referencing columns in foreign key constraints when using randomized encryption or when using deterministic encryption, if the referenced and referencing columns use different keys or algorithms
- Columns referenced by check constraints
- Columns in tables that use change data capture
- Primary key columns on tables that have change tracking
- Columns that are masked (using Dynamic Data Masking)
- Columns in Stretch Database tables. (Tables with columns encrypted with Always Encrypted can be enabled for Stretch.)
- Columns in external (PolyBase) tables (note: using external tables and tables with encrypted columns in the same query is supported)
- Table-valued parameters targeting encrypted columns are not supported.
The following clauses cannot be used for encrypted columns:
- FOR JSON PATH
- FOR XML
Although I did take a few punches with this implementation I think Always Encrypted is a great choice to keep your data secure, and I will definitely use it in the future. I am looking forward to seeing how this option improves in the next versions of SQL Server.