Audit Log Strategy (DORA / NIS2)
Generated with Claude Code
Co-Authored-By: Claude (noreply@anthropic.com)
Strategy for Azure audit log infrastructure on the TOGETHER/CCA platform. Covers Azure platform logs, Entra ID logs, and resource-level diagnostic logs. Application-level logging is already in place and documented separately.
| Field | Value |
|---|---|
| Scope | Azure platform + Entra ID + resource diagnostic logs (all subscriptions) |
| Regulatory basis | DORA (EU 2022/2554), RTS 2024/1774 Art. 12; NIS2 IR 2024/2690 (reference) |
| Subscriptions | Together-Prod, Together-Fachtest |
| Application logging | See monitoring-logging.md |
| Windows Event Logs | See windows-event-log-baseline.md |
| Server onboarding | See azure-arc-onboarding-plan.md |
Regulatory Requirements
DORA RTS 2024/1774 Article 12 — Logging
DORA applies directly to insurance undertakings. The RTS defines the technical logging requirements.
| DORA Requirement | Required Log Categories | Azure Source |
|---|---|---|
| Access control events | Sign-ins, conditional access, role assignments | Entra ID: SignInLogs, AuditLogs |
| Identity management | User/group/app creation, modification, deletion | Entra ID: AuditLogs, ProvisioningLogs |
| User activity | Resource operations, admin actions, configuration changes | Azure Activity Log (Administrative, Policy) |
| ICT anomalies | Threat detections, risky sign-ins, anomalous behavior | Entra ID: RiskyUsers, UserRiskEvents (P2) |
| ICT-related incidents | Security alerts, firewall events, intrusion attempts | Defender for Cloud, App Gateway WAF logs |
| Data access | Key/secret access, storage operations, DB queries | Key Vault AuditEvent, Storage logs, SQL audit |
| Network activity | Firewall rules, NSG events, traffic flows | App Gateway logs, NSG logs |
Additional DORA Requirements
| Requirement | Implementation | Reference |
|---|---|---|
| Tamper protection | Workspace RBAC + resource locks + optional immutable export | DORA RTS Art. 12(3) |
| Clock synchronization | w32tm (on-prem servers), Azure-managed (PaaS) | DORA RTS Art. 12(4) |
| Retention period | Risk-based; minimum 18 months (NIS2 floor), target 2 years | DORA RTS Art. 12(2), NIS2 IR 2024/2690 |
| Incident reporting | 4h initial notification, 72h intermediate report, 1 month final | DORA Art. 19 |
NIS2 note: Insurance companies are carved out of NIS2 in favor of DORA. However, the NIS2 Implementing Regulation (EU 2024/2690) establishes an 18-month minimum retention period that serves as a practical floor for all regulated entities.
Current State
| Logging Layer | Status | Details |
|---|---|---|
| Application Insights (APM) | Active | All TOGETHER apps — see monitoring-logging.md |
| Structured App Logs (CLEF) | Active | Serilog to TisApplicationLogs_CL via Fluent Bit |
| IIS W3C Logs | Active | AMA/DCR to W3CIISLog |
| Windows Event Logs | Active | AMA/DCR per server role — see windows-event-log-baseline.md |
| Azure Arc Onboarding | Complete | All Fachtest + Prod servers — see azure-arc-onboarding-plan.md |
| Azure Activity Log to Log Analytics | Done | az-prod-auditTrailing (Prod), az-fachtest-auditTrailing (Fachtest) |
| Entra ID Diagnostic Logs | Done | az-entra-auditTrailing (tenant-level, routed to Prod workspace) |
| Resource Diagnostic Logs | Missing | No diagnostic settings on Azure resources |
| Azure Policy enforcement | Missing | No DINE policies for diagnostic settings |
| Log retention configuration | Missing | Default retention on all tables (30 days interactive) |
| Tamper protection | Missing | No resource locks or RBAC restrictions on workspaces |
Gap Summary
| Gap | DORA Impact | Priority |
|---|---|---|
| No diagnostic settings on Key Vaults | Secret/certificate access not auditable | Critical |
| Retention below 18 months on all tables | NIS2 minimum not met, DORA risk-based requirement unmet | Critical |
| No diagnostic settings on App Gateway | WAF/firewall events not retained or queryable | High |
| No diagnostic settings on SQL resources | SQL audit events not centralized | High |
| No diagnostic settings on NSGs | Network security events not retained | High |
| No Azure Policy enforcement | New resources deployed without logging | High |
| No tamper protection on logs | DORA Art. 12(3) non-compliance | High |
| No diagnostic settings on Storage Accounts | Blob/file access not auditable | Medium |
Target Architecture
Azure Platform Log Analytics Workspaces
---------------------------------------------- -----------------------------------------
Together-Plattform-LogAnalyticsworkspace
Activity Log (Together-Prod) ──────────────────► (Prod)
Entra ID Diagnostic Logs (tenant-level) ───────► Workspace ID: 9ee01003-d32e-4110-ab57-
1f09be580fc3
Resource Diagnostic Settings: │
Key Vaults ──────── audit ───────────────────► │ Interactive retention: 90 days
App Gateway ─────── allLogs ─────────────────► │ Total retention: 730 days (2 yrs)
SQL Servers ─────── audit ───────────────────► │
NSGs ────────────── allLogs ─────────────────► │
Storage Accounts ── allLogs ─────────────────► │
VPN Gateway ─────── allLogs ─────────────────► │
│
Azure Policy (DINE) │
Enforces diagnostic settings ────────────────► (auto-applies to new resources)
---------------------------------------------- -----------------------------------------
Fachtest-LogAnalyticsworkspace
Activity Log (Together-Fachtest) ──────────────► (Fachtest)
Workspace ID: 87f6d081-015f-436f-b58b-
Resource Diagnostic Settings: add840d4be7a
Key Vaults ──────── audit ───────────────────►
... │ Same retention policy
Workspace Mapping
| Subscription | Target Workspace | Resource Group |
|---|---|---|
| Together-Prod | Together-Plattform-LogAnalyticsworkspace | LogAnalytics-Prod |
| Together-Fachtest | Fachtest-LogAnalyticsworkspace | LogAnalytics-Fachtest |
Note: Entra ID diagnostic logs are configured at the tenant level — a single diagnostic setting covers both subscriptions. Route to the Prod workspace for centralized identity audit.
Azure Activity Log
Route the Activity Log from each subscription to the respective Log Analytics workspace. The Activity Log captures all subscription-level operations: resource creation/deletion, RBAC changes, policy evaluations, security alerts.
Configuration
| Subscription | Diagnostic Setting Name | Categories | Target Workspace | Status |
|---|---|---|---|---|
| Together-Prod | az-prod-auditTrailing | Administrative, Security, Alert, Policy | Prod workspace | Done |
| Together-Fachtest | az-fachtest-auditTrailing | Administrative, Security, Alert, Policy | Fachtest workspace | Done |
CLI Example
# Together-Prod
az monitor diagnostic-settings subscription create \
--name "diag-activitylog-to-law" \
--subscription "Together-Prod" \
--workspace "/subscriptions/<prod-sub-id>/resourceGroups/LogAnalytics-Prod/providers/Microsoft.OperationalInsights/workspaces/Together-Plattform-LogAnalyticsworkspace" \
--logs '[
{"category": "Administrative", "enabled": true},
{"category": "Security", "enabled": true},
{"category": "Alert", "enabled": true},
{"category": "Policy", "enabled": true}
]'
Repeat for Together-Fachtest with the Fachtest workspace.
Entra ID Diagnostic Logs
Entra ID logs are configured at the tenant level (not per subscription). The Azure portal retains sign-in logs for only 7 days (free) or 30 days (P1/P2). Routing to Log Analytics is required for DORA-compliant retention.
Log Categories
| Category | DORA Relevance | Priority | License |
|---|---|---|---|
| AuditLogs | Identity management, access control changes | Critical | Free / P1 / P2 |
| SignInLogs | User authentication audit trail | Critical | Free / P1 / P2 |
| NonInteractiveUserSignInLogs | Background/automated auth on behalf of users | High | P1 / P2 |
| ServicePrincipalSignInLogs | App/service principal authentication | High | P1 / P2 |
| ManagedIdentitySignInLogs | Managed identity authentication | High | P1 / P2 |
| ProvisioningLogs | User provisioning to non-Microsoft apps | Medium | P1 / P2 |
| RiskyUsers | Users flagged as at-risk | Critical | P2 only |
| UserRiskEvents | Risky sign-in event details | Critical | P2 only |
| RiskyServicePrincipals | Suspicious service principal activity | High | P2 only |
| ServicePrincipalRiskEvents | Service principal risk events | High | P2 only |
| MicrosoftGraphActivityLogs | All HTTP requests via Microsoft Graph | Medium | P1 / P2 |
Action required: Determine the current Entra ID license tier. With P1, the top 6 categories are available. With P2, all 11 categories including the risk detection logs (critical for DORA Art. 10 — anomaly detection) become available.
CLI Example
# Tenant-level Entra ID diagnostic setting
az monitor diagnostic-settings create \
--name "diag-entraid-to-law" \
--resource "/providers/Microsoft.aadiam/diagnosticSettings" \
--workspace "/subscriptions/<prod-sub-id>/resourceGroups/LogAnalytics-Prod/providers/Microsoft.OperationalInsights/workspaces/Together-Plattform-LogAnalyticsworkspace" \
--logs '[
{"category": "AuditLogs", "enabled": true},
{"category": "SignInLogs", "enabled": true},
{"category": "NonInteractiveUserSignInLogs", "enabled": true},
{"category": "ServicePrincipalSignInLogs", "enabled": true},
{"category": "ManagedIdentitySignInLogs", "enabled": true},
{"category": "ProvisioningLogs", "enabled": true},
{"category": "RiskyUsers", "enabled": true},
{"category": "UserRiskEvents", "enabled": true},
{"category": "RiskyServicePrincipals", "enabled": true},
{"category": "ServicePrincipalRiskEvents", "enabled": true},
{"category": "MicrosoftGraphActivityLogs", "enabled": true}
]'
Note: Enabling a P2-only category without the license will fail silently or produce an error. Enable only the categories matching your license tier.
Resource Diagnostic Settings
Azure has no global "enable all diagnostics" switch. Each resource type must have diagnostic settings configured individually, selecting which log categories to send and to which destination. This is the largest gap in the current setup.
Resource Inventory
| Priority | Resource Type | Resource Name(s) | Log Category Group | Target Workspace |
|---|---|---|---|---|
| Critical | Key Vault | at-tgca-tis-p-default | audit | Prod |
| Critical | Key Vault | at-tgca-tis-d-default, at-tgca-tis-v-default, at-tgca-tis-f-default, at-tgca-tis-s-default | audit | Fachtest |
| Critical | Application Gateway | TIS-PROD-CCA_Weblight-AppGw | allLogs | Prod |
| High | NSG | Per subnet (DMZ, VPN, APP, DB) | allLogs | Respective |
| High | SQL Server (IaaS) | CCA-Hosting-SQL01, CCA-Hosting-SQL02 | See note below | Prod |
| High | Storage Account | Backup storage, tisccacdnstorage | allLogs (per sub-service) | Respective |
| Medium | VPN Gateway | VPN / VNet Gateway (if deployed) | allLogs | Prod |
| Medium | Bastion Host | (if deployed) | allLogs | Respective |
| Medium | Log Analytics Workspace | Both workspaces (meta-audit) | audit | Respective |
SQL Server on VMs (IaaS): CCA-Hosting SQL Servers are IaaS VMs, not Azure SQL PaaS. Azure diagnostic settings don't apply to SQL on VMs. Instead, configure SQL Server Audit within SQL Server itself to write to a file share or Windows Event Log, which AMA can then forward. This is a separate task from Azure resource diagnostics.
Category Groups
Azure supports two category groups that simplify configuration:
| Category Group | Content | Recommended For |
|---|---|---|
audit | Security-relevant events only (access, changes, authentication) | Key Vaults, Workspaces — lower volume, compliance-focused |
allLogs | All available log categories | App Gateway, NSGs, Storage — need operational + security logs |
Using category groups is preferred over selecting individual categories because Azure automatically includes new categories as they are added.
CLI Example (Key Vault)
az monitor diagnostic-settings create \
--name "diag-to-law" \
--resource "/subscriptions/<prod-sub-id>/resourceGroups/TIS-Secrets/providers/Microsoft.KeyVault/vaults/at-tgca-tis-p-default" \
--workspace "/subscriptions/<prod-sub-id>/resourceGroups/LogAnalytics-Prod/providers/Microsoft.OperationalInsights/workspaces/Together-Plattform-LogAnalyticsworkspace" \
--logs '[{"categoryGroup": "audit", "enabled": true}]'
Retention Strategy
Log Analytics supports two retention tiers:
- Interactive (analytics) retention: Data available for KQL queries (4–730 days, default 30)
- Total retention (archive): Data available via search jobs only (up to 12 years total)
Target Retention
| Table | Content | Interactive | Total | Rationale |
|---|---|---|---|---|
AzureActivity | Subscription operations | 90 days | 730 days | Admin audit trail; 90 days free |
SigninLogs | User sign-ins | 90 days | 730 days | Authentication audit |
AADNonInteractiveUserSignInLogs | Automated sign-ins | 90 days | 730 days | Authentication audit |
AADServicePrincipalSignInLogs | Service principal sign-ins | 90 days | 730 days | Service authentication audit |
AADManagedIdentitySignInLogs | Managed identity sign-ins | 90 days | 730 days | Service authentication audit |
AuditLogs | Entra ID changes | 90 days | 730 days | Identity management audit |
AADRiskyUsers | Risky users (P2) | 90 days | 730 days | Anomaly detection |
AZKVAuditLogs | Key Vault access | 90 days | 730 days | Secret/cert access audit |
AGWAccessLogs | App Gateway access | 90 days | 730 days | WAF/firewall audit |
AGWFirewallLogs | App Gateway WAF | 90 days | 730 days | Intrusion detection |
AZNSGFlowLogs | NSG flow data | 30 days | 180 days | Network forensics (high volume) |
StorageBlobLogs | Blob access | 90 days | 730 days | Data access audit |
TisApplicationLogs_CL | Application logs | 90 days | 730 days | Application audit |
W3CIISLog | IIS access logs | 90 days | 730 days | Web access audit |
Event | Windows event logs | 90 days | 730 days | OS-level audit |
Cost note: Interactive retention beyond the free tier (31 days, or 90 days for
AzureActivity) costs ~$0.10/GB/month. Archive retention costs ~$0.02/GB/month. NSG flow logs have high volume — shorter interactive retention recommended.
CLI Example
# Set retention on a specific table
az monitor log-analytics workspace table update \
--resource-group LogAnalytics-Prod \
--workspace-name Together-Plattform-LogAnalyticsworkspace \
--name AzureActivity \
--retention-time 90 \
--total-retention-time 730
Repeat for each table in both workspaces.
Enforcement via Azure Policy
Azure Policy with DeployIfNotExists (DINE) effect automatically creates diagnostic settings on resources that lack them. This ensures new resources are never deployed without logging.
Recommended Approach
Use the built-in Azure Policy initiative: "Enable audit category group resource logging to Log Analytics". This initiative contains individual DINE policies for 100+ resource types. Each policy:
- Evaluates whether a resource has a diagnostic setting with the
auditcategory group enabled - If missing, deploys an ARM template to create one
- Automatically applies to new resources at creation time
- Requires a remediation task for existing resources
Assignment per Subscription
| Subscription | Initiative Assignment | Workspace Parameter | Managed Identity | Status |
|---|---|---|---|---|
| Together-Prod | diag-audit-to-law-prod | Prod workspace resource ID | System-assigned (Contributor) | Pending |
| Together-Fachtest | diag-audit-to-law-fachtest | Fachtest workspace resource ID | System-assigned (Contributor) | Pending |
Implementation Steps
-
Identify the initiative definition:
az policy set-definition list \
--query "[?contains(displayName, 'Enable audit category group resource logging to Log Analytics')].[name, displayName]" \
-o table -
Assign at subscription scope:
az policy assignment create \
--name "diag-audit-to-law-prod" \
--display-name "Audit logs to Log Analytics (Prod)" \
--policy-set-definition "<initiative-definition-id>" \
--scope "/subscriptions/<prod-sub-id>" \
--params '{"logAnalytics": {"value": "/subscriptions/<prod-sub-id>/resourceGroups/LogAnalytics-Prod/providers/Microsoft.OperationalInsights/workspaces/Together-Plattform-LogAnalyticsworkspace"}}' \
--mi-system-assigned \
--location westeurope -
Grant Contributor role to managed identity:
az role assignment create \
--assignee-object-id "<managed-identity-principal-id>" \
--role "Contributor" \
--scope "/subscriptions/<prod-sub-id>" -
Trigger compliance evaluation:
az policy state trigger-scan --subscription "<prod-sub-id>" -
Create remediation tasks for existing resources:
az policy remediation create \
--name "remediate-keyvault-diag" \
--policy-assignment "diag-audit-to-law-prod" \
--definition-reference-id "<keyvault-policy-reference-id>" \
--resource-discovery-mode ReEvaluateCompliance -
Verify compliance:
az policy state summarize \
--subscription "<prod-sub-id>" \
--policy-assignment "diag-audit-to-law-prod" \
-o table
Important: DINE policies only auto-deploy on new resources. For existing resources, you must run remediation tasks (step 5) — one per resource type within the initiative.
Tamper Protection and Clock Synchronization
Tamper Protection
DORA RTS Art. 12(3) requires logs to be protected against tampering, deletion, and unauthorized access.
| Measure | Scope | Implementation | Priority |
|---|---|---|---|
| Workspace RBAC | Both workspaces | Restrict Log Analytics Contributor to a dedicated security group; resource owners should not be able to modify/delete logs | Critical |
| Resource Lock | Both workspaces | Apply CanNotDelete lock to prevent accidental deletion | Critical |
| Table-level RBAC | Sensitive tables | Use table-level access control for SigninLogs, AuditLogs if needed | Medium |
| Immutable export | Long-term archive | Export critical tables to Storage Account with immutability policies (WORM) | Optional (Phase 3+) |
# Apply CanNotDelete lock to Prod workspace
az lock create \
--name "do-not-delete" \
--lock-type CanNotDelete \
--resource-group LogAnalytics-Prod \
--resource-name Together-Plattform-LogAnalyticsworkspace \
--resource-type Microsoft.OperationalInsights/workspaces
Clock Synchronization
DORA RTS Art. 12(4) requires clock synchronization against a documented reliable time source.
| Environment | Method | Time Source | Status |
|---|---|---|---|
| On-prem servers (Arc-connected) | Windows Time Service (w32tm) | Domain Controllers (NTP hierarchy) | Verify |
| Azure PaaS resources | Azure-managed | Microsoft NTP infrastructure | Automatic |
| CCA-Hosting VMs | Windows Time Service | Azure time sync (VMICTimeProvider) | Verify |
Verification: check
w32tm /query /statuson all servers. For Arc-connected servers, this can be done remotely via Azure Arc Run Command.
Implementation Roadmap
Phase 1 — Activity Log + Entra ID (Week 1–2)
| Task | Scope | Status |
|---|---|---|
| Create Activity Log diagnostic setting | Together-Prod | Done — az-prod-auditTrailing |
| Create Activity Log diagnostic setting | Together-Fachtest | Done — az-fachtest-auditTrailing |
| Create Entra ID diagnostic setting (tenant-level) | All categories matching license tier | Done — az-entra-auditTrailing |
| Verify Activity Log data in Prod workspace | KQL query | Pending |
| Verify Entra ID data in Prod workspace | KQL query | Pending |
Phase 2 — Resource Diagnostic Settings (Week 3–4)
| Task | Resource | Status |
|---|---|---|
Diagnostic setting: Key Vault at-tgca-tis-p-default | Prod | Pending |
Diagnostic setting: Key Vault at-tgca-tis-f-default | Fachtest | Pending |
Diagnostic setting: Key Vault at-tgca-tis-d-default | Fachtest | Pending |
Diagnostic setting: Key Vault at-tgca-tis-v-default | Fachtest | Pending |
Diagnostic setting: Key Vault at-tgca-tis-s-default | Fachtest | Pending |
| Diagnostic setting: Application Gateway | Prod | Pending |
| Diagnostic setting: NSGs (all subnets) | Both environments | Pending |
| Diagnostic setting: Storage Accounts | Both environments | Pending |
| Verify Key Vault audit logs in workspace | KQL query | Pending |
| Verify App Gateway logs in workspace | KQL query | Pending |
Phase 3 — Azure Policy (Week 5–6)
| Task | Scope | Status |
|---|---|---|
| Assign built-in audit initiative | Together-Prod | Pending |
| Assign built-in audit initiative | Together-Fachtest | Pending |
| Grant managed identity Contributor role | Both subscriptions | Pending |
| Run remediation tasks for existing resources | Both subscriptions | Pending |
| Verify policy compliance | Both subscriptions | Pending |
Phase 4 — Retention Configuration (Week 7)
| Task | Scope | Status |
|---|---|---|
| Set retention on all tables in Prod workspace | 90 days interactive, 730 days total | Pending |
| Set retention on all tables in Fachtest workspace | 90 days interactive, 730 days total | Pending |
| Verify retention settings | CLI check | Pending |
Phase 5 — Tamper Protection (Week 8)
| Task | Scope | Status |
|---|---|---|
| Apply CanNotDelete lock to Prod workspace | Prod | Pending |
| Apply CanNotDelete lock to Fachtest workspace | Fachtest | Pending |
| Review workspace RBAC — restrict Log Analytics Contributor | Both workspaces | Pending |
| Verify clock synchronization on all servers | All Arc-connected servers | Pending |
Phase 6 — Verification (Week 9–10)
| Task | Scope | Status |
|---|---|---|
| Run all verification queries (see below) | Both workspaces | Pending |
| Document compliance status | This document | Pending |
| Review open questions | All stakeholders | Pending |
Verification
Activity Log
AzureActivity
| where TimeGenerated > ago(24h)
| summarize count() by CategoryValue
| order by count_ desc
Entra ID Sign-In Logs
SigninLogs
| where TimeGenerated > ago(24h)
| summarize count() by ResultType
| order by count_ desc
Key Vault Audit Logs
AZKVAuditLogs
| where TimeGenerated > ago(24h)
| summarize count() by OperationName
| order by count_ desc
Application Gateway Access Logs
AGWAccessLogs
| where TimeGenerated > ago(24h)
| summarize count() by RuleName
| order by count_ desc
Policy Compliance Check
az policy state summarize \
--subscription "<prod-sub-id>" \
--policy-assignment "diag-audit-to-law-prod" \
--query "policyAssignments[0].{compliant: results.resourceDetails[?complianceState=='compliant'].count | [0], nonCompliant: results.resourceDetails[?complianceState=='noncompliant'].count | [0]}"
Retention Verification
# Check retention on key tables
for table in AzureActivity SigninLogs AuditLogs AZKVAuditLogs TisApplicationLogs_CL W3CIISLog Event; do
echo "--- $table ---"
az monitor log-analytics workspace table show \
--resource-group LogAnalytics-Prod \
--workspace-name Together-Plattform-LogAnalyticsworkspace \
--name "$table" \
--query "{table: name, retention: retentionInDays, totalRetention: totalRetentionInDays}" \
-o table 2>/dev/null || echo "Table not yet provisioned"
done
Clock Synchronization (on Arc-connected servers)
Event
| where TimeGenerated > ago(7d)
| where Source == "Microsoft-Windows-Time-Service"
| where EventID in (35, 36, 37, 134)
| project TimeGenerated, Computer, EventID, RenderedDescription
Open Questions
| Question | Context | Needed By |
|---|---|---|
| Entra ID license tier (P1 vs P2)? | Determines whether risk detection logs (RiskyUsers, UserRiskEvents) are available. P2 is strongly recommended for DORA Art. 10 (anomaly detection). | Phase 1 |
| Domain Controllers (TISDC01, TISDC02) — include in Arc onboarding? | DC security logs are critical for identity audit. Open question from azure-arc-onboarding-plan.md. | Phase 2 |
| TISWAP01 + TISADFS01 — assign DCRs? | Currently Arc-onboarded with AMA but no DCR applied. ADFS logs are particularly important for authentication audit. | Phase 2 |
| SQL Server on-VM audit configuration? | CCA-Hosting SQL Servers (SQL01, SQL02) are IaaS — need SQL Server Audit configured within the engine, not via Azure diagnostic settings. | Phase 2 |
| Microsoft Sentinel evaluation? | SIEM/SOAR capabilities for automated threat detection, incident response, and DORA compliance workbooks. Budget approval required. | After Phase 6 |
| Immutable blob export for long-term archive? | DORA tamper protection — workspace RBAC may be sufficient, but immutable storage export provides a stronger guarantee. Cost/complexity trade-off. | Phase 5 |