Skip to main content
emnode
Compliance

Retain Azure audit and activity logs

One capability across your SQL estate: make sure the audit trail that records who touched a database, and what they did, is kept long enough to investigate an incident and to satisfy an auditor, rather than rolling off after a fortnight.

14 min·10 sections·AZURE

Last reviewed

Remediates Microsoft Defender for Cloud: azure-sql-audit-retention-90-days

Retaining audit logs: the basics

What does a SQL server with too-short audit retention actually look like?

An audit log is the record of who connected to a database, what they read, and what they changed. Azure SQL auditing writes that record to a destination you choose, and when the destination is a storage account, you set a retention period in days for how long those records are kept before Azure deletes them. The default retention value is 0, which Azure treats as unlimited, but plenty of accounts are configured with a short window such as 7 or 30 days because someone wanted to keep the storage bill down. The result is an audit trail that exists but is too short to be useful: by the time an incident is noticed and investigated, the evidence has already rolled off.

Microsoft Defender for Cloud turns this into a single, specific recommendation: 'Audit retention for SQL servers should be set to at least 90 days.' It checks the server-level auditing configuration and flags any SQL server whose auditing writes to a storage account with a retention period set below 90 days. Ninety days is the line because it is the minimum window most incident-response processes and compliance frameworks assume: long enough that a breach discovered weeks after the fact still has a readable trail behind it. A server with auditing simply switched off is a different finding; this one is specifically about the length of the trail you keep.

The important nuance is where the retention setting lives. The 90-day retention period is a property of the storage account audit destination only. If a server sends its audit logs to a Log Analytics workspace or an Event Hub instead, the auditing configuration carries no retention-days value, because the lifetime of those logs is governed by the workspace or the hub itself, not by the auditing settings. So the work splits cleanly: for storage-account targets, set retention to at least 90 days on the auditing configuration; for Log Analytics or Event Hub targets, confirm the retention is governed correctly at the workspace or hub instead.

In this lesson you will learn how Azure SQL auditing expresses log retention, why 90 days is the line Defender for Cloud draws, how to find every SQL server whose trail is too short, and how to extend retention without losing the logs you already have. The Controls this lesson covers section lists the Defender for Cloud recommendation in this capability, linking to a deep page with the exact check and a copy-and-paste fix.

Fun fact

The breach you cannot scope

The painful truth about data breaches is how long they go unnoticed. Industry breach reports have for years put the average time to identify and contain an incident at the better part of a year. That single statistic is why 90 days is the floor and not the ceiling: an audit trail that only reaches back two or three weeks is already useless against the typical detection gap. When auditing writes to a storage account, retention is a single number in days, and Azure deletes anything older the moment it crosses the line. Set that number to 7 to save a few pence, and you have quietly decided that any breach found more than a week late will be unscopeable.

Finding short audit retention across a subscription

Priya is the security lead at a fintech preparing for its first SOC 2 audit. Defender for Cloud shows the audit-retention recommendation failing on several SQL servers across two subscriptions that pre-date the team's current guardrails.

Rather than work the findings blind, Priya starts by listing each server's auditing configuration: which target it writes to, and where it sends to a storage account, what the retention period actually is. That separates the servers with a genuinely short window from the ones that send to Log Analytics, where retention lives elsewhere.

List every SQL server's audit state and retention. The servers writing to blob storage with a low retentionDays are the real targets.

$ az sql server audit-policy show --resource-group rg-data --name sql-payments-prod --query "{state:state, blob:blobStorageTargetState, days:retentionDays}" -o table
State Blob Days
------- ------- ------
Enabled Enabled 7
# Auditing is on, writing to a storage account, but only 7 days are kept.
# A breach found a month from now would have no trail. Raise this to >= 90.

A server that audits to blob storage with a retention below 90 days is the exact shape this recommendation flags. Servers that audit to Log Analytics show no retentionDays here, because their retention is set on the workspace instead.

How Defender for Cloud decides audit retention is too shortdeep dive

The recommendation reads the server-level auditing configuration, the 'Microsoft.Sql/servers/auditingSettings' object named 'default'. When state is Enabled and the audit logs are written to a storage account, that object carries a 'retentionDays' value. Defender for Cloud flags the server when retentionDays is set to a positive number below 90. A value of 0 is the special case Azure treats as unlimited retention, which satisfies the check rather than failing it, so a server keeping logs forever is healthy, not flagged.

The setting is specific to the storage-account destination. When auditing instead targets a Log Analytics workspace or an Event Hub, the auditing object carries no meaningful retentionDays, because the lifetime of those records is controlled by the workspace retention policy or the Event Hub message-retention setting respectively. That is why the same recommendation can be satisfied two different ways: by raising retentionDays on a storage target, or by confirming that a Log Analytics or Event Hub target retains long enough on its own settings. The recommendation maps to the Microsoft Cloud Security Benchmark control LT-6, configure log storage retention, which is the benchmark's requirement that logs are kept long enough to be useful for investigation and compliance.

Defender for Cloud evaluates this against the benchmark on a periodic cycle, so raising retention does not flip the recommendation to Healthy instantly. The configuration change itself is immediate, but the posture catches up on the next assessment. One subtlety worth knowing: when you raise the retention period, the new window applies going forward, so older logs that were already past the previous, shorter limit are not magically restored. The strongest position pairs the per-server setting with an Azure Policy backstop so no server can be left below the line in the first place.

What is the impact of a too-short audit trail?

The direct impact lands at exactly the wrong moment. Audit logs are the record you reach for during an incident: to establish who accessed which data, when, and from where. If the retention window is shorter than the gap between a breach happening and being discovered, that record is already deleted when you go looking for it. You cannot scope the incident, you cannot say with confidence whose data was affected, and you cannot prove what an attacker did or did not reach. A short window does not reduce the chance of a breach; it reduces your ability to understand one.

The second-order impact is everything that depends on scoping. Breach-notification law requires you to tell affected individuals and regulators within tight windows, and you can only notify accurately if you can see who was affected. Without a trail, you face a choice between over-notifying, which is costly and reputationally damaging, and under-notifying, which is a compliance failure in its own right. Cyber-insurance claims, legal defence and customer trust all hinge on being able to reconstruct what happened, and the audit trail is the artefact that lets you.

On the compliance side, retention floors are written into the frameworks. SOC 2, ISO 27001, PCI DSS, HIPAA and the UK and EU data-protection regimes all expect audit and access logs to be retained long enough to support investigation, with 90 days a common minimum and one year frequently required for regulated data. A SQL estate where every server keeps at least 90 days of audit trail is a cheap, concrete artefact to hand an auditor; a scatter of 7-day windows is a finding you will be asked to remediate on the spot.

How do you extend audit retention safely?

Work the capability as one loop rather than chasing the finding server by server. The order matters: confirm where each server sends its audit logs before you touch retention, so you set the number on the targets where it actually applies and verify the others elsewhere.

1. Inventory every server's audit target and window

For each SQL server, read the auditing configuration: is it enabled, does it write to a storage account, a Log Analytics workspace or an Event Hub, and where it writes to storage, what is the retention in days. This inventory is the source of truth, because a server auditing to Log Analytics will never show a retentionDays value and is not fixed by changing one.

2. Separate storage targets from workspace and hub targets

For servers auditing to a storage account, retention is set directly on the auditing configuration and is the thing you raise. For servers auditing to a Log Analytics workspace or an Event Hub, retention lives on the workspace retention policy or the hub message-retention setting instead, so the fix is to confirm those are set long enough rather than touching the auditing object.

3. Raise the window to at least 90 days, data first

On the storage-account targets, set retentionDays to 90 or more, or to 0 for unlimited retention. Prioritise servers holding regulated or customer data over staging and test servers. Remember the change applies going forward: it preserves logs from this point on, it cannot recover logs that already aged off under the old, shorter window.

4. Ratchet it shut with Azure Policy

Assign the built-in policy that audits SQL servers configured below 90 days of storage retention, so any new or reconfigured server that drops below the line is surfaced automatically rather than discovered at the next audit. That turns a one-time clean-up into a standing guarantee that the trail is always long enough.

# Raise SQL audit retention to 90 days on a server that audits to a storage account.
# retentionDays only applies to the storage-account target; 0 would mean unlimited.
az sql server audit-policy update \
  --resource-group rg-data \
  --name sql-payments-prod \
  --state Enabled \
  --blob-storage-target-state Enabled \
  --storage-account stsqlauditprod \
  --retention-days 90

# Ratchet it shut: look the built-in policy up by its exact display name (never
# hardcode the GUID), then assign it so any server below 90 days is surfaced.
pid=$(az policy definition list \
  --query "[?displayName=='SQL servers with auditing to storage account destination should be configured with 90 days retention or higher'].name" \
  -o tsv)

az policy assignment create \
  --name audit-sql-retention-90 \
  --policy "$pid" \
  --scope "/subscriptions/00000000-0000-0000-0000-000000000000"

Quick quiz

Question 1 of 5

Defender for Cloud flags 'Audit retention for SQL servers should be set to at least 90 days' on a server. What is it actually checking?

You can now treat SQL audit retention as one capability rather than a one-off finding: inventory where each server sends its audit logs, separate the storage targets from the Log Analytics and Event Hub ones, raise every storage window to at least 90 days starting with the data-bearing servers, and ratchet the floor shut with Azure Policy. The Controls this lesson covers section below links the recommendation to its deep page and fix.

Back to the library