Skip to content

Commit 718b9bb

Browse files
authored
Merge pull request #15042 from MartinPankraz/feature/sap-tools-readme-audit-log-smoke-test
Feature/sap tools readme audit log smoke test
2 parents 094d1fa + 126b728 commit 718b9bb

11 files changed

Lines changed: 236 additions & 12 deletions
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# SAP Security Audit Log Smoke Test — Simulate RFC Call via SAP GUI
2+
3+
This guide describes a quick, manual smoke test you can run **directly on the SAP backend** to confirm that the Security Audit Log RFC used by the agentless SAP data connector is working correctly — before raising a support ticket with Microsoft and/or SAP.
4+
5+
## Purpose
6+
7+
The agentless SAP connector (SAP Integration Suite / SAPCC connector) reads Security Audit Log data from the SAP backend via the `RSAU_API_GET_LOG_DATA` **remote-enabled** function module (RFC). If audit log data (`ABAPAuditLog`) is missing or delayed in Microsoft Sentinel, the fastest way to isolate whether the issue is on the SAP side or the connector side is to call this function module manually using SAP GUI transaction code `SE37`. If the manual call also returns no data (or errors), the issue is on the SAP side (e.g., Security Audit Log not active, no events in the time window, authorization issue, bugs in support package of the SAP Basis release) and should be investigated with SAP first. If the manual call succeeds and returns records, but data still doesn't appear in Sentinel, the issue is more likely in the connector/pipeline.
8+
9+
## Prerequisites
10+
11+
- SAP GUI access to the relevant SAP system with an account that has developer/admin authorization to run `SE37` and test function modules.
12+
- Knowledge of the SAP client (mandant) number used by the connector.
13+
14+
## Steps
15+
16+
### 1. Open the function module in SE37
17+
18+
On SAPGUI, run transaction `SE37` and enter `RSAU_API_GET_LOG_DATA` as the
19+
function module. Click **Execute** (the Test/Execute icon highlighted below).
20+
21+
![SE37 - Function Builder initial screen, RSAU_API_GET_LOG_DATA entered](media/01-se37-function-module.jpg)
22+
23+
This opens the **Test Function Module: Initial Screen**, listing the import parameters
24+
(`IS_INTERVAL`, `IT_R_MSG`, `IT_R_MANDT`, `IT_R_USER`, `IT_R_TCD`, `IT_R_REPS`,
25+
`IT_R_INSTANCE`):
26+
27+
![Test Function Module initial screen with import parameters](media/02-test-function-module-initial.jpg)
28+
29+
### 2. Set the time window (IS_INTERVAL)
30+
31+
Click on the value of `IS_INTERVAL` to edit the time window of the audit log query.
32+
Enter a narrow window to mimic the connectors behavior and avoid too large data set selections (e.g., 1 minute) in the `DAT_FROM` / `DAT_TO` / `TIM_FROM` /
33+
`TIM_TO` fields, then click the **Insert Date** (copy) button to confirm the entry.
34+
35+
> [!NOTE]
36+
> The required date format on the input field may vary based on your language settings.
37+
38+
![Editing IS_INTERVAL to a 1-minute time window](media/03-is-interval-time-window.jpg)
39+
40+
### 3. Filter by SAP client (IT_R_MANDT)
41+
42+
Back on the function module screen, edit the value of `IT_R_MANDT` to filter by your SAP
43+
client: `S = I`, `OP = EQ`, `LOW = <your client>` (e.g., `001`). Click the exit/back
44+
button to save the entry.
45+
46+
![Setting IT_R_MANDT client filter](media/04-it-r-mandt-client-filter.jpg)
47+
48+
### 4. Execute and review results
49+
50+
Click **Execute** to run the audit log query. Record the **runtime** and the **number of
51+
records returned** (`ET_LOG` entry count) — these confirm whether the SAP backend can
52+
generate and return audit log data for the requested window.
53+
54+
> [!IMPORTANT]
55+
> A runtime of more than 3 minutes for a single minute time window indicate performance issues on the SAP backend. Consult the [performance guide](https://learn.microsoft.com/azure/sentinel/sap/sap-deploy-troubleshoot#long-message-processing-times-or-message-volume-anomalies-on-sap-cloud-integration) for troubleshooting steps. Consult SAP's notes for optimized audit log retrieval.
56+
> - 3726943 - RSAU_API_GET_LOG_DATA | Dataselection only from Filesystem details
57+
> - 3407647 - RSAU_READ_LOG | Optimization of reading audit log files
58+
59+
![Result screen showing runtime](media/05-execute-result-runtime.jpg)
60+
61+
![Result screen showing export parameters, ET_LOG and ET_RETURN entry counts](media/06-execute-result-records.jpg)
62+
63+
## Before opening a support ticket
64+
65+
Use the results of this smoke test as evidence when engaging support:
66+
67+
- [ ] Security Audit Log is active and required message classes are being recorded on the SAP system for the tested time window (confirm via `RSAU_CONFIG` / `SM19` if `ET_LOG` returns 0 entries).
68+
- [ ] `IT_R_MANDT` client filter matches the client configured in the connector/destination.
69+
- [ ] Note the runtime and record count (`ET_LOG` entries) returned by the RFC call.
70+
- [ ] Check `ET_RETURN` for any warning/error messages from the function module.
71+
- [ ] If records **are** returned here but do **not** appear in Sentinel's `ABAPAuditLog` table for the same time window, the issue is likely in the connector/pipeline
72+
- [ ] If records are **not** returned here (and Security Audit Log is confirmed active), the issue is on the SAP backend side — investigate with your **SAP** Basis/Security team first. Start with SAP notes listed on the [prerequisites page on Microsoft Learn](https://learn.microsoft.com/azure/sentinel/sap/prerequisites-for-deploying-sap-continuous-threat-monitoring#sap-prerequisites-for-the-agentless-data-connector).
73+
74+
## Related
75+
76+
- [IntegrationSuite README](README.md) — connector onboarding scripts and architecture.

Solutions/SAP/Tools/IntegrationSuite/IntegrationSuiteHelpers.ps1

Lines changed: 132 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
# Shared helper functions for SAP Integration Suite Sentinel Connector scripts
33
# This module provides common functionality for Azure authentication, DCR/DCE management,
44
# and data connector operations for SAP Integration Suite integration with Microsoft Sentinel.
5+
#
6+
# NAMING CONVENTION (must match Azure portal deployed resources, downstream tooling depends on it):
7+
# Data Collection Rule : Microsoft-Sentinel-SAPCC-DCR-<first 12 chars of workspace GUID>
8+
# Data Collection Endpoint : ASI-<full workspace GUID>
9+
# Both names are derived from the Log Analytics workspace ID (customerId) and are enforced
10+
# through Get-SapccDcrName / Get-SapccDceName and Assert-SapccResourceName.
511

612
# Function to log messages with colored output
713
function Write-Log {
@@ -16,6 +22,116 @@ function Write-Log {
1622
Write-Host "[$timestamp] [$Level] $Message" -ForegroundColor $color
1723
}
1824

25+
#region SAPCC resource naming convention
26+
27+
# Prefixes and patterns for the enforced SAP Cloud Connector / Integration Suite naming convention
28+
$script:SapccDcrNamePrefix = "Microsoft-Sentinel-SAPCC-DCR-"
29+
$script:SapccDceNamePrefix = "ASI-"
30+
$script:SapccDcrNamePattern = '^Microsoft-Sentinel-SAPCC-DCR-[0-9a-f]{8}-[0-9a-f]{3}$'
31+
$script:SapccDceNamePattern = '^ASI-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
32+
33+
# Function to normalize and validate a workspace GUID (Log Analytics customerId)
34+
function Get-NormalizedWorkspaceId {
35+
param(
36+
[Parameter(Mandatory=$true)]
37+
[string]$WorkspaceId
38+
)
39+
40+
$normalized = $WorkspaceId.Trim().ToLowerInvariant()
41+
42+
$parsed = [Guid]::Empty
43+
if (-not [Guid]::TryParse($normalized, [ref]$parsed)) {
44+
Write-Log "Workspace ID '$WorkspaceId' is not a valid GUID. Cannot build SAPCC resource names." -Level "ERROR"
45+
throw "Invalid workspace ID '$WorkspaceId'. A GUID is required to enforce the SAPCC naming convention."
46+
}
47+
48+
return $parsed.ToString("D").ToLowerInvariant()
49+
}
50+
51+
# Function to build the Data Collection Rule name: Microsoft-Sentinel-SAPCC-DCR-<first 12 chars of workspace GUID>
52+
function Get-SapccDcrName {
53+
param(
54+
[Parameter(Mandatory=$true)]
55+
[string]$WorkspaceId
56+
)
57+
58+
$normalized = Get-NormalizedWorkspaceId -WorkspaceId $WorkspaceId
59+
$name = "$($script:SapccDcrNamePrefix)$($normalized.Substring(0, 12))"
60+
61+
Assert-SapccResourceName -Name $name -Type "DCR"
62+
return $name
63+
}
64+
65+
# Function to build the Data Collection Endpoint name: ASI-<full workspace GUID>
66+
function Get-SapccDceName {
67+
param(
68+
[Parameter(Mandatory=$true)]
69+
[string]$WorkspaceId
70+
)
71+
72+
$normalized = Get-NormalizedWorkspaceId -WorkspaceId $WorkspaceId
73+
$name = "$($script:SapccDceNamePrefix)$normalized"
74+
75+
Assert-SapccResourceName -Name $name -Type "DCE"
76+
return $name
77+
}
78+
79+
# Function to test a resource name against the enforced convention
80+
function Test-SapccResourceName {
81+
param(
82+
[Parameter(Mandatory=$true)]
83+
[AllowEmptyString()]
84+
[string]$Name,
85+
[Parameter(Mandatory=$true)]
86+
[ValidateSet("DCR", "DCE")]
87+
[string]$Type
88+
)
89+
90+
if ([string]::IsNullOrWhiteSpace($Name)) {
91+
return $false
92+
}
93+
94+
$pattern = if ($Type -eq "DCR") { $script:SapccDcrNamePattern } else { $script:SapccDceNamePattern }
95+
return $Name -match $pattern
96+
}
97+
98+
# Function to get the expected name format for error messages
99+
function Get-SapccExpectedNameFormat {
100+
param(
101+
[Parameter(Mandatory=$true)]
102+
[ValidateSet("DCR", "DCE")]
103+
[string]$Type
104+
)
105+
106+
if ($Type -eq "DCR") {
107+
return "Microsoft-Sentinel-SAPCC-DCR-<first 12 chars of workspace GUID> (e.g. Microsoft-Sentinel-SAPCC-DCR-befd8617-c90)"
108+
}
109+
110+
return "ASI-<full workspace GUID> (e.g. ASI-befd8617-c90d-40e8-82f4-4e79d3e4c92b)"
111+
}
112+
113+
# Function to enforce the naming convention, throwing on any deviation
114+
function Assert-SapccResourceName {
115+
param(
116+
[Parameter(Mandatory=$true)]
117+
[AllowEmptyString()]
118+
[string]$Name,
119+
[Parameter(Mandatory=$true)]
120+
[ValidateSet("DCR", "DCE")]
121+
[string]$Type
122+
)
123+
124+
if (Test-SapccResourceName -Name $Name -Type $Type) {
125+
return
126+
}
127+
128+
$expected = Get-SapccExpectedNameFormat -Type $Type
129+
Write-Log "$Type name '$Name' violates the required naming convention. Expected: $expected" -Level "ERROR"
130+
throw "$Type name '$Name' violates the required SAPCC naming convention. Expected: $expected"
131+
}
132+
133+
#endregion
134+
19135
# Function to check if Azure CLI is installed
20136
function Test-AzCli {
21137
try {
@@ -208,9 +324,9 @@ function Get-SentinelWorkspaceDetails {
208324

209325
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
210326

211-
# Extract a short ID from workspace ID for naming (first 12 chars of last GUID segment)
212-
$workspaceId = $response.properties.customerId
213-
$shortId = $workspaceId.Substring(0, [Math]::Min(12, $workspaceId.Length))
327+
# Extract a short ID from workspace ID for naming (first 12 chars of the workspace GUID)
328+
$workspaceId = Get-NormalizedWorkspaceId -WorkspaceId $response.properties.customerId
329+
$shortId = $workspaceId.Substring(0, 12)
214330

215331
Write-Log "Workspace details retrieved successfully" -Level "SUCCESS"
216332
Write-Log " Location: $($response.location)"
@@ -239,14 +355,14 @@ function Get-OrCreateSapccDataCollectionEndpoint {
239355
[Parameter(Mandatory=$true)]
240356
[string]$ResourceGroupName,
241357
[Parameter(Mandatory=$true)]
242-
[string]$WorkspaceShortId,
358+
[string]$WorkspaceId,
243359
[Parameter(Mandatory=$true)]
244360
[string]$Location
245361
)
246362

247363
try {
248-
# DCE naming convention: Microsoft-Sentinel-SAPCC-{workspace-short-id}
249-
$dceName = "Microsoft-Sentinel-SAPCC-$WorkspaceShortId"
364+
# DCE naming convention: ASI-{full workspace GUID}
365+
$dceName = Get-SapccDceName -WorkspaceId $WorkspaceId
250366

251367
Write-Log "Checking for existing Data Collection Endpoint '$dceName'..."
252368

@@ -339,6 +455,9 @@ function Get-DataCollectionEndpointById {
339455
$dceName = $DataCollectionEndpointId.Split('/')[-1]
340456

341457
Write-Log "Found DCE '$dceName'" -Level "SUCCESS"
458+
if (-not (Test-SapccResourceName -Name $dceName -Type "DCE")) {
459+
Write-Log "DCE '$dceName' does not follow the required naming convention: $(Get-SapccExpectedNameFormat -Type 'DCE'). Existing ingestion is left untouched, but downstream tooling may not recognize this resource." -Level "WARNING"
460+
}
342461
Write-Log " Logs Ingestion Endpoint: $($response.properties.logsIngestion.endpoint)"
343462

344463
return @{
@@ -416,7 +535,7 @@ function Get-OrCreateSapccDataCollectionRule {
416535
[Parameter(Mandatory=$true)]
417536
[string]$ResourceGroupName,
418537
[Parameter(Mandatory=$true)]
419-
[string]$WorkspaceShortId,
538+
[string]$WorkspaceId,
420539
[Parameter(Mandatory=$true)]
421540
[string]$WorkspaceResourceId,
422541
[Parameter(Mandatory=$false)]
@@ -426,8 +545,8 @@ function Get-OrCreateSapccDataCollectionRule {
426545
)
427546

428547
try {
429-
# DCR naming convention: Microsoft-Sentinel-SAPCC-DCR-{workspace-short-id}
430-
$dcrName = "Microsoft-Sentinel-SAPCC-DCR-$WorkspaceShortId"
548+
# DCR naming convention: Microsoft-Sentinel-SAPCC-DCR-{first 12 chars of workspace GUID}
549+
$dcrName = Get-SapccDcrName -WorkspaceId $WorkspaceId
431550

432551
Write-Log "Checking for existing Data Collection Rule '$dcrName'..."
433552

@@ -473,6 +592,10 @@ function Get-OrCreateSapccDataCollectionRule {
473592
return $null
474593
}
475594

595+
# The referenced DCE must follow the naming convention, otherwise downstream processing breaks
596+
$referencedDceName = $DataCollectionEndpointId.Split('/')[-1]
597+
Assert-SapccResourceName -Name $referencedDceName -Type "DCE"
598+
476599
# Load DCR schema from SAPCC_DCR.json
477600
$dcrProperties = Get-SapccDcrTemplate -WorkspaceResourceId $WorkspaceResourceId -DataCollectionEndpointId $DataCollectionEndpointId
478601

Solutions/SAP/Tools/IntegrationSuite/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ These standard tables integrate natively with the Microsoft Sentinel Solution fo
2626
- **CSV-based destination management**: Process multiple SAP destinations from a CSV file
2727
- **Automatic connection naming**: Connections are named `{ConnectionPrefix}-{DestinationName}`
2828
- **Shared infrastructure**: Single DCE/DCR shared across all connections
29+
- **Enforced DCE/DCR naming**: Names are derived from the Log Analytics workspace ID and validated, so they always match Azure portal deployed resources:
30+
- DCR: `Microsoft-Sentinel-SAPCC-DCR-<first 12 chars of workspace GUID>`
31+
- DCE: `ASI-<full workspace GUID>`
32+
33+
The scripts abort with a clear error if a name (or a supplied DCE reference) violates this convention, because downstream processes depend on it.
2934

3035
## Files
3136

@@ -37,6 +42,7 @@ These standard tables integrate natively with the Microsoft Sentinel Solution fo
3742
| `IntegrationSuiteHelpers.ps1` | Shared helper functions for Azure, DCR/DCE, CSV processing, and CF operations |
3843
| `SAPCC_DCR.json` | Data Collection Rule template with SAP data streams |
3944
| `destinations-sample.csv` | Sample CSV file showing expected destination format |
45+
| [`AUDIT-LOG-SMOKE-TEST.md`](AUDIT-LOG-SMOKE-TEST.md) | Manual smoke test to validate the Security Audit Log RFC on the SAP backend before raising a support ticket |
4046

4147
## Architecture
4248

Solutions/SAP/Tools/IntegrationSuite/connect-sentinel-to-integration-suite.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ if ($null -eq $workspaceDetails) {
270270
$dcrInfo = Get-OrCreateSapccDataCollectionRule `
271271
-SubscriptionId $SubscriptionId `
272272
-ResourceGroupName $ResourceGroupName `
273-
-WorkspaceShortId $workspaceDetails.ShortId `
273+
-WorkspaceId $workspaceDetails.WorkspaceId `
274274
-WorkspaceResourceId $workspaceDetails.ResourceId `
275275
-Location $workspaceDetails.Location
276276

@@ -289,7 +289,7 @@ if ($null -eq $dceInfo) {
289289
$dceInfo = Get-OrCreateSapccDataCollectionEndpoint `
290290
-SubscriptionId $SubscriptionId `
291291
-ResourceGroupName $ResourceGroupName `
292-
-WorkspaceShortId $workspaceDetails.ShortId `
292+
-WorkspaceId $workspaceDetails.WorkspaceId `
293293
-Location $workspaceDetails.Location
294294

295295
if ($null -eq $dceInfo) {
@@ -301,7 +301,7 @@ if ($null -eq $dceInfo) {
301301
$dcrInfo = Get-OrCreateSapccDataCollectionRule `
302302
-SubscriptionId $SubscriptionId `
303303
-ResourceGroupName $ResourceGroupName `
304-
-WorkspaceShortId $workspaceDetails.ShortId `
304+
-WorkspaceId $workspaceDetails.WorkspaceId `
305305
-WorkspaceResourceId $workspaceDetails.ResourceId `
306306
-DataCollectionEndpointId $dceInfo.ResourceId `
307307
-Location $workspaceDetails.Location
74.1 KB
Loading
101 KB
Loading
53.9 KB
Loading
50.4 KB
Loading
94.6 KB
Loading
46.2 KB
Loading

0 commit comments

Comments
 (0)