Back to blog
AzureBest PracticesCloud SecurityMonitoring & LoggingOperations & Compliance

No Azure Monitor Log Profile: Why Your Activity Logs Need a Home

Learn why a missing Azure Monitor activity log profile leaves your subscription without an audit trail, and how to export, enforce, and verify activity logs.

TL;DR

This check flags Azure subscriptions with no Monitor activity log profile, which means your control-plane events are not being exported to long-term storage. Without it you lose the audit trail needed to investigate breaches. Fix it by creating a log profile (or a diagnostic setting) that ships activity logs to a storage account, Log Analytics workspace, or Event Hub.

Azure records every control-plane operation against your subscription in the activity log: who started a VM, who changed a network security group, who rotated a key, who deleted a resource group. That log is your primary forensic record when something goes wrong. The problem is that the activity log only retains events for 90 days by default, and it stays inside Azure with no export to anywhere you control. If an attacker gets in, or an engineer fat-fingers a deletion, 90 days of volatile retention is rarely enough to reconstruct what happened.

The No Azure Monitor Log Profile check (monitor_nologprofile) catches subscriptions where no mechanism exists to route those activity log events out to durable storage. This post explains what the check looks for, why the gap matters, and how to close it for good.


What this check detects

The check inspects a subscription and reports a failure when no Azure Monitor activity log profile is configured. A log profile defines three things:

  • Where activity log events are sent: a storage account, an Event Hub, or both.
  • Which categories of events to capture, such as Write, Delete, and Action.
  • How long to retain events when archived to a storage account.

If a subscription has zero log profiles, the activity log is never exported. It exists only in the rolling 90-day Azure-managed buffer, and once those 90 days pass the events are gone.

Note: Log profiles are the classic, subscription-wide way to export activity logs. Microsoft has since introduced diagnostic settings for activity logs, which is the modern, recommended approach. Both satisfy the intent of this check. We cover both below, and we recommend new deployments use diagnostic settings.


Why it matters

The activity log is the closest thing Azure gives you to a subscription-level audit trail. Without exporting it, you are exposed in a few concrete ways.

You cannot investigate an incident past 90 days

Breaches are often discovered months after the initial compromise. The 2024 incident reports across the industry repeatedly show dwell times measured in weeks or months. If your activity log only holds 90 days and the attacker first gained access 100 days ago, the records of their initial moves no longer exist. You are investigating a crime scene that has already been cleaned.

Attackers can outlast your retention

A patient attacker who understands Azure knows the default retention. They can establish persistence, go quiet, and wait. By the time they act again, the evidence of how they got in has aged out. Exporting logs to immutable storage breaks that strategy.

Warning: If an attacker gains Owner or Contributor on your subscription, they can delete a log profile or diagnostic setting and stop the export. Lock down who can modify monitoring configuration, and alert on changes to it. Export to a storage account in a separate, tightly controlled subscription where the operational team has no delete rights.

Compliance frameworks expect it

CIS Microsoft Azure Foundations Benchmark, PCI DSS, SOC 2, and ISO 27001 all require retained audit logging of administrative actions. An auditor asking for proof of who changed a firewall rule six months ago will not accept "the log expired." A missing log profile is a frequent finding in cloud compliance assessments.

You lose alerting and correlation potential

Activity logs sitting unexported cannot easily feed a SIEM. Routing them to a Log Analytics workspace or Event Hub lets you run KQL queries, build alert rules, and correlate control-plane events with sign-in logs and resource telemetry. Without the export, that capability does not exist.


How to fix it

You have two valid paths. Pick diagnostic settings for anything new. Use the legacy log profile only if you have tooling that still depends on it.

Option A: Diagnostic setting for the activity log (recommended)

First create or identify a destination. A Log Analytics workspace is the most useful target because it makes the logs queryable.

# Create a resource group and Log Analytics workspace
az group create \
  --name rg-monitoring \
  --location eastus

az monitor log-analytics workspace create \
  --resource-group rg-monitoring \
  --workspace-name law-activitylogs \
  --location eastus

Grab the workspace resource ID and your subscription ID, then create the subscription-level diagnostic setting.

WORKSPACE_ID=$(az monitor log-analytics workspace show \
  --resource-group rg-monitoring \
  --workspace-name law-activitylogs \
  --query id -o tsv)

SUB_ID=$(az account show --query id -o tsv)

az monitor diagnostic-settings subscription create \
  --name "activity-log-to-law" \
  --location eastus \
  --workspace "$WORKSPACE_ID" \
  --logs '[
    {"category": "Administrative", "enabled": true},
    {"category": "Security", "enabled": true},
    {"category": "ServiceHealth", "enabled": true},
    {"category": "Alert", "enabled": true},
    {"category": "Recommendation", "enabled": true},
    {"category": "Policy", "enabled": true},
    {"category": "Autoscale", "enabled": true},
    {"category": "ResourceHealth", "enabled": true}
  ]'

Tip: Send the same activity log to both a Log Analytics workspace (for querying and alerting) and an Event Hub (to forward into an external SIEM such as Splunk or Sentinel data connectors). You can specify --workspace and --event-hub in the same command.

Option B: Legacy log profile to a storage account

If you specifically need a log profile, this archives the activity log to a storage account with a defined retention period.

# Create a storage account for archived logs
az storage account create \
  --name activitylogarchive$RANDOM \
  --resource-group rg-monitoring \
  --location eastus \
  --sku Standard_LRS \
  --kind StorageV2

# Create the log profile (covers all regions)
az monitor log-profiles create \
  --name "default" \
  --location null \
  --locations eastus westus northeurope global \
  --categories "Write" "Delete" "Action" \
  --days 365 \
  --enabled true \
  --storage-account-id "/subscriptions/$SUB_ID/resourceGroups/rg-monitoring/providers/Microsoft.Storage/storageAccounts/"

Warning: Each subscription can have only one log profile. If a misconfigured profile already exists, the create command fails. Inspect it with az monitor log-profiles list before changing anything, and remember that deleting and recreating leaves a gap in coverage.

Console steps

  1. Open the Azure portal and go to Monitor.
  2. Select Activity log in the left menu, then Export Activity Logs at the top.
  3. Confirm the correct subscription is selected, then click Add diagnostic setting.
  4. Name the setting, tick the log categories you want (at minimum Administrative and Security).
  5. Choose a destination: a Log Analytics workspace, a storage account for archive, or an Event Hub.
  6. Click Save.

Verify the fix

# Confirm a subscription diagnostic setting exists
az monitor diagnostic-settings subscription list -o table

# Or, for the legacy log profile
az monitor log-profiles list -o table

If either returns a configured entry pointing at a real destination, the check will pass on the next scan.


How to prevent it from happening again

Fixing one subscription by hand does not scale. Bake the export into your provisioning process and enforce it with policy.

Enforce with Azure Policy

Azure ships a built-in policy definition that deploys an activity log diagnostic setting to a Log Analytics workspace if one is missing. Assign it at the management group level so every current and future subscription inherits it.

# Find the built-in policy
az policy definition list \
  --query "[?contains(displayName, 'activity log') && policyType=='BuiltIn'].{name:name, display:displayName}" \
  -o table

# Assign a deployIfNotExists policy at a management group scope
az policy assignment create \
  --name "deploy-activity-log-diag" \
  --display-name "Deploy activity log to Log Analytics" \
  --policy "" \
  --scope "/providers/Microsoft.Management/managementGroups/" \
  --location eastus \
  --mi-system-assigned \
  --role "Contributor" \
  --identity-scope "/providers/Microsoft.Management/managementGroups/"

With a deployIfNotExists effect, Azure remediates non-compliant subscriptions automatically, so a new subscription is covered shortly after it appears.

Define it in infrastructure as code

If you manage subscriptions through Terraform, declare the diagnostic setting alongside the workspace so it is version controlled and reviewable.

resource "azurerm_log_analytics_workspace" "activity" {
  name                = "law-activitylogs"
  location            = "eastus"
  resource_group_name = azurerm_resource_group.monitoring.name
  sku                 = "PerGB2018"
  retention_in_days   = 90
}

resource "azurerm_monitor_diagnostic_setting" "activity_log" {
  name                       = "activity-log-to-law"
  target_resource_id         = "/subscriptions/${data.azurerm_subscription.current.subscription_id}"
  log_analytics_workspace_id = azurerm_log_analytics_workspace.activity.id

  enabled_log {
    category = "Administrative"
  }
  enabled_log {
    category = "Security"
  }
  enabled_log {
    category = "Policy"
  }
}

Gate it in CI/CD

Add a step to your pipeline that fails the build if the activity log export is missing. A simple check using the CLI works well as a guardrail before a plan is applied.

#!/usr/bin/env bash
set -euo pipefail

count=$(az monitor diagnostic-settings subscription list --query "length(value)" -o tsv)

if [ "$count" -eq 0 ]; then
  echo "FAIL: no activity log diagnostic setting on this subscription"
  exit 1
fi
echo "PASS: activity log export configured"

Tip: Run a Lensix scan on a schedule rather than relying only on pipeline checks. Policy and IaC catch issues you provision through the expected channels, but a continuous scan catches drift, manual changes, and subscriptions created outside your standard process.


Best practices

  • Centralize logs. Send activity logs from all subscriptions to a single Log Analytics workspace or a dedicated logging subscription. Cross-subscription querying beats hunting through dozens of isolated destinations.
  • Separate the storage destination. Archive to a storage account in a subscription where day-to-day operators have no delete permissions. This protects the trail even if a working subscription is compromised.
  • Enable immutability. Apply a time-based immutability policy on the storage container holding archived logs so they cannot be altered or deleted within the retention window.
  • Set retention to match compliance. Ninety days is rarely enough. Many frameworks expect one year or more. Configure retention deliberately rather than accepting defaults.
  • Alert on monitoring changes. Create an alert that fires when a diagnostic setting or log profile is deleted or modified. Tampering with logging is often an early sign of an attacker covering tracks.
  • Capture the right categories. At minimum keep Administrative and Security. Add Policy and ServiceHealth for governance and operational context.
  • Review access to logging config. Restrict who can edit Monitor settings. Treat that permission as sensitive as the data the logs protect.

A missing log profile is a small configuration gap with an outsized consequence: when you most need to know what happened, the record is simply not there. Export the activity log to durable storage, enforce it with policy, and verify it continuously. The cost is minimal, and the day you need that six-month-old audit trail, it will be the cheapest insurance you ever bought.

Fix Missing Azure Monitor Log Profile | Lensix | Lensix