ownerlens 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +183 -0
- package/README.md +209 -0
- package/bin/ownerlens.js +92 -0
- package/dist/assets/index-B9aAYpVl.css +1 -0
- package/dist/assets/index-BcwLk2bx.js +10 -0
- package/dist/index.html +13 -0
- package/package.json +73 -0
- package/src/App.tsx +18 -0
- package/src/components/azure/AzureComponent.test.tsx +625 -0
- package/src/components/azure/AzureComponent.tsx +189 -0
- package/src/components/azure/AzureRbacComponent.tsx +104 -0
- package/src/components/azure/ClosableAzureTab.tsx +42 -0
- package/src/components/azure/EntraPermissionsComponent.tsx +194 -0
- package/src/components/azure/ManagedIdentityComponent.test.tsx +324 -0
- package/src/components/azure/ManagedIdentityComponent.tsx +141 -0
- package/src/components/azure/ResourceGroupComponent.tsx +157 -0
- package/src/components/azure/ServicePrincipalComponent.test.tsx +457 -0
- package/src/components/azure/ServicePrincipalComponent.tsx +155 -0
- package/src/components/azure/ServicePrincipalFieldRenderers.tsx +140 -0
- package/src/components/azure/ZtaComponent.test.tsx +267 -0
- package/src/components/azure/ZtaComponent.tsx +276 -0
- package/src/components/azure/ZtaRemediationBadge.tsx +70 -0
- package/src/components/azure/api.ts +216 -0
- package/src/components/azure/azureReportConfig.ts +247 -0
- package/src/core/azure/azureRbac.ts +70 -0
- package/src/core/azure/entra/index.ts +1 -0
- package/src/core/azure/entra/managedIdentity.ts +21 -0
- package/src/core/azure/entra/servicePrincipal.ts +34 -0
- package/src/core/azure/entra/types.ts +56 -0
- package/src/core/azure/identityEnrichment.ts +65 -0
- package/src/core/azure/resources.ts +141 -0
- package/src/core/azure/ztaReport.ts +58 -0
- package/src/core/config.ts +39 -0
- package/src/core/ownership/OwnershipTarget.ts +32 -0
- package/src/core/ownership/resolveOwner.ts +5 -0
- package/src/core/ownership/types.ts +14 -0
- package/src/core/risk/types.ts +1 -0
- package/src/core/runtime/index.ts +1 -0
- package/src/core/runtime/localSnapshotFiles.ts +74 -0
- package/src/core/runtime/rest.ts +61 -0
- package/src/lib/searchFilterUtils.ts +17 -0
- package/src/lib/utils.ts +48 -0
- package/src/main.tsx +10 -0
- package/src/providers/azure/identities/azureIdentityTypes.ts +1 -0
- package/src/providers/azure/identities/buildAzureManagedIdentityAssignmentIndex.test.ts +32 -0
- package/src/providers/azure/identities/buildAzureManagedIdentityAssignmentIndex.ts +35 -0
- package/src/providers/azure/identities/userAssignedIdentityAssignments.ts +52 -0
- package/src/providers/azure/inputTransferObject/entra/EntraAppRoleAssignment.ts +10 -0
- package/src/providers/azure/inputTransferObject/entra/EntraApplication.ts +27 -0
- package/src/providers/azure/inputTransferObject/entra/EntraOAuth2PermissionGrant.ts +8 -0
- package/src/providers/azure/inputTransferObject/entra/EntraServicePrincipal.ts +43 -0
- package/src/providers/azure/inputTransferObject/entra/EntraSnapshot.ts +13 -0
- package/src/providers/azure/inputTransferObject/entra/EntraSnapshotMeta.ts +12 -0
- package/src/providers/azure/inputTransferObject/resources/AzureActivityLog.ts +1 -0
- package/src/providers/azure/inputTransferObject/resources/AzureResource.ts +1 -0
- package/src/providers/azure/inputTransferObject/resources/AzureResourceGroup.ts +1 -0
- package/src/providers/azure/inputTransferObject/resources/AzureRoleAssignment.ts +1 -0
- package/src/providers/azure/inputTransferObject/resources/AzureSnapshot.ts +1 -0
- package/src/providers/azure/inputTransferObject/resources/AzureSnapshotMeta.ts +1 -0
- package/src/providers/azure/inputTransferObject/resources/AzureSubscription.ts +1 -0
- package/src/providers/azure/inputTransferObject/resources/AzureUserAssignedManagedIdentity.ts +1 -0
- package/src/providers/azure/ownership/azureActivityOwnershipEvidence.ts +60 -0
- package/src/providers/azure/ownership/azureOwnerReportTypes.ts +13 -0
- package/src/providers/azure/ownership/azureOwnershipConfig.ts +21 -0
- package/src/providers/azure/ownership/azureOwnershipTypes.ts +46 -0
- package/src/providers/azure/ownership/buildAzureOwnershipReport.test.ts +99 -0
- package/src/providers/azure/ownership/buildAzureOwnershipReport.ts +90 -0
- package/src/providers/azure/ownership/buildAzureOwnershipTargets.test.ts +87 -0
- package/src/providers/azure/ownership/buildAzureOwnershipTargets.ts +42 -0
- package/src/providers/azure/ownership/resolveAzureOwner.ts +146 -0
- package/src/providers/azure/runtime/DisabledEvidenceStore.ts +34 -0
- package/src/providers/azure/runtime/EnrichmentService.ts +35 -0
- package/src/providers/azure/runtime/LocalReportRuntime.test.ts +2318 -0
- package/src/providers/azure/runtime/LocalReportRuntime.ts +302 -0
- package/src/providers/azure/runtime/RuntimeHost.ts +60 -0
- package/src/providers/azure/runtime/SnapshotImporter.ts +44 -0
- package/src/providers/azure/runtime/enrichment/azureIdentityEnrichment.ts +523 -0
- package/src/providers/azure/runtime/enrichment/azureScopeClassifier.ts +30 -0
- package/src/providers/azure/runtime/enrichment/evaluateAzureRoleAssignmentRisk.ts +88 -0
- package/src/providers/azure/runtime/entra/EntraCollectionQueryService.ts +307 -0
- package/src/providers/azure/runtime/entra/LocalEntraReportRuntime.ts +227 -0
- package/src/providers/azure/runtime/entra/appRoleAssignmentsTable.ts +52 -0
- package/src/providers/azure/runtime/entra/applicationsTable.ts +175 -0
- package/src/providers/azure/runtime/entra/entraServicePrincipalMapper.ts +63 -0
- package/src/providers/azure/runtime/entra/localReportRuntimeRest.ts +41 -0
- package/src/providers/azure/runtime/entra/oauth2PermissionGrantsTable.ts +48 -0
- package/src/providers/azure/runtime/entra/principalProjection.ts +173 -0
- package/src/providers/azure/runtime/entra/servicePrincipalsTable.ts +149 -0
- package/src/providers/azure/runtime/entra/snapshotMetadataTable.ts +18 -0
- package/src/providers/azure/runtime/entra/snapshotStore.ts +102 -0
- package/src/providers/azure/runtime/localReportCollections.ts +101 -0
- package/src/providers/azure/runtime/localReportRuntimeRest.ts +71 -0
- package/src/providers/azure/runtime/resources/AzureResourcesCollectionQueryService.ts +145 -0
- package/src/providers/azure/runtime/resources/LocalAzureResourcesReportRuntime.ts +114 -0
- package/src/providers/azure/runtime/resources/disabledOwnerEvidenceTable.ts +60 -0
- package/src/providers/azure/runtime/resources/localReportRuntimeRest.ts +81 -0
- package/src/providers/azure/runtime/resources/resourceGroupOwnership.ts +90 -0
- package/src/providers/azure/runtime/resources/snapshotMetadataTable.ts +19 -0
- package/src/providers/azure/runtime/resources/snapshotStore.ts +128 -0
- package/src/providers/azure/runtime/resources/tables.ts +441 -0
- package/src/providers/azure/runtime/runtimeRestQuery.ts +46 -0
- package/src/providers/azure/runtime/runtimeSqlSchema.ts +357 -0
- package/src/providers/azure/runtime/zta/Discovery.ts +141 -0
- package/src/providers/azure/runtime/zta/LocalZeroTrustAssessmentReportRuntime.ts +86 -0
- package/src/providers/azure/runtime/zta/ZeroTrustAssessmentQueryService.ts +124 -0
- package/src/providers/azure/runtime/zta/localReportRuntimeRest.ts +15 -0
- package/src/providers/azure/runtime/zta/snapshotMetadataTable.ts +77 -0
- package/src/providers/azure/runtime/zta/snapshotStore.ts +112 -0
- package/src/providers/azure/runtime/zta/tables.ts +361 -0
- package/src/providers/azure/runtime/zta/types.ts +7 -0
- package/src/providers/azure/runtime/zta/ztaReportMapper.ts +12 -0
- package/src/report/applyCollectionControls.ts +289 -0
- package/src/report/buildCollectionColumns.tsx +38 -0
- package/src/report/components/ConfidenceBadge.tsx +10 -0
- package/src/report/components/EvidenceList.test.ts +25 -0
- package/src/report/components/EvidenceList.tsx +52 -0
- package/src/report/components/GenericTable.tsx +373 -0
- package/src/report/components/PermissionRiskBadge.tsx +19 -0
- package/src/report/components/reportTableControls.test.ts +175 -0
- package/src/report/components/reportTableControls.tsx +483 -0
- package/src/report/components/ui/badge.tsx +35 -0
- package/src/report/components/ui/button.tsx +38 -0
- package/src/report/components/ui/card.tsx +23 -0
- package/src/report/components/ui/input.tsx +15 -0
- package/src/report/components/ui/table.tsx +44 -0
- package/src/report/components/ui/tabs.tsx +29 -0
- package/src/report/export/csv.ts +34 -0
- package/src/report/ownerManualPrecheck.test.ts +137 -0
- package/src/report/ownerManualPrecheck.ts +132 -0
- package/src/report/reportArchitecture.test.ts +125 -0
- package/src/report/reportTypes.ts +54 -0
- package/src/report/reportValueRenderers.tsx +54 -0
- package/src/report/runtimeCollectionQuery.ts +23 -0
- package/src/report/types.ts +14 -0
- package/src/styles.css +43 -0
- package/tools/README.md +108 -0
- package/tools/azure-activity-check.ps1 +164 -0
- package/tools/collect-azure.ps1 +54 -0
- package/tools/collect-entra.ps1 +47 -0
- package/tools/collect-scripts.test.ts +22 -0
- package/tools/prepare-entra-snapshot.ps1 +403 -0
- package/tools/prepare-entra-snapshot.test.ts +14 -0
- package/tools/prepare-resource-snapshot.ps1 +345 -0
- package/vite.config.ts +23 -0
package/tools/README.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# OwnerLens Tools
|
|
2
|
+
|
|
3
|
+
PowerShell scripts in this directory create the JSON snapshot files consumed by the OwnerLens app.
|
|
4
|
+
|
|
5
|
+
## Core Files
|
|
6
|
+
|
|
7
|
+
- `prepare-resource-snapshot.ps1` creates the Azure resource snapshot used by the app. It exports subscriptions, resource groups, resources, managed identities, role assignments, and optional Azure Monitor activity logs.
|
|
8
|
+
- `prepare-entra-snapshot.ps1` creates the Entra snapshot used by the app. It exports service principals, application registrations, and groups so ownership and identity relationships can be resolved.
|
|
9
|
+
|
|
10
|
+
Run these commands from the repository root so the default output paths write into `.\data`.
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
- PowerShell 7 or Windows PowerShell
|
|
15
|
+
- Azure PowerShell modules:
|
|
16
|
+
|
|
17
|
+
```powershell
|
|
18
|
+
Install-Module Az -Scope CurrentUser
|
|
19
|
+
Install-Module Az.ManagedServiceIdentity -Scope CurrentUser
|
|
20
|
+
Install-Module Microsoft.Graph -Scope CurrentUser
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If `Invoke-AzRestMethod` is missing, update `Az.Accounts`:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
Update-Module Az.Accounts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Sign In
|
|
30
|
+
|
|
31
|
+
Sign in to Azure before creating the resource snapshot:
|
|
32
|
+
|
|
33
|
+
```powershell
|
|
34
|
+
Connect-AzAccount
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Sign in to Microsoft Graph before creating the Entra snapshot:
|
|
38
|
+
|
|
39
|
+
```powershell
|
|
40
|
+
Connect-MgGraph -TenantId "<tenant-id>" -Scopes "Application.Read.All","Group.Read.All","Directory.Read.All"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Create Snapshots
|
|
44
|
+
|
|
45
|
+
Create the Azure resource snapshot:
|
|
46
|
+
|
|
47
|
+
```powershell
|
|
48
|
+
.\tools\collect-azure.ps1
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
By default this writes `.\data\snapshot.json`, using the current Azure subscription and the last 90 days of activity logs.
|
|
52
|
+
|
|
53
|
+
Common resource snapshot options:
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
.\tools\collect-azure.ps1 -SubscriptionIds "sub-id-1,sub-id-2"
|
|
57
|
+
.\tools\collect-azure.ps1 -OutputPath ".\data\snapshot-prod.json"
|
|
58
|
+
.\tools\collect-azure.ps1 -ActivityDays 30 -MaxActivityRecords 5000
|
|
59
|
+
.\tools\collect-azure.ps1 -SkipAuditLogsExport
|
|
60
|
+
.\tools\collect-azure.ps1 -ExpandResourceProperties
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Resource property expansion is disabled by default because OwnerLens reads the standard resource fields plus identity data from the resource list response. Use `-ExpandResourceProperties` only when debugging or when you need Azure's additional expanded metadata in a raw snapshot.
|
|
64
|
+
|
|
65
|
+
Create the Entra snapshot:
|
|
66
|
+
|
|
67
|
+
```powershell
|
|
68
|
+
.\tools\collect-entra.ps1
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
By default this writes `.\data\entra-snapshot.json`.
|
|
72
|
+
|
|
73
|
+
Common Entra snapshot option:
|
|
74
|
+
|
|
75
|
+
```powershell
|
|
76
|
+
.\tools\collect-entra.ps1 -TenantId "<tenant-id>"
|
|
77
|
+
.\tools\collect-entra.ps1 -OutputPath ".\data\entra-snapshot-prod.json"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
After both files exist, start the app with `npm run dev` and refresh the browser.
|
|
81
|
+
|
|
82
|
+
The same collectors are available through npm scripts:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm run collect:azure -- -SubscriptionIds "sub-id-1,sub-id-2"
|
|
86
|
+
npm run collect:entra -- -TenantId "<tenant-id>"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
After publishing the package, the equivalent `npx` commands are:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx ownerlens collect:azure -SubscriptionIds "sub-id-1,sub-id-2"
|
|
93
|
+
npx ownerlens collect:entra -TenantId "<tenant-id>"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Scripts
|
|
97
|
+
|
|
98
|
+
- `collect-azure.ps1` signs in when needed, then calls `prepare-resource-snapshot.ps1`.
|
|
99
|
+
- `collect-entra.ps1` signs in when needed, then calls `prepare-entra-snapshot.ps1`.
|
|
100
|
+
- `prepare-resource-snapshot.ps1` exports Azure subscriptions, resource groups, resources, user-assigned managed identities, role assignments, and optional Azure Monitor activity logs.
|
|
101
|
+
- `prepare-entra-snapshot.ps1` exports Entra service principals, application registrations, and groups.
|
|
102
|
+
- `azure-activity-check.ps1` is a helper loaded by `prepare-resource-snapshot.ps1`; it is not usually run directly.
|
|
103
|
+
|
|
104
|
+
## Notes
|
|
105
|
+
|
|
106
|
+
- Snapshot files can contain tenant, subscription, resource, identity, application registration, group, credential metadata, and activity-log metadata. Review them before sharing.
|
|
107
|
+
- The app discovers files in `.\data` whose names end with `snapshot.json`, such as `snapshot.json`, `entra-snapshot.json`, or `snapshot-prod.json`.
|
|
108
|
+
- If scripts fail with a missing connection error, run the relevant sign-in command again and retry.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
if (-not $script:AzureActivityLogCache) {
|
|
2
|
+
$script:AzureActivityLogCache = @{}
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function Get-ActivityLogValue {
|
|
6
|
+
param(
|
|
7
|
+
[object]$Object,
|
|
8
|
+
[string]$PropertyName
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
if (-not $Object) {
|
|
12
|
+
return $null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
$property = $Object.PSObject.Properties[$PropertyName]
|
|
16
|
+
if (-not $property) {
|
|
17
|
+
return $null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return $property.Value
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function Get-ActivityLogField {
|
|
24
|
+
param(
|
|
25
|
+
[object]$Entry,
|
|
26
|
+
[string]$PropertyName
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
$value = Get-ActivityLogValue $Entry $PropertyName
|
|
30
|
+
if ($null -ne $value) {
|
|
31
|
+
return $value
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
$properties = Get-ActivityLogValue $Entry "properties"
|
|
35
|
+
return Get-ActivityLogValue $properties $PropertyName
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function Get-ActivityLogClaim {
|
|
39
|
+
param(
|
|
40
|
+
[object]$Claims,
|
|
41
|
+
[string[]]$ClaimNames
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
if (-not $Claims) {
|
|
45
|
+
return $null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
foreach ($claimName in $ClaimNames) {
|
|
49
|
+
$value = Get-ActivityLogValue $Claims $claimName
|
|
50
|
+
if ($null -ne $value -and -not [string]::IsNullOrWhiteSpace([string]$value)) {
|
|
51
|
+
return $value
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return $null
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function Get-ActivityLogCacheKey {
|
|
59
|
+
param(
|
|
60
|
+
[string]$SubscriptionId,
|
|
61
|
+
[datetime]$StartTime,
|
|
62
|
+
[int]$MaxRecord
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
$normalizedStartTime = $StartTime.ToUniversalTime().ToString("o")
|
|
66
|
+
return "$SubscriptionId|$normalizedStartTime|$MaxRecord"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function Get-AzureMonitorActivityLogs {
|
|
70
|
+
param(
|
|
71
|
+
[string]$SubscriptionId,
|
|
72
|
+
[datetime]$StartTime,
|
|
73
|
+
[int]$MaxRecord
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
$logs = [System.Collections.Generic.List[object]]::new()
|
|
77
|
+
if ($MaxRecord -le 0) {
|
|
78
|
+
return $logs
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
$cacheKey = Get-ActivityLogCacheKey -SubscriptionId $SubscriptionId -StartTime $StartTime -MaxRecord $MaxRecord
|
|
82
|
+
if ($script:AzureActivityLogCache.ContainsKey($cacheKey)) {
|
|
83
|
+
return $script:AzureActivityLogCache[$cacheKey]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
$endTime = Get-Date
|
|
87
|
+
$filter = "eventTimestamp ge '$($StartTime.ToUniversalTime().ToString("o"))' and eventTimestamp le '$($endTime.ToUniversalTime().ToString("o"))'"
|
|
88
|
+
$encodedFilter = [Uri]::EscapeDataString($filter)
|
|
89
|
+
$requestPath = "/subscriptions/$SubscriptionId/providers/microsoft.insights/eventtypes/management/values?api-version=2015-04-01&`$filter=$encodedFilter"
|
|
90
|
+
|
|
91
|
+
while ($requestPath -and $logs.Count -lt $MaxRecord) {
|
|
92
|
+
if ($requestPath -match "^https?://") {
|
|
93
|
+
$response = Invoke-AzRestMethod -Method GET -Uri $requestPath
|
|
94
|
+
} else {
|
|
95
|
+
$response = Invoke-AzRestMethod -Method GET -Path $requestPath
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
$content = $response.Content | ConvertFrom-Json
|
|
99
|
+
foreach ($entry in @($content.value)) {
|
|
100
|
+
if ($logs.Count -ge $MaxRecord) {
|
|
101
|
+
break
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
$operationName = Get-ActivityLogField $entry "operationName"
|
|
105
|
+
$status = Get-ActivityLogField $entry "status"
|
|
106
|
+
$subStatus = Get-ActivityLogField $entry "subStatus"
|
|
107
|
+
$category = Get-ActivityLogField $entry "category"
|
|
108
|
+
$resourceProviderName = Get-ActivityLogField $entry "resourceProviderName"
|
|
109
|
+
$resourceType = Get-ActivityLogField $entry "resourceType"
|
|
110
|
+
$authorization = Get-ActivityLogField $entry "authorization"
|
|
111
|
+
$claims = Get-ActivityLogField $entry "claims"
|
|
112
|
+
|
|
113
|
+
$logs.Add([pscustomobject]@{
|
|
114
|
+
eventTimestamp = Get-ActivityLogField $entry "eventTimestamp"
|
|
115
|
+
submissionTimestamp = Get-ActivityLogField $entry "submissionTimestamp"
|
|
116
|
+
caller = Get-ActivityLogField $entry "caller"
|
|
117
|
+
callerUserPrincipalName = Get-ActivityLogClaim $claims @(
|
|
118
|
+
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
|
|
119
|
+
"unique_name",
|
|
120
|
+
"upn",
|
|
121
|
+
"preferred_username"
|
|
122
|
+
)
|
|
123
|
+
callerName = Get-ActivityLogClaim $claims @(
|
|
124
|
+
"name",
|
|
125
|
+
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
|
|
126
|
+
)
|
|
127
|
+
callerEmail = Get-ActivityLogClaim $claims @(
|
|
128
|
+
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
|
|
129
|
+
"email",
|
|
130
|
+
"emails",
|
|
131
|
+
"preferred_username"
|
|
132
|
+
)
|
|
133
|
+
callerObjectId = Get-ActivityLogClaim $claims @(
|
|
134
|
+
"http://schemas.microsoft.com/identity/claims/objectidentifier",
|
|
135
|
+
"oid",
|
|
136
|
+
"objectidentifier"
|
|
137
|
+
)
|
|
138
|
+
callerIdentityType = Get-ActivityLogClaim $claims @("idtyp")
|
|
139
|
+
callerAppId = Get-ActivityLogClaim $claims @("appid", "azp")
|
|
140
|
+
callerIpAddress = Get-ActivityLogClaim $claims @("ipaddr")
|
|
141
|
+
callerTenantId = Get-ActivityLogClaim $claims @(
|
|
142
|
+
"http://schemas.microsoft.com/identity/claims/tenantid",
|
|
143
|
+
"tid"
|
|
144
|
+
)
|
|
145
|
+
operationName = Get-ActivityLogValue $operationName "localizedValue"
|
|
146
|
+
operationNameValue = Get-ActivityLogValue $operationName "value"
|
|
147
|
+
status = Get-ActivityLogValue $status "localizedValue"
|
|
148
|
+
subStatus = Get-ActivityLogValue $subStatus "localizedValue"
|
|
149
|
+
category = Get-ActivityLogValue $category "localizedValue"
|
|
150
|
+
resourceGroupName = Get-ActivityLogField $entry "resourceGroupName"
|
|
151
|
+
resourceId = Get-ActivityLogField $entry "resourceId"
|
|
152
|
+
resourceProviderName = Get-ActivityLogValue $resourceProviderName "localizedValue"
|
|
153
|
+
resourceType = Get-ActivityLogValue $resourceType "localizedValue"
|
|
154
|
+
authorizationAction = Get-ActivityLogValue $authorization "action"
|
|
155
|
+
authorizationScope = Get-ActivityLogValue $authorization "scope"
|
|
156
|
+
}) | Out-Null
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
$requestPath = Get-ActivityLogValue $content "nextLink"
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
$script:AzureActivityLogCache[$cacheKey] = $logs
|
|
163
|
+
return $script:AzureActivityLogCache[$cacheKey]
|
|
164
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[string]$OutputDir = ".\data",
|
|
3
|
+
[string]$OutputPath = "",
|
|
4
|
+
[int]$ActivityDays = 90,
|
|
5
|
+
[int]$MaxActivityRecords = 10000,
|
|
6
|
+
[switch]$SkipAuditLogsExport,
|
|
7
|
+
[string]$SubscriptionIds = "",
|
|
8
|
+
[switch]$ExpandResourceProperties,
|
|
9
|
+
[switch]$SkipLogin
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
$ErrorActionPreference = "Stop"
|
|
13
|
+
|
|
14
|
+
function Write-CollectProgress {
|
|
15
|
+
param([string]$Message)
|
|
16
|
+
|
|
17
|
+
$timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
|
|
18
|
+
Write-Host "[$timestamp] $Message"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
$resolvedOutputPath = $OutputPath
|
|
22
|
+
if ([string]::IsNullOrWhiteSpace($resolvedOutputPath)) {
|
|
23
|
+
$resolvedOutputPath = Join-Path $OutputDir "snapshot.json"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (-not (Get-Command Get-AzContext -ErrorAction SilentlyContinue)) {
|
|
27
|
+
throw "Az PowerShell module missing. Install: Install-Module Az -Scope CurrentUser"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
$context = Get-AzContext
|
|
31
|
+
if (-not $SkipLogin -and -not $context) {
|
|
32
|
+
Write-CollectProgress "Azure context not found. Starting Connect-AzAccount."
|
|
33
|
+
Connect-AzAccount | Out-Null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Write-CollectProgress "Collecting Azure resource snapshot"
|
|
37
|
+
Write-CollectProgress "Output path: $resolvedOutputPath"
|
|
38
|
+
|
|
39
|
+
$prepareParams = @{
|
|
40
|
+
OutputPath = $resolvedOutputPath
|
|
41
|
+
ActivityDays = $ActivityDays
|
|
42
|
+
MaxActivityRecords = $MaxActivityRecords
|
|
43
|
+
SubscriptionIds = $SubscriptionIds
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if ($SkipAuditLogsExport) {
|
|
47
|
+
$prepareParams.SkipAuditLogsExport = $true
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if ($ExpandResourceProperties) {
|
|
51
|
+
$prepareParams.ExpandResourceProperties = $true
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
& "$PSScriptRoot\prepare-resource-snapshot.ps1" @prepareParams
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[string]$OutputDir = ".\data",
|
|
3
|
+
[string]$OutputPath = "",
|
|
4
|
+
[string]$TenantId = "",
|
|
5
|
+
[string[]]$Scopes = @("Application.Read.All", "Group.Read.All", "Directory.Read.All"),
|
|
6
|
+
[switch]$SkipLogin
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
$ErrorActionPreference = "Stop"
|
|
10
|
+
|
|
11
|
+
function Write-CollectProgress {
|
|
12
|
+
param([string]$Message)
|
|
13
|
+
|
|
14
|
+
$timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
|
|
15
|
+
Write-Host "[$timestamp] $Message"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
$resolvedOutputPath = $OutputPath
|
|
19
|
+
if ([string]::IsNullOrWhiteSpace($resolvedOutputPath)) {
|
|
20
|
+
$resolvedOutputPath = Join-Path $OutputDir "entra-snapshot.json"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
Import-Module Microsoft.Graph.Authentication -ErrorAction Stop
|
|
25
|
+
} catch {
|
|
26
|
+
throw "Microsoft Graph PowerShell module missing: Microsoft.Graph.Authentication. Install: Install-Module Microsoft.Graph -Scope CurrentUser"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
$context = Get-MgContext
|
|
30
|
+
if (-not $SkipLogin -and -not $context) {
|
|
31
|
+
Write-CollectProgress "Microsoft Graph context not found. Starting Connect-MgGraph."
|
|
32
|
+
|
|
33
|
+
$connectParams = @{
|
|
34
|
+
Scopes = $Scopes
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (-not [string]::IsNullOrWhiteSpace($TenantId)) {
|
|
38
|
+
$connectParams.TenantId = $TenantId
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Connect-MgGraph @connectParams | Out-Null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Write-CollectProgress "Collecting Microsoft Entra snapshot"
|
|
45
|
+
Write-CollectProgress "Output path: $resolvedOutputPath"
|
|
46
|
+
|
|
47
|
+
& "$PSScriptRoot\prepare-entra-snapshot.ps1" -OutputPath $resolvedOutputPath
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
const packageJson = JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf8"));
|
|
5
|
+
const cli = readFileSync(join(process.cwd(), "bin/ownerlens.js"), "utf8");
|
|
6
|
+
const collectEntra = readFileSync(join(process.cwd(), "tools/collect-entra.ps1"), "utf8");
|
|
7
|
+
const collectAzure = readFileSync(join(process.cwd(), "tools/collect-azure.ps1"), "utf8");
|
|
8
|
+
|
|
9
|
+
test("package exposes OwnerLens collect commands through the npm bin", () => {
|
|
10
|
+
expect(packageJson.bin.ownerlens).toBe("./bin/ownerlens.js");
|
|
11
|
+
expect(packageJson.scripts["collect:entra"]).toBe("node ./bin/ownerlens.js collect:entra");
|
|
12
|
+
expect(packageJson.scripts["collect:azure"]).toBe("node ./bin/ownerlens.js collect:azure");
|
|
13
|
+
expect(cli).toContain('["collect:entra", "collect-entra.ps1"]');
|
|
14
|
+
expect(cli).toContain('["collect:azure", "collect-azure.ps1"]');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("collect wrappers delegate to the snapshot exporters used by the runtime", () => {
|
|
18
|
+
expect(collectEntra).toContain("prepare-entra-snapshot.ps1");
|
|
19
|
+
expect(collectEntra).toContain('Join-Path $OutputDir "entra-snapshot.json"');
|
|
20
|
+
expect(collectAzure).toContain("prepare-resource-snapshot.ps1");
|
|
21
|
+
expect(collectAzure).toContain('Join-Path $OutputDir "snapshot.json"');
|
|
22
|
+
});
|