Back to Checks
SQL server uses a customer-managed key for the TDE protector and all databases have TDE enabled
sqlserver_tde_encrypted_with_cmk
Service: sqlserverSeverity: critical
OfficialBuilt-inVerified
Categories:encryption
Resource Type:microsoft.sql/servers
Azure SQL Server uses Transparent Data Encryption with a customer-managed key in Azure Key Vault, and each database has TDE Enabled
Risk
Without TDE with CMK, data at rest may be unencrypted or controlled by service keys, weakening confidentiality and key custody. Attackers or insiders could read backups, snapshots, or stolen disks, and you cannot enforce rotation, revocation, or separation of duties, raising compliance and incident response risks.
Run this check with Prowler
Run in Prowler CloudRun
prowler azure --checks sqlserver_tde_encrypted_with_cmkRecommendation
Use a customer-managed TDE protector in Azure Key Vault or Managed HSM and ensure TDE is Enabled for every database.
- Apply least privilege to key access
- Enable rotation and monitor key use
- Protect keys with soft-delete and purge protection
- Enforce via policy and maintain key backups for restores
Remediation
CLI
az rest --method PUT --url "https://management.azure.com/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.Sql/servers/<SERVER_NAME>/encryptionProtector/current?api-version=2021-11-01" --body '{"properties":{"serverKeyType":"AzureKeyVault","serverKeyName":"<KEY_VAULT_NAME>_<KEY_NAME>_<KEY_VERSION>"}}' && az sql db tde set --resource-group <RESOURCE_GROUP> --server <SERVER_NAME> --database <DATABASE_NAME> --status EnabledTerraform
# Set the SQL Server TDE protector to a Key Vault CMK
resource "azurerm_mssql_server_transparent_data_encryption" "<example_resource_name>" {
server_id = "<example_resource_id>"
key_vault_key_id = "<key_vault_key_id>" # critical: KID of the Key Vault key to use as TDE protector
}
# Ensure TDE is enabled on the database
resource "azurerm_mssql_database" "<example_resource_name>" {
name = "<example_resource_name>"
server_id = "<example_resource_id>"
transparent_data_encryption_enabled = true # critical: turns on TDE for the database
}NativeIaC
// Add the Key Vault key to the SQL server
resource serverKey 'Microsoft.Sql/servers/keys@2021-11-01' = {
name: '<example_resource_name>/<example_resource_name>'
properties: {
serverKeyType: 'AzureKeyVault' // critical: use a customer-managed key from Azure Key Vault
uri: 'https://<example_resource_name>.vault.azure.net/keys/<example_resource_name>/<example_resource_id>' // critical: KID of the Key Vault key
}
}
// Set the server TDE protector to the Key Vault key (CMK)
resource encryptionProtector 'Microsoft.Sql/servers/encryptionProtector@2021-11-01' = {
name: '<example_resource_name>/current'
properties: {
serverKeyType: 'AzureKeyVault' // critical: switches protector from service-managed to CMK
serverKeyName: '<example_resource_name>' // critical: reference the key added above
}
}
// Ensure TDE is enabled on the database
resource dbTde 'Microsoft.Sql/servers/databases/transparentDataEncryption@2014-04-01' = {
name: '<example_resource_name>/<example_resource_name>/current'
properties: {
status: 'Enabled' // critical: turns on TDE for the database
}
}Other
1In the Azure portal, go to SQL servers > select <server>
2Under Security, open Transparent data encryption
3Select Customer-managed key and choose the key from Azure Key Vault, then Save
4For each database on this server: go to SQL databases > select <database> > Transparent data encryption
5Set Status to On and Save
Check Code
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.sqlserver.sqlserver_client import sqlserver_client
class sqlserver_tde_encrypted_with_cmk(Check):
def execute(self) -> Check_Report_Azure:
findings = []
for subscription, sql_servers in sqlserver_client.sql_servers.items():
subscription_name = sqlserver_client.subscriptions.get(
subscription, subscription
)
for sql_server in sql_servers:
databases = [
database
for database in (
sql_server.databases if sql_server.databases is not None else []
)
if database.name.lower() != "master"
]
if len(databases) > 0:
report = Check_Report_Azure(
metadata=self.metadata(), resource=sql_server
)
report.subscription = subscription
found_disabled = False
if (
sql_server.encryption_protector.server_key_type
== "AzureKeyVault"
):
for database in databases:
if found_disabled:
break
if database.tde_encryption.status == "Enabled":
report.status = "PASS"
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription_name} ({subscription}) has TDE enabled with CMK."
else:
report.status = "FAIL"
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription_name} ({subscription}) has TDE disabled with CMK."
found_disabled = True
else:
report.status = "FAIL"
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription_name} ({subscription}) has TDE disabled without CMK."
findings.append(report)
return findingsReferences
- https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Sql/use-byok-for-transparent-data-encryption.html#
- https://learn.microsoft.com/en-us/azure/azure-sql/database/transparent-data-encryption-byok-overview?view=azuresql
- https://learn.microsoft.com/en-us/azure/azure-sql/database/transparent-data-encryption-byok-overview?view=azuresql&tabs=azurekeyvault%2Cazurekeyvaultrequirements%2Cazurekeyvaultrecommendations