├── .DS_Store
├── .gitignore
├── API Postman Collection
├── EASM Filter Mappings.xlsx
├── Postman.png
└── Readme.md
├── Automation
├── Create-ServiceNow-Incident-KeyVault
│ ├── Create-ServiceNow-Incident-KeyVault.json
│ └── Readme.md
├── Create-ServiceNow-Incident
│ ├── Create-ServiceNow-Incident.json
│ └── Readme.md
├── Inventory-Alerts-Email-KeyVault
│ ├── Inventory-Alerts-Email-Keyvault.json
│ └── Readme.md
├── Inventory-Alerts-Email
│ ├── Inventory-Alerts-Email.json
│ └── Readme.md
├── Inventory-Asset-Management
│ ├── Inventory-Asset-Management.json
│ └── Readme.md
├── Inventory-Assets-Download-Keyvault
│ ├── Inventory-Assets-Download-Keyvault.json
│ └── Readme.md
├── Inventory-Assets-Download
│ ├── Inventory-Assets-Download.json
│ └── Readme.md
├── MDTI-MDEASM-Integration
│ ├── MDTI-MDEASM-Integration.json
│ └── Readme.md
├── Qualys-VulnManagement-Integration
│ ├── Qualys-VulnIntegration.json
│ └── Readme.md
├── Rapid7-VulnManagement-Integration
│ ├── Rapid7-VulnIntegration.json
│ └── Readme.md
├── Readme.md
├── Tenable-VulnManagement-Integration
│ ├── Readme.md
│ └── Tenable-VulnIntegration.json
└── logic_app_logo.png
├── CODE_OF_CONDUCT.md
├── Inventory Queries
├── DefaultOpenPages.txt
├── EASM Filter Mappings.xlsx
└── Readme.md
├── Jupyter-Notebooks
├── MDEASM_PowerShell_Notebook.dib
├── MDEASM_Python_Notebook.ipynb
└── README.md
├── LICENSE
├── README.md
├── SECURITY.md
├── SUPPORT.md
├── Scripts
└── billable_assets.py
├── Workbook
├── .images
│ └── image_workbook_consolidated.png
├── README.md
└── mdeasm_workbook_template.json
└── azure-pipelines.yml
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/MDEASM-Solutions/0fcf868649fc05e83622d5533e4caddf3c7f9ee0/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 |
--------------------------------------------------------------------------------
/API Postman Collection/EASM Filter Mappings.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/MDEASM-Solutions/0fcf868649fc05e83622d5533e4caddf3c7f9ee0/API Postman Collection/EASM Filter Mappings.xlsx
--------------------------------------------------------------------------------
/API Postman Collection/Postman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/MDEASM-Solutions/0fcf868649fc05e83622d5533e4caddf3c7f9ee0/API Postman Collection/Postman.png
--------------------------------------------------------------------------------
/API Postman Collection/Readme.md:
--------------------------------------------------------------------------------
1 | ## MDEASM REST API samples using Postman
2 | This repo contains REST API Samples using Postman for Microsoft Defender External Attack Surface Management (MDEASM) API.
3 |
4 | ## Instructions to use Postman Collection
5 | In order to use the shared postman collection, follow these steps:
6 | 1. Install [Postman Client](https://www.postman.com/)
7 | 2. Copy the collection [link](https://api.postman.com/collections/24842526-73467100-1039-484c-850b-5550eb0a4ab5?access_key=PMAT-01GKSWRD0CFS3M3SB5WYH2NKA7) and import it as a new Postman collection in your Workspace
8 | 3. Fill in the needed Azure values to the collection variables like SubscriptionID, tenantId etc.
9 | 4. collection is ready to be **Run**
10 | 5. Helper file **EASM Filter Mappings.xlsx** for finding queryable field names for Asset Search parameter "filter" can be found in the folder
11 |
12 | MDEASM API documentation can be found here, https://learn.microsoft.com/en-us/rest/api/defenderforeasm/
13 |
14 | Azure AD Authentication details can be found here, https://docs.microsoft.com/en-us/rest/api/azure/#how-to-call-azure-rest-apis-with-postman
15 |
16 |
17 |
18 | ## Suggestions and feedback
19 | We value your feedback. Let us know if you run into any problems or share your suggestions and feedback to MDEASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com
20 |
--------------------------------------------------------------------------------
/Automation/Create-ServiceNow-Incident-KeyVault/Create-ServiceNow-Incident-KeyVault.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "metadata": {
5 | "comments": "Automation: Azure Logic App process to query MD EASM Inventory and create incidents in ServiceNow Incident table using Azure KeyVault for storing EASM API Client Secrets",
6 | "author": "MD EASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com"
7 | },
8 | "parameters": {
9 | "workflows_EASM_CreateSNOW_Incident_name": {
10 | "defaultValue": "EASM-CreateSNOW-Incident-KeyVault",
11 | "type": "String"
12 | },
13 | "ClientId": {
14 | "defaultValue": "",
15 | "type": "String"
16 | },
17 | "KeyVaultSecretName": {
18 | "defaultValue": "",
19 | "type": "String"
20 | },
21 | "EASMWorkspaceName": {
22 | "defaultValue": "",
23 | "type": "String"
24 | },
25 | "Region": {
26 | "defaultValue": "",
27 | "type": "String",
28 | "allowedValues": [
29 | "southcentralus",
30 | "eastus",
31 | "australiaeast",
32 | "westus3",
33 | "swedencentral",
34 | "eastasia",
35 | "japaneast",
36 | "westeurope",
37 | "northeurope",
38 | "switzerlandnorth",
39 | "canadacentral",
40 | "centralus",
41 | "norwayeast",
42 | "francecentral",
43 | ""
44 | ],
45 | "metadata": {
46 | "description": "Allowed Azure region values, southcentralus, eastus, australiaeast, westus3, swedencentral, eastasia, japaneast, westeurope, northeurope, switzerlandnorth, canadacentral, centralus, norwayeast, francecentral"
47 | }
48 | },
49 | "RunFrequency": {
50 | "defaultValue": 1,
51 | "type": "Int",
52 | "metadata": {
53 | "description": "Run Frequency is in Hours"
54 | }
55 | },
56 | "api-version": {
57 | "defaultValue": "2022-11-01-preview",
58 | "type": "String"
59 | },
60 | "filter": {
61 | "defaultValue": "state = \"confirmed\"",
62 | "type": "String"
63 | },
64 | "maxpagesize": {
65 | "defaultValue": "50",
66 | "type": "String"
67 | }
68 | },
69 | "variables": {
70 | "ServiceNowConnectionName": "[concat('ServiceNow-', parameters('workflows_EASM_CreateSNOW_Incident_name'))]",
71 | "KeyvaultConnectionName": "[concat('Keyvault-', parameters('workflows_EASM_CreateSNOW_Incident_name'))]"
72 | },
73 | "resources": [
74 | {
75 | "type": "Microsoft.Web/connections",
76 | "apiVersion": "2016-06-01",
77 | "name": "[variables('ServiceNowConnectionName')]",
78 | "location": "[resourceGroup().location]",
79 | "properties": {
80 | "api": {
81 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/service-now')]"
82 | }
83 | }
84 | },
85 | {
86 | "type": "Microsoft.Web/connections",
87 | "apiVersion": "2016-06-01",
88 | "name": "[variables('KeyvaultConnectionName')]",
89 | "location": "[resourceGroup().location]",
90 | "properties": {
91 | "api": {
92 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/keyvault')]"
93 | }
94 | }
95 | },
96 | {
97 | "type": "Microsoft.Logic/workflows",
98 | "apiVersion": "2017-07-01",
99 | "name": "[parameters('workflows_EASM_CreateSNOW_Incident_name')]",
100 | "location": "[resourceGroup().location]",
101 | "dependsOn": [
102 | "[resourceId('Microsoft.Web/connections', variables('ServiceNowConnectionName'))]",
103 | "[resourceId('Microsoft.Web/connections', variables('KeyvaultConnectionName'))]"
104 | ],
105 | "properties": {
106 | "state": "Enabled",
107 | "definition": {
108 | "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
109 | "contentVersion": "1.0.0.0",
110 | "parameters": {
111 | "$connections": {
112 | "defaultValue": {},
113 | "type": "Object"
114 | },
115 | "ClientId": {
116 | "defaultValue": "",
117 | "type": "String"
118 | },
119 | "EASMWorkspaceName": {
120 | "defaultValue": "",
121 | "type": "String"
122 | },
123 | "KeyVaultSecretName": {
124 | "defaultValue": "",
125 | "type": "String"
126 | },
127 | "Region": {
128 | "defaultValue": "eastus",
129 | "type": "String",
130 | "allowedValues": [
131 | "southcentralus",
132 | "eastus",
133 | "australiaeast",
134 | "westus3",
135 | "swedencentral",
136 | "eastasia",
137 | "japaneast",
138 | "westeurope",
139 | "northeurope",
140 | "switzerlandnorth",
141 | "canadacentral",
142 | "centralus",
143 | "norwayeast",
144 | "francecentral"
145 | ]
146 | },
147 | "ResourceGroupName": {
148 | "defaultValue": "[resourceGroup().name]",
149 | "type": "String"
150 | },
151 | "RunFrequency": {
152 | "defaultValue": 1,
153 | "type": "Int"
154 | },
155 | "SubscriptionId": {
156 | "defaultValue": "[subscription().subscriptionId]",
157 | "type": "String"
158 | },
159 | "TenantId": {
160 | "defaultValue": "[subscription().tenantId]",
161 | "type": "String"
162 | },
163 | "api-version": {
164 | "defaultValue": "2022-11-01-preview",
165 | "type": "String"
166 | },
167 | "filter": {
168 | "defaultValue": "state = \"confirmed\"",
169 | "type": "String"
170 | },
171 | "maxpagesize": {
172 | "defaultValue": "50",
173 | "type": "String"
174 | }
175 | },
176 | "triggers": {
177 | "Recurrence": {
178 | "recurrence": {
179 | "frequency": "Hour",
180 | "interval": "@parameters('RunFrequency')"
181 | },
182 | "evaluatedRecurrence": {
183 | "frequency": "Hour",
184 | "interval": 1
185 | },
186 | "type": "Recurrence",
187 | "conditions": [],
188 | "runtimeConfiguration": {
189 | "concurrency": {
190 | "runs": 1
191 | }
192 | }
193 | }
194 | },
195 | "actions": {
196 | "For_each": {
197 | "foreach": "@body('Scheduled_Query_to_EASM')?['content']",
198 | "actions": {
199 | "Create_Incident": {
200 | "runAfter": {
201 | "Parse_JSON": [
202 | "Succeeded"
203 | ]
204 | },
205 | "type": "ApiConnection",
206 | "inputs": {
207 | "host": {
208 | "connection": {
209 | "name": "@parameters('$connections')['service-now']['connectionId']"
210 | }
211 | },
212 | "method": "post",
213 | "body": {
214 | "caller_id": "MDEASM Automation",
215 | "comments": "EASM Inventory Asset Details\n\nName: @{body('Parse_JSON')?['name']}\nType: @{body('Parse_JSON')?['kind']}\nuuid: @{body('Parse_JSON')?['uuid']}\nAdded to Inventory: @{body('Parse_JSON')?['createdDate']}\nLast updated: @{body('Parse_JSON')?['updatedDate']}\n",
216 | "impact": "2",
217 | "priority": "2",
218 | "short_description": "MD EASM reported vulnerability for asset \"@{body('Parse_JSON')?['name']}\"",
219 | "sys_tags": "MDEASM",
220 | "urgency": "2"
221 | },
222 | "path": "/api/now/v2/table/@{encodeURIComponent('incident')}",
223 | "queries": {
224 | "sysparm_display_value": false,
225 | "sysparm_exclude_reference_link": true
226 | }
227 | }
228 | },
229 | "Parse_JSON": {
230 | "type": "ParseJson",
231 | "inputs": {
232 | "content": "@items('For_each')",
233 | "schema": {
234 | "properties": {
235 | "asset": {
236 | "properties": {},
237 | "type": "object"
238 | },
239 | "auditTrail": {
240 | "items": {
241 | "properties": {
242 | "displayName": {},
243 | "id": {},
244 | "kind": {
245 | "type": "string"
246 | },
247 | "name": {
248 | "type": "string"
249 | },
250 | "reason": {}
251 | },
252 | "required": [
253 | "id",
254 | "name",
255 | "displayName",
256 | "kind",
257 | "reason"
258 | ],
259 | "type": "object"
260 | },
261 | "type": "array"
262 | },
263 | "createdDate": {
264 | "type": "string"
265 | },
266 | "discoGroupName": {},
267 | "displayName": {
268 | "type": "string"
269 | },
270 | "externalId": {},
271 | "id": {
272 | "type": "string"
273 | },
274 | "kind": {
275 | "type": "string"
276 | },
277 | "labels": {},
278 | "name": {
279 | "type": "string"
280 | },
281 | "reason": {},
282 | "state": {
283 | "type": "string"
284 | },
285 | "updatedDate": {
286 | "type": "string"
287 | },
288 | "uuid": {
289 | "type": "string"
290 | },
291 | "wildcard": {
292 | "type": "boolean"
293 | }
294 | },
295 | "type": "object"
296 | }
297 | }
298 | },
299 | "Update_EASM_Asset": {
300 | "runAfter": {
301 | "Create_Incident": [
302 | "Succeeded"
303 | ]
304 | },
305 | "limit": {
306 | "timeout": "PT90S"
307 | },
308 | "type": "Http",
309 | "inputs": {
310 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets",
311 | "method": "PATCH",
312 | "headers": {
313 | "Content-Type": "application/json"
314 | },
315 | "queries": {
316 | "api-version": "@parameters('api-version')",
317 | "filter": "uuid=@{items('For_each')?['uuid']}"
318 | },
319 | "body": {
320 | "externalId": "@{body('Create_Incident')?['result']?['number']}"
321 | },
322 | "authentication": {
323 | "audience": "https://easm.defender.microsoft.com/",
324 | "authority": "",
325 | "clientId": "@{parameters('ClientId')}",
326 | "secret": "@{body('Get_secret')?['value']}",
327 | "tenant": "@{parameters('TenantId')}",
328 | "type": "ActiveDirectoryOAuth"
329 | },
330 | "retryPolicy": {
331 | "type": "fixed",
332 | "count": 10,
333 | "interval": "PT20S"
334 | }
335 | }
336 | }
337 | },
338 | "runAfter": {
339 | "Scheduled_Query_to_EASM": [
340 | "Succeeded"
341 | ]
342 | },
343 | "type": "Foreach"
344 | },
345 | "Get_secret": {
346 | "runAfter": {},
347 | "type": "ApiConnection",
348 | "inputs": {
349 | "host": {
350 | "connection": {
351 | "name": "@parameters('$connections')['keyvault']['connectionId']"
352 | }
353 | },
354 | "method": "get",
355 | "path": "/secrets/@{encodeURIComponent(parameters('KeyVaultSecretName'))}/value"
356 | }
357 | },
358 | "Scheduled_Query_to_EASM": {
359 | "runAfter": {
360 | "Get_secret": [
361 | "Succeeded"
362 | ]
363 | },
364 | "type": "Http",
365 | "inputs": {
366 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets",
367 | "method": "GET",
368 | "headers": {
369 | "Content-Type": "application/json",
370 | "User-Agent": "GitHub-LogicApps-CreateSNOWIncident"
371 | },
372 | "queries": {
373 | "api-version": "@{parameters('api-version')}",
374 | "filter": "@{parameters('filter')}",
375 | "mark": "*",
376 | "maxpagesize": "@{parameters('maxpagesize')}",
377 | "skip": "0"
378 | },
379 | "authentication": {
380 | "audience": "https://easm.defender.microsoft.com/",
381 | "clientId": "@{parameters('ClientId')}",
382 | "secret": "@{body('Get_secret')?['value']}",
383 | "tenant": "@{parameters('TenantId')}",
384 | "type": "ActiveDirectoryOAuth"
385 | }
386 | },
387 | "runtimeConfiguration": {
388 | "contentTransfer": {
389 | "transferMode": "Chunked"
390 | }
391 | }
392 | }
393 | },
394 | "outputs": {}
395 | },
396 | "parameters": {
397 | "$connections": {
398 | "value": {
399 | "service-now": {
400 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/service-now')]",
401 | "connectionId": "[resourceId('Microsoft.Web/connections', variables('ServiceNowConnectionName'))]",
402 | "connectionName": "[variables('ServiceNowConnectionName')]"
403 | },
404 | "keyvault": {
405 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/keyvault')]",
406 | "connectionId": "[resourceId('Microsoft.Web/connections', variables('KeyvaultConnectionName'))]",
407 | "connectionName": "[variables('KeyvaultConnectionName')]"
408 | }
409 | }
410 | },
411 | "ClientId": {
412 | "value": "[parameters('ClientId')]"
413 | },
414 | "EASMWorkspaceName": {
415 | "value": "[parameters('EASMWorkspaceName')]"
416 | },
417 | "KeyVaultSecretName": {
418 | "value": "[parameters('KeyVaultSecretName')]"
419 | },
420 | "RunFrequency": {
421 | "value": "[parameters('RunFrequency')]"
422 | },
423 | "api-version": {
424 | "value": "[parameters('api-version')]"
425 | },
426 | "filter": {
427 | "value": "[parameters('filter')]"
428 | },
429 | "Region": {
430 | "value": "[parameters('Region')]"
431 | },
432 | "maxpagesize": {
433 | "value": "[parameters('maxpagesize')]"
434 | }
435 | }
436 | }
437 | }
438 | ]
439 | }
--------------------------------------------------------------------------------
/Automation/Create-ServiceNow-Incident-KeyVault/Readme.md:
--------------------------------------------------------------------------------
1 | # MDEASM: Create ServiceNow Incidents for MD EASM using Azure Keyvault
2 |
3 | ## Overview
4 | Playbook demonstrates automation to create incidents in ServiceNow for select Inventory Assets by querying for certain vulnerabilities or set criteria from your MDEASM Inventory and EASM Authentication using Azure Keyvault to store and access EASM API Client Secret Values.
5 |
6 | 1. The playbook queries MDEASM Inventory using the 'filter' parameter and creates incidents in ServiceNow Instance for each Asset result from the MDEASM query
7 | 2. The playbook has inbuilt trigger condition to run only when Assets are returned by the EASM Query, this allows the playbook to run near-realtime frequency and not add any additional Azure cost. the 'RunFrequency' parameter (In Hours) can be used to change the schedule to run the playbook as needed. By default it is run very 60 seconds
8 | 3. The playbook also adds/updates the ServiceNow Incident Number to the MDEASM Asset detail field 'ExternalId' for reference
9 | 4. The playbook uses Azure Logic Apps Service Now Connector
10 |
11 | ## Prerequisites
12 | 1. MDEASM API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
13 | 2. ServiceNow API connection requires authorization using serviceNow instance URL, username and password
14 | 3. MDEASM filter parameter needs to be set to an appropriate value to query inventory assets. Refer MDEASM API documentation
15 | For Example: here's a query to monitor and alert for all assets with CVSS Score >= 8
16 | state="confirmed" and kind = "page" and rooturl = true and cvssScore >= 8
17 | 4. KeyVault "Get Secret" connection requires authorization using your login with your "KeyVault Name" and "tenantId"
18 |
19 | ## Deployment
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | ### Post-Deployment Instructions
29 | After deploying the playbook, you must authorize the connections leveraged.
30 |
31 | 1. Visit the playbook resource.
32 | 2. Under "Development Tools" (located on the left), click "API Connections".
33 | 3. Ensure each connection has been authorized.
34 |
35 | The playbook can be edited if any custom changes needed.
36 |
--------------------------------------------------------------------------------
/Automation/Create-ServiceNow-Incident/Create-ServiceNow-Incident.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "metadata": {
5 | "comments": "Automation: Azure Logic App process to query MD EASM Inventory and create incidents in ServiceNow Incident table",
6 | "author": "MD EASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com"
7 | },
8 | "parameters": {
9 | "workflows_EASM_CreateSNOW_Incident_name": {
10 | "defaultValue": "EASM-CreateSNOW-Incident",
11 | "type": "String"
12 | },
13 | "ClientId": {
14 | "defaultValue": "Client-ID",
15 | "type": "String"
16 | },
17 | "ClientSecret": {
18 | "defaultValue": "Client-Secret",
19 | "type": "SecureString"
20 | },
21 | "EASMWorkspaceName": {
22 | "defaultValue": "WorkspaceName",
23 | "type": "String"
24 | },
25 | "RunFrequency": {
26 | "defaultValue": 60,
27 | "type": "Int"
28 | },
29 | "api-version": {
30 | "defaultValue": "2022-04-01-preview",
31 | "type": "String"
32 | },
33 | "filter": {
34 | "defaultValue": "state = \"confirmed\" and kind = \"PAGE\" and rootUrl = true and externalId empty",
35 | "type": "String"
36 | },
37 | "maxpagesize": {
38 | "defaultValue": "50",
39 | "type": "String"
40 | }
41 | },
42 | "variables": {
43 | "ServiceNow5ConnectionName": "[concat('ServiceNow5-', parameters('workflows_EASM_CreateSNOW_Incident_name'))]"
44 | },
45 | "resources": [
46 | {
47 | "type": "Microsoft.Web/connections",
48 | "apiVersion": "2016-06-01",
49 | "name": "[variables('ServiceNow5ConnectionName')]",
50 | "location": "[resourceGroup().location]",
51 | "properties": {
52 | "api": {
53 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/service-now')]"
54 | }
55 | }
56 | },
57 | {
58 | "type": "Microsoft.Logic/workflows",
59 | "apiVersion": "2017-07-01",
60 | "name": "[parameters('workflows_EASM_CreateSNOW_Incident_name')]",
61 | "location": "[resourceGroup().location]",
62 | "dependsOn": [
63 | "[resourceId('Microsoft.Web/connections', variables('ServiceNow5ConnectionName'))]"
64 | ],
65 | "properties": {
66 | "state": "Enabled",
67 | "definition": {
68 | "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
69 | "contentVersion": "1.0.0.0",
70 | "parameters": {
71 | "$connections": {
72 | "defaultValue": {},
73 | "type": "Object"
74 | },
75 | "ClientId": {
76 | "defaultValue": "Client-ID",
77 | "type": "String"
78 | },
79 | "ClientSecret": {
80 | "defaultValue": "Client-Secret",
81 | "type": "SecureString"
82 | },
83 | "EASMWorkspaceName": {
84 | "defaultValue": "workSpaceName",
85 | "type": "String"
86 | },
87 | "Region": {
88 | "defaultValue": "[resourceGroup().location]",
89 | "type": "String"
90 | },
91 | "ResourceGroupName": {
92 | "defaultValue": "[resourceGroup().name]",
93 | "type": "String"
94 | },
95 | "RunFrequency": {
96 | "defaultValue": 60,
97 | "type": "Int"
98 | },
99 | "SubscriptionId": {
100 | "defaultValue": "[subscription().subscriptionId]",
101 | "type": "String"
102 | },
103 | "TenantId": {
104 | "defaultValue": "[subscription().tenantId]",
105 | "type": "String"
106 | },
107 | "api-version": {
108 | "defaultValue": "2022-04-01-preview",
109 | "type": "String"
110 | },
111 | "filter": {
112 | "defaultValue": "state = \"confirmed\" and kind = \"PAGE\" and rootUrl = true and externalId empty",
113 | "type": "String"
114 | },
115 | "maxpagesize": {
116 | "defaultValue": "50",
117 | "type": "String"
118 | }
119 | },
120 | "triggers": {
121 | "Scheduled_Query_to_EASM": {
122 | "recurrence": {
123 | "frequency": "Second",
124 | "interval": "@parameters('RunFrequency')"
125 | },
126 | "evaluatedRecurrence": {
127 | "frequency": "Second",
128 | "interval": 60
129 | },
130 | "type": "Http",
131 | "inputs": {
132 | "authentication": {
133 | "audience": "https://easm.defender.microsoft.com/",
134 | "clientId": "@parameters('ClientId')",
135 | "secret": "@parameters('ClientSecret')",
136 | "tenant": "@parameters('TenantId')",
137 | "type": "ActiveDirectoryOAuth"
138 | },
139 | "headers": {
140 | "Content-Type": "application/json",
141 | "User-Agent": "GitHub-LogicApps-CreateSNOWIncident"
142 | },
143 | "method": "GET",
144 | "queries": {
145 | "api-version": "@parameters('api-version')",
146 | "filter": "@parameters('filter')",
147 | "mark": "*",
148 | "maxpagesize": "@parameters('maxpagesize')",
149 | "skip": "0"
150 | },
151 | "retryPolicy": {
152 | "count": 6,
153 | "interval": "PT10S",
154 | "type": "fixed"
155 | },
156 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
157 | },
158 | "conditions": [
159 | {
160 | "expression": "@greater(triggerBody()?.totalElements,0)"
161 | }
162 | ],
163 | "runtimeConfiguration": {
164 | "concurrency": {
165 | "runs": 1
166 | }
167 | }
168 | }
169 | },
170 | "actions": {
171 | "For_each": {
172 | "foreach": "@triggerBody()?['content']",
173 | "actions": {
174 | "Create_Incident": {
175 | "runAfter": {
176 | "Parse_JSON": [
177 | "Succeeded"
178 | ]
179 | },
180 | "type": "ApiConnection",
181 | "inputs": {
182 | "body": {
183 | "caller_id": "MDEASM Automation",
184 | "comments": "EASM Inventory Asset Details\n\nName: @{body('Parse_JSON')?['name']}\nType: @{body('Parse_JSON')?['kind']}\nuuid: @{body('Parse_JSON')?['uuid']}\nAdded to Inventory: @{body('Parse_JSON')?['createdDate']}\nLast updated: @{body('Parse_JSON')?['updatedDate']}\n",
185 | "impact": "2",
186 | "priority": "2",
187 | "short_description": "MD EASM reported vulnerability for asset \"@{body('Parse_JSON')?['name']}\"",
188 | "sys_tags": "MDEASM",
189 | "urgency": "2"
190 | },
191 | "host": {
192 | "connection": {
193 | "name": "@parameters('$connections')['service-now_1']['connectionId']"
194 | }
195 | },
196 | "method": "post",
197 | "path": "/api/now/v2/table/@{encodeURIComponent('incident')}",
198 | "queries": {
199 | "sysparm_display_value": false,
200 | "sysparm_exclude_reference_link": true
201 | },
202 | "retryPolicy": {
203 | "count": 10,
204 | "interval": "PT10S",
205 | "type": "fixed"
206 | }
207 | }
208 | },
209 | "Parse_JSON": {
210 | "runAfter": {},
211 | "type": "ParseJson",
212 | "inputs": {
213 | "content": "@items('For_each')",
214 | "schema": {
215 | "properties": {
216 | "asset": {
217 | "properties": {},
218 | "type": "object"
219 | },
220 | "auditTrail": {
221 | "items": {
222 | "properties": {
223 | "displayName": {},
224 | "id": {},
225 | "kind": {
226 | "type": "string"
227 | },
228 | "name": {
229 | "type": "string"
230 | },
231 | "reason": {}
232 | },
233 | "required": [
234 | "id",
235 | "name",
236 | "displayName",
237 | "kind",
238 | "reason"
239 | ],
240 | "type": "object"
241 | },
242 | "type": "array"
243 | },
244 | "createdDate": {
245 | "type": "string"
246 | },
247 | "discoGroupName": {},
248 | "displayName": {
249 | "type": "string"
250 | },
251 | "externalId": {},
252 | "id": {
253 | "type": "string"
254 | },
255 | "kind": {
256 | "type": "string"
257 | },
258 | "labels": {},
259 | "name": {
260 | "type": "string"
261 | },
262 | "reason": {},
263 | "state": {
264 | "type": "string"
265 | },
266 | "updatedDate": {
267 | "type": "string"
268 | },
269 | "uuid": {
270 | "type": "string"
271 | },
272 | "wildcard": {
273 | "type": "boolean"
274 | }
275 | },
276 | "type": "object"
277 | }
278 | }
279 | },
280 | "Update_EASM_Asset": {
281 | "runAfter": {
282 | "Create_Incident": [
283 | "Succeeded"
284 | ]
285 | },
286 | "limit": {
287 | "timeout": "PT90S"
288 | },
289 | "type": "Http",
290 | "inputs": {
291 | "authentication": {
292 | "audience": "https://easm.defender.microsoft.com/",
293 | "clientId": "@parameters('ClientId')",
294 | "secret": "@parameters('ClientSecret')",
295 | "tenant": "@parameters('TenantId')",
296 | "type": "ActiveDirectoryOAuth"
297 | },
298 | "body": {
299 | "externalId": "@{body('Create_Incident')?['result']?['number']}"
300 | },
301 | "headers": {
302 | "Content-Type": "application/json"
303 | },
304 | "method": "PATCH",
305 | "queries": {
306 | "api-version": "@parameters('api-version')",
307 | "filter": "uuid=@{items('For_each')?['uuid']}"
308 | },
309 | "retryPolicy": {
310 | "count": 10,
311 | "interval": "PT20S",
312 | "type": "fixed"
313 | },
314 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
315 | },
316 | "description": "Update EASM Asset External Id field with the ServiceNow incident number "
317 | }
318 | },
319 | "runAfter": {},
320 | "type": "Foreach"
321 | }
322 | },
323 | "outputs": {}
324 | },
325 | "parameters": {
326 | "$connections": {
327 | "value": {
328 | "service-now_1": {
329 | "connectionId": "[resourceId('Microsoft.Web/connections', variables('ServiceNow5ConnectionName'))]",
330 | "connectionName": "[variables('ServiceNow5ConnectionName')]",
331 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/service-now')]"
332 | }
333 | }
334 | },
335 | "ClientId": {
336 | "value": "[parameters('ClientId')]"
337 | },
338 | "ClientSecret": {
339 | "value": "[parameters('ClientSecret')]"
340 | },
341 | "EASMWorkspaceName": {
342 | "value": "[parameters('EASMWorkspaceName')]"
343 | },
344 | "RunFrequency": {
345 | "value": "[parameters('RunFrequency')]"
346 | },
347 | "api-version": {
348 | "value": "[parameters('api-version')]"
349 | },
350 | "filter": {
351 | "value": "[parameters('filter')]"
352 | },
353 | "maxpagesize": {
354 | "value": "[parameters('maxpagesize')]"
355 | }
356 | }
357 | }
358 | }
359 | ]
360 | }
--------------------------------------------------------------------------------
/Automation/Create-ServiceNow-Incident/Readme.md:
--------------------------------------------------------------------------------
1 | # MDEASM: Create ServiceNow Incidents
2 |
3 | ## Overview
4 | Playbook demonstrates automation to create incidents in ServiceNow for select Inventory Assets by querying for certain vulnerabilities or set criteria from your MDEASM Inventory.
5 |
6 | 1. The playbook queries MDEASM Inventory using the 'filter' parameter and creates incidents in ServiceNow Instance for each Asset result from the MDEASM query
7 | 2. The playbook has inbuilt trigger condition to run only when Assets are returned by the EASM Query, this allows the playbook to run near-realtime frequency and not add any additional Azure cost. the 'RunFrequency' parameter (In Seconds) can be used to change the schedule to run the playbook as needed. By default it is run very 60 seconds
8 | 3. The playbook also adds/updates the ServiceNow Incident Number to the MDEASM Asset detail field 'ExternalId' for reference
9 | 4. The playbook uses Azure Logic Apps Service Now Connector
10 |
11 | ## Prerequisites
12 | 1. MDEASM API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
13 | 2. ServiceNow API connection requires authorization using serviceNow instance URL, username and password
14 | 3. MDEASM filter parameter needs to be set to an appropriate value to query inventory assets. Refer MDEASM API documentation
15 |
16 | ## Deployment
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ### Post-Deployment Instructions
26 | After deploying the playbook, you must authorize the connections leveraged.
27 |
28 | 1. Visit the playbook resource.
29 | 2. Under "Development Tools" (located on the left), click "API Connections".
30 | 3. Ensure each connection has been authorized.
31 |
32 | The playbook can be edited if any custom changes needed.
33 |
--------------------------------------------------------------------------------
/Automation/Inventory-Alerts-Email-KeyVault/Inventory-Alerts-Email-Keyvault.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "metadata": {
5 | "comments": "Automation: Azure Logic App process to Monitor Inventory Assets and alert via Email notifications for required or custom Inventory query using Azure KeyVault for storing EASM API Client Secrets",
6 | "author": "MD EASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com"
7 | },
8 | "parameters": {
9 | "workflows_Inventory_Alerts_Email_KeyVault_name": {
10 | "defaultValue": "Inventory-Alerts-Email-KeyVault",
11 | "type": "String"
12 | },
13 | "ClientId": {
14 | "defaultValue": "",
15 | "type": "String"
16 | },
17 | "KeyVaultSecretName": {
18 | "defaultValue": "",
19 | "type": "String"
20 | },
21 | "EASMWorkspaceName": {
22 | "defaultValue": "",
23 | "type": "String"
24 | },
25 | "Region": {
26 | "defaultValue": "",
27 | "type": "String",
28 | "allowedValues": [
29 | "southcentralus",
30 | "eastus",
31 | "australiaeast",
32 | "westus3",
33 | "swedencentral",
34 | "eastasia",
35 | "japaneast",
36 | "westeurope",
37 | "northeurope",
38 | "switzerlandnorth",
39 | "canadacentral",
40 | "centralus",
41 | "norwayeast",
42 | "francecentral",
43 | ""
44 | ],
45 | "metadata": {
46 | "description": "Allowed Azure region values, southcentralus, eastus, australiaeast, westus3, swedencentral, eastasia, japaneast, westeurope, northeurope, switzerlandnorth, canadacentral, centralus, norwayeast, francecentral"
47 | }
48 | },
49 | "RunFrequency": {
50 | "defaultValue": 1,
51 | "type": "Int",
52 | "metadata": {
53 | "description": "Run Frequency is in Hours"
54 | }
55 | },
56 | "api-version": {
57 | "defaultValue": "2022-11-01-preview",
58 | "type": "String"
59 | },
60 | "filter": {
61 | "defaultValue": "state = \"confirmed\"",
62 | "type": "String"
63 | },
64 | "LabelName": {
65 | "defaultValue": "EmailAlert",
66 | "type": "String"
67 | },
68 | "maxpagesize": {
69 | "defaultValue": "100",
70 | "type": "String"
71 | }
72 | },
73 | "variables": {
74 | "Office365ConnectionName": "[concat('Office365-', parameters('workflows_Inventory_Alerts_Email_KeyVault_name'))]",
75 | "KeyvaultConnectionName": "[concat('Keyvault-', parameters('workflows_Inventory_Alerts_Email_KeyVault_name'))]"
76 | },
77 | "resources": [
78 | {
79 | "type": "Microsoft.Web/connections",
80 | "apiVersion": "2016-06-01",
81 | "name": "[variables('Office365ConnectionName')]",
82 | "location": "[resourceGroup().location]",
83 | "properties": {
84 | "api": {
85 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/office365')]"
86 | }
87 | }
88 | },
89 | {
90 | "type": "Microsoft.Web/connections",
91 | "apiVersion": "2016-06-01",
92 | "name": "[variables('KeyvaultConnectionName')]",
93 | "location": "[resourceGroup().location]",
94 | "properties": {
95 | "api": {
96 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/keyvault')]"
97 | }
98 | }
99 | },
100 | {
101 | "type": "Microsoft.Logic/workflows",
102 | "apiVersion": "2017-07-01",
103 | "name": "[parameters('workflows_Inventory_Alerts_Email_KeyVault_name')]",
104 | "location": "[resourceGroup().location]",
105 | "dependsOn": [
106 | "[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]",
107 | "[resourceId('Microsoft.Web/connections', variables('KeyvaultConnectionName'))]"
108 | ],
109 | "properties": {
110 | "state": "Enabled",
111 | "definition": {
112 | "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
113 | "contentVersion": "1.0.0.0",
114 | "parameters": {
115 | "$connections": {
116 | "defaultValue": {},
117 | "type": "Object"
118 | },
119 | "ClientId": {
120 | "defaultValue": "",
121 | "type": "String"
122 | },
123 | "EASMWorkspaceName": {
124 | "defaultValue": "",
125 | "type": "String"
126 | },
127 | "KeyVaultSecretName": {
128 | "defaultValue": "",
129 | "type": "String"
130 | },
131 | "LabelName": {
132 | "defaultValue": "EmailAlert",
133 | "type": "String"
134 | },
135 | "Region": {
136 | "defaultValue": "eastus",
137 | "type": "String",
138 | "allowedValues": [
139 | "southcentralus",
140 | "eastus",
141 | "australiaeast",
142 | "westus3",
143 | "swedencentral",
144 | "eastasia",
145 | "japaneast",
146 | "westeurope",
147 | "northeurope",
148 | "switzerlandnorth",
149 | "canadacentral",
150 | "centralus",
151 | "norwayeast",
152 | "francecentral"
153 | ]
154 | },
155 | "ResourceGroupName": {
156 | "defaultValue": "[resourceGroup().name]",
157 | "type": "String"
158 | },
159 | "RunFrequency": {
160 | "defaultValue": 1,
161 | "type": "Int"
162 | },
163 | "SubscriptionId": {
164 | "defaultValue": "[subscription().subscriptionId]",
165 | "type": "String"
166 | },
167 | "TenantId": {
168 | "defaultValue": "[subscription().tenantId]",
169 | "type": "String"
170 | },
171 | "api-version": {
172 | "defaultValue": "2022-11-01-preview",
173 | "type": "String"
174 | },
175 | "filter": {
176 | "defaultValue": "state = \"confirmed\"",
177 | "type": "String"
178 | },
179 | "maxpagesize": {
180 | "defaultValue": "100",
181 | "type": "String"
182 | }
183 | },
184 | "triggers": {
185 | "Recurrence": {
186 | "recurrence": {
187 | "frequency": "Hour",
188 | "interval": "@parameters('RunFrequency')"
189 | },
190 | "evaluatedRecurrence": {
191 | "frequency": "Hour",
192 | "interval": 1
193 | },
194 | "type": "Recurrence",
195 | "conditions": [],
196 | "runtimeConfiguration": {
197 | "concurrency": {
198 | "runs": 1
199 | }
200 | }
201 | }
202 | },
203 | "actions": {
204 | "Condition": {
205 | "actions": {
206 | "Create_Label": {
207 | "runAfter": {},
208 | "limit": {
209 | "timeout": "PT90S"
210 | },
211 | "type": "Http",
212 | "inputs": {
213 | "authentication": {
214 | "audience": "https://management.core.windows.net/",
215 | "clientId": "@parameters('ClientId')",
216 | "secret": "@body('Get_secret')?['value']",
217 | "tenant": "@parameters('TenantId')",
218 | "type": "ActiveDirectoryOAuth"
219 | },
220 | "body": {},
221 | "headers": {
222 | "Content-Type": "application/json",
223 | "User-Agent": "GitHub-LogicApps-EmailAlerts"
224 | },
225 | "method": "PUT",
226 | "queries": {
227 | "api-version": "2022-04-01-preview"
228 | },
229 | "retryPolicy": {
230 | "count": 10,
231 | "interval": "PT20S",
232 | "type": "fixed"
233 | },
234 | "uri": "https://management.azure.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups@{parameters('ResourceGroupName')}/providers/Microsoft.Easm/workspaces/@{parameters('EASMWorkspaceName')}/labels/@{parameters('LabelName')}"
235 | }
236 | },
237 | "Update_Assets": {
238 | "runAfter": {
239 | "Create_Label": [
240 | "Succeeded"
241 | ]
242 | },
243 | "limit": {
244 | "timeout": "PT90S"
245 | },
246 | "type": "Http",
247 | "inputs": {
248 | "authentication": {
249 | "audience": "https://easm.defender.microsoft.com/",
250 | "clientId": "@parameters('ClientId')",
251 | "secret": "@body('Get_secret')?['value']",
252 | "tenant": "@parameters('TenantId')",
253 | "type": "ActiveDirectoryOAuth"
254 | },
255 | "body": {
256 | "labels": {
257 | "@{parameters('LabelName')}": true
258 | }
259 | },
260 | "headers": {
261 | "Content-Type": "application/json",
262 | "User-Agent": "GitHub-LogicApps-EmailAlerts"
263 | },
264 | "method": "PATCH",
265 | "queries": {
266 | "api-version": "@parameters('api-version')",
267 | "filter": "@{parameters('filter')} and label != @{parameters('LabelName')}"
268 | },
269 | "retryPolicy": {
270 | "count": 10,
271 | "interval": "PT20S",
272 | "type": "fixed"
273 | },
274 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
275 | }
276 | }
277 | },
278 | "runAfter": {
279 | "Update_EASM_Asset": [
280 | "Failed",
281 | "TimedOut"
282 | ]
283 | },
284 | "expression": {
285 | "and": [
286 | {
287 | "equals": [
288 | "@outputs('Update_EASM_Asset')['statusCode']",
289 | 400
290 | ]
291 | }
292 | ]
293 | },
294 | "type": "If",
295 | "description": "If label does not exist, this path creates it and then updates assets with newly created label"
296 | },
297 | "Create_CSV_table": {
298 | "runAfter": {
299 | "Parse_JSON": [
300 | "Succeeded"
301 | ]
302 | },
303 | "type": "Table",
304 | "inputs": {
305 | "format": "CSV",
306 | "from": "@body('Parse_JSON')"
307 | }
308 | },
309 | "Get_secret": {
310 | "runAfter": {},
311 | "type": "ApiConnection",
312 | "inputs": {
313 | "host": {
314 | "connection": {
315 | "name": "@parameters('$connections')['keyvault_1']['connectionId']"
316 | }
317 | },
318 | "method": "get",
319 | "path": "/secrets/@{encodeURIComponent(parameters('KeyVaultSecretName'))}/value"
320 | }
321 | },
322 | "Parse_JSON": {
323 | "runAfter": {
324 | "Scheduled_Query_to_EASM": [
325 | "Succeeded"
326 | ]
327 | },
328 | "type": "ParseJson",
329 | "inputs": {
330 | "content": "@body('Scheduled_Query_to_EASM')?['content']",
331 | "schema": {
332 | "items": {
333 | "properties": {
334 | "asset": {
335 | "properties": {},
336 | "type": "object"
337 | },
338 | "auditTrail": {
339 | "type": [
340 | "array",
341 | "null"
342 | ]
343 | },
344 | "createdDate": {
345 | "type": [
346 | "string",
347 | "null"
348 | ]
349 | },
350 | "discoGroupName": {
351 | "type": [
352 | "string",
353 | "null"
354 | ]
355 | },
356 | "displayName": {
357 | "type": [
358 | "string",
359 | "null"
360 | ]
361 | },
362 | "externalId": {
363 | "type": [
364 | "string",
365 | "null"
366 | ]
367 | },
368 | "history": {
369 | "type": [
370 | "string",
371 | "array",
372 | "null"
373 | ]
374 | },
375 | "id": {
376 | "type": [
377 | "string",
378 | "null"
379 | ]
380 | },
381 | "kind": {
382 | "type": [
383 | "string",
384 | "null"
385 | ]
386 | },
387 | "labels": {
388 | "type": [
389 | "array",
390 | "null"
391 | ]
392 | },
393 | "name": {
394 | "type": [
395 | "string",
396 | "null"
397 | ]
398 | },
399 | "reason": {
400 | "type": [
401 | "string",
402 | "null"
403 | ]
404 | },
405 | "state": {
406 | "type": [
407 | "string",
408 | "null"
409 | ]
410 | },
411 | "updatedDate": {
412 | "type": [
413 | "string",
414 | "null"
415 | ]
416 | },
417 | "uuid": {
418 | "type": [
419 | "string",
420 | "null"
421 | ]
422 | },
423 | "wildcard": {
424 | "type": [
425 | "boolean",
426 | "null"
427 | ]
428 | }
429 | },
430 | "required": [],
431 | "type": "object"
432 | },
433 | "type": "array"
434 | }
435 | }
436 | },
437 | "Scheduled_Query_to_EASM": {
438 | "runAfter": {
439 | "Get_secret": [
440 | "Succeeded"
441 | ]
442 | },
443 | "type": "Http",
444 | "inputs": {
445 | "authentication": {
446 | "audience": "https://easm.defender.microsoft.com/",
447 | "clientId": "@parameters('ClientId')",
448 | "secret": "@body('Get_secret')?['value']",
449 | "tenant": "@parameters('TenantId')",
450 | "type": "ActiveDirectoryOAuth"
451 | },
452 | "method": "GET",
453 | "queries": {
454 | "api-version": "@parameters('api-version')",
455 | "filter": "@{parameters('filter')} and label != @{parameters('LabelName')}",
456 | "mark": "*",
457 | "maxpagesize": "@parameters('maxpagesize')"
458 | },
459 | "retryPolicy": {
460 | "count": 10,
461 | "interval": "PT10S",
462 | "type": "fixed"
463 | },
464 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
465 | }
466 | },
467 | "Send_an_email_(V2)": {
468 | "runAfter": {
469 | "Create_CSV_table": [
470 | "Succeeded"
471 | ]
472 | },
473 | "type": "ApiConnection",
474 | "inputs": {
475 | "body": {
476 | "Attachments": [
477 | {
478 | "ContentBytes": "@{base64(body('Create_CSV_table'))}",
479 | "Name": "EASM_alerts.csv"
480 | }
481 | ],
482 | "Body": "
Hi,
\n
\nMDEASM detected Assets in your Inventory matching your monitoring query,
\n@{parameters('filter')}
\n
\nPlease check your EASM Inventory for individual Asset details found in this alert.
\nAlso, attached is list of these assets for your reference in CSV format.
\n
\n---
\nThanks for using MDEASM Alerts
27 |
28 |
29 | ### Post-Deployment Instructions
30 | After deploying the playbook, you must authorize the connections leveraged.
31 |
32 | 1. Visit the playbook resource.
33 | 2. Under "Development Tools" (located on the left), click "API Connections".
34 | 3. Ensure each connection has been authorized.
35 |
36 | The playbook can be edited if any custom or parameter changes needed.
37 |
--------------------------------------------------------------------------------
/Automation/Inventory-Alerts-Email/Inventory-Alerts-Email.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "metadata": {
5 | "comments": "Automation: Azure Logic App process to Monitor Inventory Assets and alert via Email notifications for required or custom Inventory query.",
6 | "author": "MD EASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com"
7 | },
8 | "parameters": {
9 | "workflows_EASM_Alerts_Email_name": {
10 | "defaultValue": "Inventory-Alerts-Email",
11 | "type": "String"
12 | },
13 | "ClientId": {
14 | "defaultValue": "Client-ID",
15 | "type": "String"
16 | },
17 | "ClientSecret": {
18 | "defaultValue": "Client-Secret",
19 | "type": "SecureString"
20 | },
21 | "EASMWorkspaceName": {
22 | "defaultValue": "WorkspaceName",
23 | "type": "String"
24 | },
25 | "RunFrequency": {
26 | "defaultValue": 3600,
27 | "type": "Int"
28 | },
29 | "api-version": {
30 | "defaultValue": "2022-11-01-preview",
31 | "type": "String"
32 | },
33 | "LabelName": {
34 | "defaultValue": "LabelName",
35 | "type": "String"
36 | },
37 | "filter": {
38 | "defaultValue": "filter",
39 | "type": "String"
40 | },
41 | "maxpagesize": {
42 | "defaultValue": "100",
43 | "type": "String"
44 | }
45 | },
46 | "variables": {
47 | "Office365ConnectionName": "[concat('Office365-', parameters('workflows_EASM_Alerts_Email_name'))]"
48 | },
49 | "resources": [
50 | {
51 | "type": "Microsoft.Web/connections",
52 | "apiVersion": "2016-06-01",
53 | "name": "[variables('Office365ConnectionName')]",
54 | "location": "[resourceGroup().location]",
55 | "properties": {
56 | "api": {
57 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/office365')]"
58 | }
59 | }
60 | },
61 | {
62 | "type": "Microsoft.Logic/workflows",
63 | "apiVersion": "2017-07-01",
64 | "name": "[parameters('workflows_EASM_Alerts_Email_name')]",
65 | "location": "[resourceGroup().location]",
66 | "dependsOn": [
67 | "[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]"
68 | ],
69 | "properties": {
70 | "state": "Enabled",
71 | "definition": {
72 | "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
73 | "contentVersion": "1.0.0.0",
74 | "parameters": {
75 | "$connections": {
76 | "defaultValue": {},
77 | "type": "Object"
78 | },
79 | "ClientId": {
80 | "defaultValue": "Client-ID",
81 | "type": "String"
82 | },
83 | "ClientSecret": {
84 | "defaultValue": "Client-Secret",
85 | "type": "SecureString"
86 | },
87 | "EASMWorkspaceName": {
88 | "defaultValue": "workSpaceName",
89 | "type": "String"
90 | },
91 | "LabelName": {
92 | "defaultValue": "EmailAlert",
93 | "type": "String"
94 | },
95 | "Region": {
96 | "defaultValue": "[resourceGroup().location]",
97 | "type": "String"
98 | },
99 | "ResourceGroupName": {
100 | "defaultValue": "[resourceGroup().name]",
101 | "type": "String"
102 | },
103 | "RunFrequency": {
104 | "defaultValue": 60,
105 | "type": "Int"
106 | },
107 | "SubscriptionId": {
108 | "defaultValue": "[subscription().subscriptionId]",
109 | "type": "String"
110 | },
111 | "TenantId": {
112 | "defaultValue": "[subscription().tenantId]",
113 | "type": "String"
114 | },
115 | "api-version": {
116 | "defaultValue": "2022-11-01-preview",
117 | "type": "String"
118 | },
119 | "filter": {
120 | "defaultValue": "filter",
121 | "type": "String"
122 | },
123 | "maxpagesize": {
124 | "defaultValue": "50",
125 | "type": "String"
126 | }
127 | },
128 | "triggers": {
129 | "Scheduled_Query_to_EASM": {
130 | "recurrence": {
131 | "frequency": "Second",
132 | "interval": "@parameters('RunFrequency')"
133 | },
134 | "evaluatedRecurrence": {
135 | "frequency": "Second",
136 | "interval": 86400
137 | },
138 | "type": "Http",
139 | "inputs": {
140 | "authentication": {
141 | "audience": "https://easm.defender.microsoft.com/",
142 | "clientId": "@parameters('ClientId')",
143 | "secret": "@parameters('ClientSecret')",
144 | "tenant": "@parameters('TenantId')",
145 | "type": "ActiveDirectoryOAuth"
146 | },
147 | "headers": {
148 | "Content-Type": "application/json",
149 | "User-Agent": "GitHub-LogicApps-EmailAlerts"
150 | },
151 | "method": "GET",
152 | "queries": {
153 | "api-version": "@parameters('api-version')",
154 | "filter": "@{parameters('filter')} and label != @{parameters('LabelName')}",
155 | "mark": "*",
156 | "maxpagesize": "@parameters('maxpagesize')"
157 | },
158 | "retryPolicy": {
159 | "count": 6,
160 | "interval": "PT10S",
161 | "type": "fixed"
162 | },
163 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
164 | },
165 | "conditions": [
166 | {
167 | "expression": "@greater(triggerBody()?.totalElements,0)"
168 | }
169 | ],
170 | "runtimeConfiguration": {
171 | "concurrency": {
172 | "runs": 1
173 | }
174 | }
175 | }
176 | },
177 | "actions": {
178 | "Condition": {
179 | "actions": {
180 | "Create_Label": {
181 | "runAfter": {},
182 | "limit": {
183 | "timeout": "PT90S"
184 | },
185 | "type": "Http",
186 | "inputs": {
187 | "authentication": {
188 | "audience": "https://management.core.windows.net/",
189 | "clientId": "@parameters('ClientId')",
190 | "secret": "@parameters('ClientSecret')",
191 | "tenant": "@parameters('TenantId')",
192 | "type": "ActiveDirectoryOAuth"
193 | },
194 | "body": {},
195 | "headers": {
196 | "Content-Type": "application/json",
197 | "User-Agent": "GitHub-LogicApps-EmailAlerts"
198 | },
199 | "method": "PUT",
200 | "queries": {
201 | "api-version": "2022-04-01-preview"
202 | },
203 | "retryPolicy": {
204 | "count": 10,
205 | "interval": "PT20S",
206 | "type": "fixed"
207 | },
208 | "uri": "https://management.azure.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups@{parameters('ResourceGroupName')}/providers/Microsoft.Easm/workspaces/@{parameters('EASMWorkspaceName')}/labels/@{parameters('LabelName')}"
209 | }
210 | },
211 | "Update_Assets": {
212 | "runAfter": {
213 | "Create_Label": [
214 | "Succeeded"
215 | ]
216 | },
217 | "limit": {
218 | "timeout": "PT90S"
219 | },
220 | "type": "Http",
221 | "inputs": {
222 | "authentication": {
223 | "audience": "https://easm.defender.microsoft.com/",
224 | "clientId": "@parameters('ClientId')",
225 | "secret": "@parameters('ClientSecret')",
226 | "tenant": "@parameters('TenantId')",
227 | "type": "ActiveDirectoryOAuth"
228 | },
229 | "body": {
230 | "labels": {
231 | "@{parameters('LabelName')}": true
232 | }
233 | },
234 | "headers": {
235 | "Content-Type": "application/json",
236 | "User-Agent": "GitHub-LogicApps-EmailAlerts"
237 | },
238 | "method": "PATCH",
239 | "queries": {
240 | "api-version": "@parameters('api-version')",
241 | "filter": "@{parameters('filter')} and label != @{parameters('LabelName')}"
242 | },
243 | "retryPolicy": {
244 | "count": 10,
245 | "interval": "PT20S",
246 | "type": "fixed"
247 | },
248 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
249 | }
250 | }
251 | },
252 | "runAfter": {
253 | "Update_EASM_Asset": [
254 | "Failed",
255 | "TimedOut"
256 | ]
257 | },
258 | "expression": {
259 | "and": [
260 | {
261 | "equals": [
262 | "@outputs('Update_EASM_Asset')['statusCode']",
263 | 400
264 | ]
265 | }
266 | ]
267 | },
268 | "type": "If",
269 | "description": "If label does not exist, this path creates it and then updates assets with newly created label"
270 | },
271 | "Create_CSV_table": {
272 | "runAfter": {
273 | "Parse_JSON": [
274 | "Succeeded"
275 | ]
276 | },
277 | "type": "Table",
278 | "inputs": {
279 | "format": "CSV",
280 | "from": "@body('Parse_JSON')"
281 | }
282 | },
283 | "Parse_JSON": {
284 | "runAfter": {},
285 | "type": "ParseJson",
286 | "inputs": {
287 | "content": "@triggerBody()?['content']",
288 | "schema": {
289 | "items": {
290 | "properties": {
291 | "asset": {
292 | "properties": {},
293 | "type": "object"
294 | },
295 | "auditTrail": {
296 | "type": [
297 | "array",
298 | "null"
299 | ]
300 | },
301 | "createdDate": {
302 | "type": [
303 | "string",
304 | "null"
305 | ]
306 | },
307 | "discoGroupName": {
308 | "type": [
309 | "string",
310 | "null"
311 | ]
312 | },
313 | "displayName": {
314 | "type": [
315 | "string",
316 | "null"
317 | ]
318 | },
319 | "externalId": {
320 | "type": [
321 | "string",
322 | "null"
323 | ]
324 | },
325 | "history": {
326 | "type": [
327 | "string",
328 | "array",
329 | "null"
330 | ]
331 | },
332 | "id": {
333 | "type": [
334 | "string",
335 | "null"
336 | ]
337 | },
338 | "kind": {
339 | "type": [
340 | "string",
341 | "null"
342 | ]
343 | },
344 | "labels": {
345 | "type": [
346 | "array",
347 | "null"
348 | ]
349 | },
350 | "name": {
351 | "type": [
352 | "string",
353 | "null"
354 | ]
355 | },
356 | "reason": {
357 | "type": [
358 | "string",
359 | "null"
360 | ]
361 | },
362 | "state": {
363 | "type": [
364 | "string",
365 | "null"
366 | ]
367 | },
368 | "updatedDate": {
369 | "type": [
370 | "string",
371 | "null"
372 | ]
373 | },
374 | "uuid": {
375 | "type": [
376 | "string",
377 | "null"
378 | ]
379 | },
380 | "wildcard": {
381 | "type": [
382 | "boolean",
383 | "null"
384 | ]
385 | }
386 | },
387 | "required": [],
388 | "type": "object"
389 | },
390 | "type": "array"
391 | }
392 | }
393 | },
394 | "Send_an_email_(V2)": {
395 | "runAfter": {
396 | "Create_CSV_table": [
397 | "Succeeded"
398 | ]
399 | },
400 | "type": "ApiConnection",
401 | "inputs": {
402 | "body": {
403 | "Attachments": [
404 | {
405 | "ContentBytes": "@{base64(body('Create_CSV_table'))}",
406 | "Name": "EASM_alerts.csv"
407 | }
408 | ],
409 | "Body": "Hi,
\n
\nMDEASM detected @{triggerBody()?['totalElements']} Assets in your Inventory matching your monitoring query,
\n@{parameters('filter')}
\n
\nPlease check your EASM Inventory for individual Asset details found in this alert.
\nAlso, attached is list of these assets for your reference in CSV format.
\n
\n---
\nThanks for using MDEASM Alerts
25 |
26 |
27 | ### Post-Deployment Instructions
28 | After deploying the playbook, you must authorize the connections leveraged.
29 |
30 | 1. Visit the playbook resource.
31 | 2. Under "Development Tools" (located on the left), click "API Connections".
32 | 3. Ensure each connection has been authorized.
33 |
34 | The playbook can be edited if any custom changes needed.
35 |
--------------------------------------------------------------------------------
/Automation/Inventory-Asset-Management/Inventory-Asset-Management.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "metadata": {
5 | "comments": "Automation: Azure Logic App process to Manage Inventory Assets via Labels and Asset State.",
6 | "author": "MD EASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com"
7 | },
8 | "parameters": {
9 | "workflows_Inventory_Asset_Management_name": {
10 | "defaultValue": "Inventory-Asset-Management",
11 | "type": "String"
12 | },
13 | "ClientId": {
14 | "defaultValue": "",
15 | "type": "String"
16 | },
17 | "ClientSecret": {
18 | "defaultValue": "",
19 | "type": "SecureString"
20 | },
21 | "EASMWorkspaceName": {
22 | "defaultValue": "",
23 | "type": "String"
24 | },
25 | "RunFrequency": {
26 | "defaultValue": 24,
27 | "type": "Int",
28 | "metadata": {
29 | "description": "Schedule in Hours"
30 | }
31 | },
32 | "api-version": {
33 | "defaultValue": "2022-11-01-preview",
34 | "type": "String"
35 | },
36 | "LabelName": {
37 | "defaultValue": "",
38 | "type": "String",
39 | "metadata": {
40 | "description": "Label Assets will be tagged with"
41 | }
42 | },
43 | "filter": {
44 | "defaultValue": "",
45 | "type": "String",
46 | "metadata": {
47 | "description": "Inventory Asset Query"
48 | }
49 | },
50 | "maxpagesize": {
51 | "defaultValue": "50",
52 | "type": "String"
53 | },
54 | "stateValue": {
55 | "defaultValue": "",
56 | "type": "String",
57 | "metadata": {
58 | "description": "allowed values: archived, candidate, associatedThirdparty, associated, dismissed, candidateInvestigate, confirmed, associatedPartner"
59 | }
60 | }
61 | },
62 | "variables": {},
63 | "resources": [
64 | {
65 | "type": "Microsoft.Logic/workflows",
66 | "apiVersion": "2017-07-01",
67 | "name": "[parameters('workflows_Inventory_Asset_Management_name')]",
68 | "location": "[resourceGroup().location]",
69 | "tags": {},
70 | "properties": {
71 | "state": "Enabled",
72 | "definition": {
73 | "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
74 | "contentVersion": "1.0.0.0",
75 | "parameters": {
76 | "ClientId": {
77 | "defaultValue": "",
78 | "type": "String"
79 | },
80 | "ClientSecret": {
81 | "defaultValue": "",
82 | "type": "SecureString"
83 | },
84 | "EASMWorkspaceName": {
85 | "defaultValue": "",
86 | "type": "String"
87 | },
88 | "LabelName": {
89 | "defaultValue": "",
90 | "type": "String"
91 | },
92 | "Region": {
93 | "defaultValue": "[resourceGroup().location]",
94 | "type": "String"
95 | },
96 | "ResourceGroupName": {
97 | "defaultValue": "[resourceGroup().name]",
98 | "type": "String"
99 | },
100 | "RunFrequency": {
101 | "defaultValue": 12,
102 | "type": "Int"
103 | },
104 | "SubscriptionId": {
105 | "defaultValue": "[subscription().subscriptionId]",
106 | "type": "String"
107 | },
108 | "TenantId": {
109 | "defaultValue": "[subscription().tenantId]",
110 | "type": "String"
111 | },
112 | "api-version": {
113 | "defaultValue": "2022-11-01-preview",
114 | "type": "String"
115 | },
116 | "filter": {
117 | "defaultValue": "",
118 | "type": "String"
119 | },
120 | "maxpagesize": {
121 | "defaultValue": "50",
122 | "type": "String"
123 | },
124 | "stateValue": {
125 | "defaultValue": "",
126 | "type": "String"
127 | }
128 | },
129 | "triggers": {
130 | "Recurrence": {
131 | "recurrence": {
132 | "frequency": "Hour",
133 | "interval": "@parameters('RunFrequency')"
134 | },
135 | "evaluatedRecurrence": {
136 | "frequency": "Hour",
137 | "interval": 12
138 | },
139 | "type": "Recurrence",
140 | "conditions": [],
141 | "runtimeConfiguration": {
142 | "concurrency": {
143 | "runs": 1
144 | }
145 | }
146 | }
147 | },
148 | "actions": {
149 | "Condition": {
150 | "actions": {
151 | "Create_Label": {
152 | "runAfter": {},
153 | "limit": {
154 | "timeout": "PT90S"
155 | },
156 | "type": "Http",
157 | "inputs": {
158 | "authentication": {
159 | "audience": "https://management.core.windows.net/",
160 | "clientId": "@parameters('ClientId')",
161 | "secret": "@parameters('ClientSecret')",
162 | "tenant": "@parameters('TenantId')",
163 | "type": "ActiveDirectoryOAuth"
164 | },
165 | "body": {},
166 | "headers": {
167 | "Content-Type": "application/json",
168 | "User-Agent": "GitHub-LogicApps-AssetManagement"
169 | },
170 | "method": "PUT",
171 | "queries": {
172 | "api-version": "@parameters('api-version')"
173 | },
174 | "retryPolicy": {
175 | "count": 10,
176 | "interval": "PT20S",
177 | "type": "fixed"
178 | },
179 | "uri": "https://management.azure.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/providers/Microsoft.Easm/workspaces/@{parameters('EASMWorkspaceName')}/labels/@{parameters('LabelName')}"
180 | }
181 | },
182 | "Set_var_jobId": {
183 | "runAfter": {
184 | "Update_Assets": [
185 | "Succeeded"
186 | ]
187 | },
188 | "type": "SetVariable",
189 | "inputs": {
190 | "name": "JobId",
191 | "value": "@{body('Update_Assets')?['id']}"
192 | }
193 | },
194 | "Update_Assets": {
195 | "runAfter": {
196 | "Create_Label": [
197 | "Succeeded"
198 | ]
199 | },
200 | "limit": {
201 | "timeout": "PT90S"
202 | },
203 | "type": "Http",
204 | "inputs": {
205 | "authentication": {
206 | "audience": "https://easm.defender.microsoft.com/",
207 | "clientId": "@parameters('ClientId')",
208 | "secret": "@parameters('ClientSecret')",
209 | "tenant": "@parameters('TenantId')",
210 | "type": "ActiveDirectoryOAuth"
211 | },
212 | "body": "@variables('updateBody')",
213 | "headers": {
214 | "Content-Type": "application/json",
215 | "User-Agent": "GitHub-LogicApps-AssetManagement"
216 | },
217 | "method": "PATCH",
218 | "queries": {
219 | "api-version": "@parameters('api-version')",
220 | "filter": "@parameters('filter')"
221 | },
222 | "retryPolicy": {
223 | "count": 10,
224 | "interval": "PT20S",
225 | "type": "fixed"
226 | },
227 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
228 | }
229 | }
230 | },
231 | "runAfter": {
232 | "Update_EASM_Asset": [
233 | "Failed",
234 | "Succeeded"
235 | ]
236 | },
237 | "else": {
238 | "actions": {
239 | "Condition_4": {
240 | "actions": {
241 | "Set_var_jobId_2": {
242 | "runAfter": {},
243 | "type": "SetVariable",
244 | "inputs": {
245 | "name": "JobId",
246 | "value": "@{body('Update_EASM_Asset')?['id']}"
247 | }
248 | }
249 | },
250 | "runAfter": {},
251 | "else": {
252 | "actions": {
253 | "Terminate": {
254 | "runAfter": {},
255 | "type": "Terminate",
256 | "inputs": {
257 | "runStatus": "Failed"
258 | }
259 | }
260 | }
261 | },
262 | "expression": {
263 | "and": [
264 | {
265 | "equals": [
266 | "@outputs('Update_EASM_Asset')['statusCode']",
267 | 200
268 | ]
269 | }
270 | ]
271 | },
272 | "type": "If"
273 | }
274 | }
275 | },
276 | "expression": {
277 | "and": [
278 | {
279 | "equals": [
280 | "@outputs('Update_EASM_Asset')['statusCode']",
281 | 400
282 | ]
283 | }
284 | ]
285 | },
286 | "type": "If",
287 | "description": "If label does not exist, this path creates it and then updates assets with newly created label"
288 | },
289 | "Initialize_JobId_Var": {
290 | "runAfter": {
291 | "Initialize_updateBody_Var": [
292 | "Succeeded"
293 | ]
294 | },
295 | "type": "InitializeVariable",
296 | "inputs": {
297 | "variables": [
298 | {
299 | "name": "JobId",
300 | "type": "string"
301 | }
302 | ]
303 | }
304 | },
305 | "Initialize_updateBody_Var": {
306 | "runAfter": {},
307 | "type": "InitializeVariable",
308 | "inputs": {
309 | "variables": [
310 | {
311 | "name": "updateBody",
312 | "type": "object",
313 | "value": {}
314 | }
315 | ]
316 | }
317 | },
318 | "Until": {
319 | "actions": {
320 | "Delay": {
321 | "runAfter": {
322 | "check_job_status": [
323 | "Succeeded"
324 | ]
325 | },
326 | "type": "Wait",
327 | "inputs": {
328 | "interval": {
329 | "count": 10,
330 | "unit": "Minute"
331 | }
332 | }
333 | },
334 | "check_job_status": {
335 | "runAfter": {},
336 | "type": "Http",
337 | "inputs": {
338 | "authentication": {
339 | "audience": "https://easm.defender.microsoft.com/",
340 | "clientId": "@parameters('ClientId')",
341 | "secret": "@parameters('ClientSecret')",
342 | "tenant": "@parameters('TenantId')",
343 | "type": "ActiveDirectoryOAuth"
344 | },
345 | "headers": {
346 | "Content-Type": "application/json",
347 | "User-Agent": "GitHub-LogicApps-AssetManagement"
348 | },
349 | "method": "GET",
350 | "queries": {
351 | "api-version": "@parameters('api-version')"
352 | },
353 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/tasks/@{variables('JobId')}"
354 | }
355 | }
356 | },
357 | "runAfter": {
358 | "Condition": [
359 | "Succeeded"
360 | ]
361 | },
362 | "expression": "@equals(body('check_job_status')?['state'], 'complete')",
363 | "limit": {
364 | "count": 8,
365 | "timeout": "PT2H"
366 | },
367 | "type": "Until"
368 | },
369 | "Update_Condition": {
370 | "actions": {
371 | "Set_updateBody": {
372 | "runAfter": {},
373 | "type": "SetVariable",
374 | "inputs": {
375 | "name": "updateBody",
376 | "value": {
377 | "labels": {
378 | "@{parameters('LabelName')}": true
379 | },
380 | "state": "@{parameters('stateValue')}"
381 | }
382 | }
383 | }
384 | },
385 | "runAfter": {
386 | "Initialize_JobId_Var": [
387 | "Succeeded"
388 | ]
389 | },
390 | "else": {
391 | "actions": {
392 | "update_label_or_state": {
393 | "actions": {
394 | "Set_updateBody_2": {
395 | "runAfter": {},
396 | "type": "SetVariable",
397 | "inputs": {
398 | "name": "updateBody",
399 | "value": {
400 | "labels": {
401 | "@{parameters('LabelName')}": true
402 | }
403 | }
404 | }
405 | }
406 | },
407 | "runAfter": {},
408 | "else": {
409 | "actions": {
410 | "Set_updateBody_3": {
411 | "runAfter": {},
412 | "type": "SetVariable",
413 | "inputs": {
414 | "name": "updateBody",
415 | "value": {
416 | "state": "@{parameters('stateValue')}"
417 | }
418 | }
419 | }
420 | }
421 | },
422 | "expression": {
423 | "and": [
424 | {
425 | "greater": [
426 | "@length(parameters('LabelName'))",
427 | 1
428 | ]
429 | }
430 | ]
431 | },
432 | "type": "If"
433 | }
434 | }
435 | },
436 | "expression": {
437 | "and": [
438 | {
439 | "greater": [
440 | "@length(parameters('stateValue'))",
441 | 1
442 | ]
443 | },
444 | {
445 | "greater": [
446 | "@length(parameters('LabelName'))",
447 | 1
448 | ]
449 | }
450 | ]
451 | },
452 | "type": "If"
453 | },
454 | "Update_EASM_Asset": {
455 | "runAfter": {
456 | "Update_Condition": [
457 | "Succeeded"
458 | ]
459 | },
460 | "limit": {
461 | "timeout": "PT90S"
462 | },
463 | "type": "Http",
464 | "inputs": {
465 | "authentication": {
466 | "audience": "https://easm.defender.microsoft.com/",
467 | "clientId": "@parameters('ClientId')",
468 | "secret": "@parameters('ClientSecret')",
469 | "tenant": "@parameters('TenantId')",
470 | "type": "ActiveDirectoryOAuth"
471 | },
472 | "body": "@variables('updateBody')",
473 | "headers": {
474 | "Content-Type": "application/json",
475 | "User-Agent": "GitHub-LogicApps-AssetManagement"
476 | },
477 | "method": "PATCH",
478 | "queries": {
479 | "api-version": "@parameters('api-version')",
480 | "filter": "@{parameters('filter')} "
481 | },
482 | "retryPolicy": {
483 | "count": 10,
484 | "interval": "PT20S",
485 | "type": "fixed"
486 | },
487 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
488 | },
489 | "description": "Update Alerted EASM Assets with a label to track history "
490 | }
491 | },
492 | "outputs": {}
493 | },
494 | "parameters": {
495 | "ClientId": {
496 | "value": "[parameters('ClientId')]"
497 | },
498 | "ClientSecret": {
499 | "value": "[parameters('ClientSecret')]"
500 | },
501 | "EASMWorkspaceName": {
502 | "value": "[parameters('EASMWorkspaceName')]"
503 | },
504 | "LabelName": {
505 | "value": "[parameters('LabelName')]"
506 | },
507 | "RunFrequency": {
508 | "value": "[parameters('RunFrequency')]"
509 | },
510 | "api-version": {
511 | "value": "[parameters('api-version')]"
512 | },
513 | "filter": {
514 | "value": "[parameters('filter')]"
515 | },
516 | "maxpagesize": {
517 | "value": "[parameters('maxpagesize')]"
518 | },
519 | "stateValue": {
520 | "value": "[parameters('stateValue')]"
521 | }
522 | }
523 | }
524 | }
525 | ]
526 | }
527 |
--------------------------------------------------------------------------------
/Automation/Inventory-Asset-Management/Readme.md:
--------------------------------------------------------------------------------
1 | # MDEASM: Inventory Rules/Query based Asset Management
2 |
3 | ## Overview
4 | Playbook demonstrates automation that can be scheduled to run at regular intervals to update Inventory Assets by querying for certain vulnerabilities or set criteria using the "filter" parameter from your MDEASM Inventory.
5 |
6 | ### Asset update options for this playbooks are,
7 | 1. Apply labels
8 | 2. Change Asset Status
9 | 3. Do both Change Asset Status and Apply label
10 |
11 | 1. The playbook queries MDEASM Inventory using the 'filter' parameter and updates inventory Asset results
12 | 2. The 'RunFrequency' parameter (In Hours) can be used to change the schedule to run the playbook as needed. By default it is run very 24 Hours.
13 | 3. The 'LabelName' parameter is used to apply the label by the playbook on the resultant Inventory Assets. The playbook will create a new label, if the label provided doesn't already exist in the EASM Workspace.
14 | 4. The 'StateValue' parameter is used to mention the New Changed State needed for Inventory Assets. allowed Asset state values: archived, candidate, associatedThirdparty, associated, dismissed, candidateInvestigate, confirmed, associatedPartner.
15 | 5. The Playbook also checks the status of the EASM Update till it completes successfully within the EASM Workspace.
16 | 6. The Playbook will remain in running state or get failed if the update takes more than 2 hours to complete. Upon which it that playbook instance can be Re-Run.
17 |
18 | ## Prerequisites
19 | 1. MDEASM API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
20 | 2. Atleast one of the parameters 'LabelName' and/or 'StateValue' is needed to be set fo rthe playbook to run
21 | 3. MDEASM filter parameter needs to be set to an appropriate value to query inventory assets. Refer MDEASM API documentation
22 | For Example: here's a query to monitor and alert for all assets with CVSS Score >= 8
23 | state="confirmed" and kind = "page" and rooturl = true and cvssScore >= 8
24 |
25 | ## Deployment
26 |
27 |
28 |
32 |
33 |
34 | ### Post-Deployment Instructions
35 | After deploying the playbook, you must authorize the connections leveraged.
36 |
37 | 1. Visit the playbook resource.
38 | 2. Under "Development Tools" (located on the left), click "API Connections".
39 | 3. Ensure each connection has been authorized.
40 |
41 | The playbook can be edited if any custom changes needed.
42 |
--------------------------------------------------------------------------------
/Automation/Inventory-Assets-Download-Keyvault/Inventory-Assets-Download-Keyvault.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "metadata": {
5 | "comments": "Automation: Azure Logic App process to download MD EASM Inventory Assets and their details to Onedrive Storage using Azure KeyVault for storing EASM API Client Secrets",
6 | "author": "MD EASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com"
7 | },
8 | "parameters": {
9 | "workflows_InventoryAssetsDownload_name": {
10 | "defaultValue": "EASM-Inventory-Assets-Download",
11 | "type": "String"
12 | },
13 | "ClientId": {
14 | "defaultValue": "",
15 | "type": "String"
16 | },
17 | "KeyVaultSecretName": {
18 | "defaultValue": "",
19 | "type": "String"
20 | },
21 | "EASMWorkspaceName": {
22 | "defaultValue": "",
23 | "type": "String"
24 | },
25 | "EASMRegion": {
26 | "defaultValue": "",
27 | "type": "String",
28 | "allowedValues": [
29 | "southcentralus",
30 | "eastus",
31 | "australiaeast",
32 | "westus3",
33 | "swedencentral",
34 | "eastasia",
35 | "japaneast",
36 | "westeurope",
37 | "northeurope",
38 | "switzerlandnorth",
39 | "canadacentral",
40 | "centralus",
41 | "norwayeast",
42 | "francecentral",
43 | ""
44 | ],
45 | "metadata": {
46 | "description": "Allowed Azure region values, southcentralus, eastus, australiaeast, westus3, swedencentral, eastasia, japaneast, westeurope, northeurope, switzerlandnorth, canadacentral, centralus, norwayeast, francecentral"
47 | }
48 | },
49 | "RunFrequency": {
50 | "defaultValue": 1,
51 | "type": "Int"
52 | },
53 | "api-version": {
54 | "defaultValue": "2022-11-01-preview",
55 | "type": "String"
56 | },
57 | "filter": {
58 | "defaultValue": "state = \"confirmed\"",
59 | "type": "String"
60 | },
61 | "maxpagesize": {
62 | "defaultValue": "100",
63 | "type": "String"
64 | },
65 | "recentDays": {
66 | "defaultValue": 180,
67 | "type": "Int"
68 | }
69 | },
70 | "variables": {
71 | "OnedriveConnectionName": "[concat('Onedrive-', parameters('workflows_InventoryAssetsDownload_name'))]",
72 | "KeyvaultConnectionName": "[concat('Keyvault-', parameters('workflows_InventoryAssetsDownload_name'))]"
73 | },
74 | "resources": [
75 | {
76 | "type": "Microsoft.Web/connections",
77 | "apiVersion": "2016-06-01",
78 | "name": "[variables('OnedriveConnectionName')]",
79 | "location": "[resourceGroup().location]",
80 | "properties": {
81 | "api": {
82 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/onedriveforbusiness')]"
83 | }
84 | }
85 | },
86 | {
87 | "type": "Microsoft.Web/connections",
88 | "apiVersion": "2016-06-01",
89 | "name": "[variables('KeyvaultConnectionName')]",
90 | "location": "[resourceGroup().location]",
91 | "properties": {
92 | "api": {
93 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/keyvault')]"
94 | }
95 | }
96 | },
97 | {
98 | "type": "Microsoft.Logic/workflows",
99 | "apiVersion": "2017-07-01",
100 | "name": "[parameters('workflows_InventoryAssetsDownload_name')]",
101 | "location": "[resourceGroup().location]",
102 | "dependsOn": [
103 | "[resourceId('Microsoft.Web/connections', variables('OnedriveConnectionName'))]",
104 | "[resourceId('Microsoft.Web/connections', variables('KeyvaultConnectionName'))]"
105 | ],
106 | "properties": {
107 | "state": "Enabled",
108 | "definition": {
109 | "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
110 | "contentVersion": "1.0.0.0",
111 | "parameters": {
112 | "$connections": {
113 | "defaultValue": {},
114 | "type": "Object"
115 | },
116 | "ClientId": {
117 | "defaultValue": "",
118 | "type": "String"
119 | },
120 | "EASMRegion": {
121 | "defaultValue": "",
122 | "allowedValues": [
123 | "southcentralus",
124 | "eastus",
125 | "australiaeast",
126 | "westus3",
127 | "swedencentral",
128 | "eastasia",
129 | "japaneast",
130 | "westeurope",
131 | "northeurope",
132 | "switzerlandnorth",
133 | "canadacentral",
134 | "centralus",
135 | "norwayeast",
136 | "francecentral"
137 | ],
138 | "type": "String"
139 | },
140 | "EASMWorkspaceName": {
141 | "defaultValue": "",
142 | "type": "String"
143 | },
144 | "KeyVaultSecretName": {
145 | "defaultValue": "",
146 | "type": "String"
147 | },
148 | "ResourceGroupName": {
149 | "defaultValue": "[resourceGroup().name]",
150 | "type": "String"
151 | },
152 | "RunFrequency": {
153 | "defaultValue": 1,
154 | "type": "Int"
155 | },
156 | "SubscriptionId": {
157 | "defaultValue": "[subscription().subscriptionId]",
158 | "type": "String"
159 | },
160 | "TenantId": {
161 | "defaultValue": "[subscription().tenantId]",
162 | "type": "String"
163 | },
164 | "api-version": {
165 | "defaultValue": "2022-11-01-preview",
166 | "type": "String"
167 | },
168 | "filter": {
169 | "defaultValue": "state = \"confirmed\"",
170 | "type": "String"
171 | },
172 | "maxpagesize": {
173 | "defaultValue": "100",
174 | "type": "String"
175 | },
176 | "recentDays": {
177 | "defaultValue": 180,
178 | "type": "Int"
179 | }
180 | },
181 | "staticResults": {
182 | "HTTP0": {
183 | "status": "Succeeded",
184 | "outputs": {
185 | "headers": {},
186 | "statusCode": "OK"
187 | }
188 | }
189 | },
190 | "triggers": {
191 | "Recurrence": {
192 | "recurrence": {
193 | "frequency": "Day",
194 | "interval": "@parameters('RunFrequency')"
195 | },
196 | "evaluatedRecurrence": {
197 | "frequency": "Day",
198 | "interval": 1
199 | },
200 | "type": "Recurrence"
201 | }
202 | },
203 | "actions": {
204 | "Get_secret": {
205 | "runAfter": {
206 | "Set_calculateDate": [
207 | "Succeeded"
208 | ]
209 | },
210 | "type": "ApiConnection",
211 | "inputs": {
212 | "host": {
213 | "connection": {
214 | "name": "@parameters('$connections')['keyvault_2']['connectionId']"
215 | }
216 | },
217 | "method": "get",
218 | "path": "/secrets/@{encodeURIComponent(parameters('KeyVaultSecretName'))}/value"
219 | }
220 | },
221 | "Initialize_Mark": {
222 | "runAfter": {},
223 | "type": "InitializeVariable",
224 | "inputs": {
225 | "variables": [
226 | {
227 | "name": "mark",
228 | "type": "string",
229 | "value": "*"
230 | }
231 | ]
232 | }
233 | },
234 | "Initialize_calculateDate": {
235 | "runAfter": {
236 | "Initialize_Mark": [
237 | "Succeeded"
238 | ]
239 | },
240 | "type": "InitializeVariable",
241 | "inputs": {
242 | "variables": [
243 | {
244 | "name": "calculateDate",
245 | "type": "string",
246 | "value": "@{utcNow()}"
247 | }
248 | ]
249 | }
250 | },
251 | "Set_calculateDate": {
252 | "runAfter": {
253 | "Initialize_calculateDate": [
254 | "Succeeded"
255 | ]
256 | },
257 | "type": "SetVariable",
258 | "inputs": {
259 | "name": "calculateDate",
260 | "value": "@{getPastTime(parameters('recentDays'), 'Day', 's')}.000Z"
261 | }
262 | },
263 | "Until": {
264 | "actions": {
265 | "Until_2": {
266 | "actions": {
267 | "Create_file": {
268 | "runAfter": {
269 | "Mark": [
270 | "Succeeded"
271 | ]
272 | },
273 | "limit": {
274 | "timeout": "PT1H"
275 | },
276 | "type": "ApiConnection",
277 | "inputs": {
278 | "body": "@body('HTTP')",
279 | "host": {
280 | "connection": {
281 | "name": "@parameters('$connections')['onedrive_1']['connectionId']"
282 | }
283 | },
284 | "method": "post",
285 | "path": "/datasets/default/files",
286 | "queries": {
287 | "folderPath": "/Test/output",
288 | "name": "@{iterationIndexes('Until')}_@{iterationIndexes('Until_2')}_Assets_@{utcNow()}.json"
289 | },
290 | "retryPolicy": {
291 | "count": 10,
292 | "interval": "PT20S",
293 | "type": "fixed"
294 | }
295 | },
296 | "runtimeConfiguration": {
297 | "contentTransfer": {
298 | "transferMode": "Chunked"
299 | }
300 | }
301 | },
302 | "HTTP": {
303 | "runAfter": {},
304 | "limit": {
305 | "timeout": "PT180S"
306 | },
307 | "type": "Http",
308 | "inputs": {
309 | "authentication": {
310 | "audience": "https://easm.defender.microsoft.com/",
311 | "clientId": "@parameters('ClientId')",
312 | "secret": "@body('Get_secret')?['value']",
313 | "tenant": "@parameters('TenantId')",
314 | "type": "ActiveDirectoryOAuth"
315 | },
316 | "headers": {
317 | "Content-Type": "application/json",
318 | "User-Agent": "GitHub-LogicApps-InventoryDownload"
319 | },
320 | "method": "GET",
321 | "queries": {
322 | "api-version": "@parameters('api-version')",
323 | "filter": " @{parameters('filter')} and lastSeen>=\"@{variables('calculateDate')}\"",
324 | "mark": "@variables('mark')",
325 | "maxpagesize": "@{parameters('maxpagesize')}"
326 | },
327 | "retryPolicy": {
328 | "count": 10,
329 | "interval": "PT20S",
330 | "type": "fixed"
331 | },
332 | "uri": "https://@{parameters('EASMRegion')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
333 | },
334 | "runtimeConfiguration": {
335 | "contentTransfer": {
336 | "transferMode": "Chunked"
337 | },
338 | "staticResult": {
339 | "staticResultOptions": "Disabled",
340 | "name": "HTTP0"
341 | }
342 | }
343 | },
344 | "Mark": {
345 | "runAfter": {
346 | "Parse_JSON": [
347 | "Succeeded"
348 | ]
349 | },
350 | "type": "SetVariable",
351 | "inputs": {
352 | "name": "mark",
353 | "value": "@body('Parse_JSON')?['mark']"
354 | }
355 | },
356 | "Parse_JSON": {
357 | "runAfter": {
358 | "HTTP": [
359 | "Succeeded"
360 | ]
361 | },
362 | "type": "ParseJson",
363 | "inputs": {
364 | "content": "@body('HTTP')",
365 | "schema": {
366 | "properties": {
367 | "content": {
368 | "type": "array"
369 | },
370 | "first": {
371 | "type": "boolean"
372 | },
373 | "last": {
374 | "type": "boolean"
375 | },
376 | "mark": {
377 | "type": "string"
378 | },
379 | "nextLink": {
380 | "type": "string"
381 | },
382 | "number": {
383 | "type": "integer"
384 | },
385 | "numberOfElements": {
386 | "type": "integer"
387 | },
388 | "size": {
389 | "type": "integer"
390 | },
391 | "totalElements": {
392 | "type": "integer"
393 | },
394 | "totalPages": {
395 | "type": "integer"
396 | }
397 | },
398 | "type": "object"
399 | }
400 | }
401 | }
402 | },
403 | "runAfter": {},
404 | "expression": "@equals(body('Parse_JSON')?['last'], true)",
405 | "limit": {
406 | "count": 4999,
407 | "timeout": "PT20H"
408 | },
409 | "type": "Until"
410 | }
411 | },
412 | "runAfter": {
413 | "Get_secret": [
414 | "Succeeded"
415 | ]
416 | },
417 | "expression": "@equals(body('Parse_JSON')?['last'], true)",
418 | "limit": {
419 | "count": 4999,
420 | "timeout": "P3D"
421 | },
422 | "type": "Until"
423 | }
424 | },
425 | "outputs": {}
426 | },
427 | "parameters": {
428 | "$connections": {
429 | "value": {
430 | "keyvault_2": {
431 | "connectionId": "[resourceId('Microsoft.Web/connections', variables('KeyvaultConnectionName'))]",
432 | "connectionName": "[variables('KeyvaultConnectionName')]",
433 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/keyvault')]"
434 | },
435 | "onedrive_1": {
436 | "connectionId": "[resourceId('Microsoft.Web/connections', variables('OnedriveConnectionName'))]",
437 | "connectionName": "[variables('OnedriveConnectionName')]",
438 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/onedriveforbusiness')]"
439 | }
440 | }
441 | },
442 | "ClientId": {
443 | "value": "[parameters('ClientId')]"
444 | },
445 | "EASMWorkspaceName": {
446 | "value": "[parameters('EASMWorkspaceName')]"
447 | },
448 | "EASMRegion": {
449 | "value": "[parameters('EASMRegion')]"
450 | },
451 |
452 | "KeyVaultSecretName": {
453 | "value": "[parameters('KeyVaultSecretName')]"
454 | },
455 | "RunFrequency": {
456 | "value": "[parameters('RunFrequency')]"
457 | },
458 | "api-version": {
459 | "value": "[parameters('api-version')]"
460 | },
461 | "filter": {
462 | "value": "[parameters('filter')]"
463 | },
464 | "maxpagesize": {
465 | "value": "[parameters('maxpagesize')]"
466 | },
467 | "recentDays": {
468 | "value": "[parameters('recentDays')]"
469 | }
470 | }
471 | }
472 | }
473 | ]
474 | }
--------------------------------------------------------------------------------
/Automation/Inventory-Assets-Download-Keyvault/Readme.md:
--------------------------------------------------------------------------------
1 | # MDEASM: Inventory Assets Download using Azure KeyVault
2 |
3 | ## Overview
4 | Playbook demonstrates automation to download MDEASM Inventory assets and their details to Onedrive Storage using Azure KeyVault to store and access EASM API Client Secret Values providing a template to Query EASM at regular intervals to get Asset data and integrate into your desired storage solution.
5 |
6 | 1. The playbook queries MDEASM Inventory using the 'filter' parameter and saves the API response in a specified folder in OneDrive Storage as JSON Files with datetimestamp in the file name.
7 | 2. The default 'filter' parameter is set to query all Inventory Assets in the "Approved Inventory" Status. the parameter is made available to set your inventory query to match your requirements. Refer MDEASM API documentation for more details on this.
8 | 3. The playbook uses OneDrive Logic Apps Connector
9 | 4. This same process can be used to download newly added and updated assets in Inventory on a daily basis or at a set run frequency by including parameter "recentDays" to 1.
10 |
11 | ## Prerequisites
12 | 1. MDEASM API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
13 | 2. OneDrive connection requires authorization using your login and access to the folder path where the files need to be saved
14 | 3. MDEASM filter parameter needs to be set to an appropriate value to query inventory assets. Refer MDEASM API documentation
15 | 4. KeyVault "Get Secret" connection requires authorization using your login with your "KeyVault Name" and "tenantId"
16 |
17 | ## Deployment
18 |
19 |
20 |
24 |
25 |
26 | ### Post-Deployment Instructions
27 | After deploying the playbook, you must authorize the connections leveraged.
28 |
29 | 1. Visit the playbook resource.
30 | 2. Under "Development Tools" (located on the left), click "API Connections".
31 | 3. Ensure each connection has been authorized.
32 |
33 | The playbook can be edited if any custom or parameter changes needed.
34 |
--------------------------------------------------------------------------------
/Automation/Inventory-Assets-Download/Inventory-Assets-Download.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "metadata": {
5 | "comments": "Automation: Azure Logic App process to download MD EASM Inventory Assets and their details to Onedrive Storage",
6 | "author": "MD EASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com"
7 | },
8 | "parameters": {
9 | "workflows_InventoryAssetsDownload_name": {
10 | "defaultValue": "Inventory-Assets-Download",
11 | "type": "String"
12 | },
13 | "ClientId": {
14 | "defaultValue": "Client-ID",
15 | "type": "String"
16 | },
17 | "ClientSecret": {
18 | "defaultValue": "Client-Secret",
19 | "type": "SecureString"
20 | },
21 | "EASMWorkspaceName": {
22 | "defaultValue": "WorkspaceName",
23 | "type": "String"
24 | },
25 | "EASMRegion": {
26 | "defaultValue": "",
27 | "type": "String",
28 | "allowedValues": [
29 | "southcentralus",
30 | "eastus",
31 | "australiaeast",
32 | "westus3",
33 | "swedencentral",
34 | "eastasia",
35 | "japaneast",
36 | "westeurope",
37 | "northeurope",
38 | "switzerlandnorth",
39 | "canadacentral",
40 | "centralus",
41 | "norwayeast",
42 | "francecentral",
43 | ""
44 | ],
45 | "metadata": {
46 | "description": "Allowed Azure region values, southcentralus, eastus, australiaeast, westus3, swedencentral, eastasia, japaneast, westeurope, northeurope, switzerlandnorth, canadacentral, centralus, norwayeast, francecentral"
47 | }
48 | },
49 | "RunFrequency": {
50 | "defaultValue": 1,
51 | "type": "Int"
52 | },
53 | "api-version": {
54 | "defaultValue": "2022-11-01-preview",
55 | "type": "String"
56 | },
57 | "filter": {
58 | "defaultValue": "state = \"confirmed\"",
59 | "type": "String"
60 | },
61 | "maxpagesize": {
62 | "defaultValue": "100",
63 | "type": "String"
64 | },
65 | "recentDays": {
66 | "defaultValue": 180,
67 | "type": "Int"
68 | }
69 | },
70 | "variables": {
71 | "OnedriveConnectionName": "[concat('Onedrive-', parameters('workflows_InventoryAssetsDownload_name'))]"
72 | },
73 | "resources": [
74 | {
75 | "type": "Microsoft.Web/connections",
76 | "apiVersion": "2016-06-01",
77 | "name": "[variables('OnedriveConnectionName')]",
78 | "location": "[resourceGroup().location]",
79 | "properties": {
80 | "api": {
81 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/onedriveforbusiness')]"
82 | }
83 | }
84 | },
85 | {
86 | "type": "Microsoft.Logic/workflows",
87 | "apiVersion": "2017-07-01",
88 | "name": "[parameters('workflows_InventoryAssetsDownload_name')]",
89 | "location": "[resourceGroup().location]",
90 | "dependsOn": [
91 | "[resourceId('Microsoft.Web/connections', variables('OnedriveConnectionName'))]"
92 | ],
93 | "properties": {
94 | "state": "Enabled",
95 | "definition": {
96 | "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
97 | "contentVersion": "1.0.0.0",
98 | "parameters": {
99 | "$connections": {
100 | "defaultValue": {},
101 | "type": "Object"
102 | },
103 | "ClientId": {
104 | "defaultValue": "Client-ID",
105 | "type": "String"
106 | },
107 | "ClientSecret": {
108 | "defaultValue": "Client-Secret",
109 | "type": "SecureString"
110 | },
111 | "EASMWorkspaceName": {
112 | "defaultValue": "workSpaceName",
113 | "type": "String"
114 | },
115 | "EASMRegion": {
116 | "defaultValue": "",
117 | "type": "String",
118 | "allowedValues": [
119 | "southcentralus",
120 | "eastus",
121 | "australiaeast",
122 | "westus3",
123 | "swedencentral",
124 | "eastasia",
125 | "japaneast",
126 | "westeurope",
127 | "northeurope",
128 | "switzerlandnorth",
129 | "canadacentral",
130 | "centralus",
131 | "norwayeast",
132 | "francecentral"
133 | ]
134 | },
135 | "ResourceGroupName": {
136 | "defaultValue": "[resourceGroup().name]",
137 | "type": "String"
138 | },
139 | "RunFrequency": {
140 | "defaultValue": 1,
141 | "type": "Int"
142 | },
143 | "SubscriptionId": {
144 | "defaultValue": "[subscription().subscriptionId]",
145 | "type": "String"
146 | },
147 | "TenantId": {
148 | "defaultValue": "[subscription().tenantId]",
149 | "type": "String"
150 | },
151 | "api-version": {
152 | "defaultValue": "2022-11-01-preview",
153 | "type": "String"
154 | },
155 | "filter": {
156 | "defaultValue": "state = \"confirmed\"",
157 | "type": "String"
158 | },
159 | "maxpagesize": {
160 | "defaultValue": "100",
161 | "type": "String"
162 | },
163 | "recentDays": {
164 | "defaultValue": 180,
165 | "type": "Int"
166 | }
167 | },
168 | "staticResults": {
169 | "HTTP0": {
170 | "status": "Succeeded",
171 | "outputs": {
172 | "headers": {},
173 | "statusCode": "OK"
174 | }
175 | }
176 | },
177 | "triggers": {
178 | "Recurrence": {
179 | "recurrence": {
180 | "frequency": "Day",
181 | "interval": "@parameters('RunFrequency')"
182 | },
183 | "evaluatedRecurrence": {
184 | "frequency": "Day",
185 | "interval": 1
186 | },
187 | "type": "Recurrence"
188 | }
189 | },
190 | "actions": {
191 | "Initialize_Mark": {
192 | "runAfter": {},
193 | "type": "InitializeVariable",
194 | "inputs": {
195 | "variables": [
196 | {
197 | "name": "mark",
198 | "type": "string",
199 | "value": "*"
200 | }
201 | ]
202 | }
203 | },
204 | "Initialize_calculateDate": {
205 | "runAfter": {
206 | "Initialize_Mark": [
207 | "Succeeded"
208 | ]
209 | },
210 | "type": "InitializeVariable",
211 | "inputs": {
212 | "variables": [
213 | {
214 | "name": "calculateDate",
215 | "type": "string",
216 | "value": "@{utcNow()}"
217 | }
218 | ]
219 | }
220 | },
221 | "Set_calculateDate": {
222 | "runAfter": {
223 | "Initialize_calculateDate": [
224 | "Succeeded"
225 | ]
226 | },
227 | "type": "SetVariable",
228 | "inputs": {
229 | "name": "calculateDate",
230 | "value": "@{getPastTime(parameters('recentDays'), 'Day', 's')}.000Z"
231 | }
232 | },
233 | "Until": {
234 | "actions": {
235 | "Until_2": {
236 | "actions": {
237 | "Create_file": {
238 | "runAfter": {
239 | "Mark": [
240 | "Succeeded"
241 | ]
242 | },
243 | "limit": {
244 | "timeout": "PT1H"
245 | },
246 | "type": "ApiConnection",
247 | "inputs": {
248 | "body": "@body('HTTP')",
249 | "host": {
250 | "connection": {
251 | "name": "@parameters('$connections')['onedrive_1']['connectionId']"
252 | }
253 | },
254 | "method": "post",
255 | "path": "/datasets/default/files",
256 | "queries": {
257 | "folderPath": "/Test/output",
258 | "name": "@{iterationIndexes('Until')}_@{iterationIndexes('Until_2')}_Assets_@{utcNow()}.json"
259 | },
260 | "retryPolicy": {
261 | "count": 10,
262 | "interval": "PT20S",
263 | "type": "fixed"
264 | }
265 | },
266 | "runtimeConfiguration": {
267 | "contentTransfer": {
268 | "transferMode": "Chunked"
269 | }
270 | }
271 | },
272 | "HTTP": {
273 | "runAfter": {},
274 | "limit": {
275 | "timeout": "PT180S"
276 | },
277 | "type": "Http",
278 | "inputs": {
279 | "authentication": {
280 | "audience": "https://easm.defender.microsoft.com/",
281 | "clientId": "@parameters('ClientId')",
282 | "secret": "@parameters('ClientSecret')",
283 | "tenant": "@parameters('TenantId')",
284 | "type": "ActiveDirectoryOAuth"
285 | },
286 | "headers": {
287 | "Content-Type": "application/json",
288 | "User-Agent": "GitHub-LogicApps-InventoryDownload"
289 | },
290 | "method": "GET",
291 | "queries": {
292 | "api-version": "@parameters('api-version')",
293 | "filter": " @{parameters('filter')} and lastSeen>=\"@{variables('calculateDate')}\"",
294 | "mark": "@variables('mark')",
295 | "maxpagesize": "@{parameters('maxpagesize')}"
296 | },
297 | "retryPolicy": {
298 | "count": 10,
299 | "interval": "PT20S",
300 | "type": "fixed"
301 | },
302 | "uri": "https://@{parameters('EASMRegion')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
303 | },
304 | "runtimeConfiguration": {
305 | "contentTransfer": {
306 | "transferMode": "Chunked"
307 | },
308 | "staticResult": {
309 | "staticResultOptions": "Disabled",
310 | "name": "HTTP0"
311 | }
312 | }
313 | },
314 | "Mark": {
315 | "runAfter": {
316 | "Parse_JSON": [
317 | "Succeeded"
318 | ]
319 | },
320 | "type": "SetVariable",
321 | "inputs": {
322 | "name": "mark",
323 | "value": "@body('Parse_JSON')?['mark']"
324 | }
325 | },
326 | "Parse_JSON": {
327 | "runAfter": {
328 | "HTTP": [
329 | "Succeeded"
330 | ]
331 | },
332 | "type": "ParseJson",
333 | "inputs": {
334 | "content": "@body('HTTP')",
335 | "schema": {
336 | "properties": {
337 | "content": {
338 | "type": "array"
339 | },
340 | "first": {
341 | "type": "boolean"
342 | },
343 | "last": {
344 | "type": "boolean"
345 | },
346 | "mark": {
347 | "type": "string"
348 | },
349 | "nextLink": {
350 | "type": "string"
351 | },
352 | "number": {
353 | "type": "integer"
354 | },
355 | "numberOfElements": {
356 | "type": "integer"
357 | },
358 | "size": {
359 | "type": "integer"
360 | },
361 | "totalElements": {
362 | "type": "integer"
363 | },
364 | "totalPages": {
365 | "type": "integer"
366 | }
367 | },
368 | "type": "object"
369 | }
370 | }
371 | }
372 | },
373 | "runAfter": {},
374 | "expression": "@equals(body('Parse_JSON')?['last'], true)",
375 | "limit": {
376 | "count": 4999,
377 | "timeout": "PT20H"
378 | },
379 | "type": "Until"
380 | }
381 | },
382 | "runAfter": {
383 | "Set_calculateDate": [
384 | "Succeeded"
385 | ]
386 | },
387 | "expression": "@equals(body('Parse_JSON')?['last'], true)",
388 | "limit": {
389 | "count": 4999,
390 | "timeout": "P3D"
391 | },
392 | "type": "Until"
393 | }
394 | },
395 | "outputs": {}
396 | },
397 | "parameters": {
398 | "$connections": {
399 | "value": {
400 | "onedrive_1": {
401 | "connectionId": "[resourceId('Microsoft.Web/connections', variables('OnedriveConnectionName'))]",
402 | "connectionName": "[variables('OnedriveConnectionName')]",
403 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/onedriveforbusiness')]"
404 | }
405 | }
406 | },
407 | "ClientId": {
408 | "value": "[parameters('ClientId')]"
409 | },
410 | "ClientSecret": {
411 | "value": "[parameters('ClientSecret')]"
412 | },
413 | "EASMWorkspaceName": {
414 | "value": "[parameters('EASMWorkspaceName')]"
415 | },
416 | "EASMRegion": {
417 | "value": "[parameters('EASMRegion')]"
418 | },
419 | "RunFrequency": {
420 | "value": "[parameters('RunFrequency')]"
421 | },
422 | "api-version": {
423 | "value": "[parameters('api-version')]"
424 | },
425 | "filter": {
426 | "value": "[parameters('filter')]"
427 | },
428 | "maxpagesize": {
429 | "value": "[parameters('maxpagesize')]"
430 | },
431 | "recentDays": {
432 | "value": "[parameters('recentDays')]"
433 | }
434 | }
435 | }
436 | }
437 | ]
438 | }
439 |
--------------------------------------------------------------------------------
/Automation/Inventory-Assets-Download/Readme.md:
--------------------------------------------------------------------------------
1 | # MDEASM: Inventory Assets Download
2 |
3 | ## Overview
4 | Playbook demonstrates automation to download MDEASM Inventory assets and their details to Onedrive Storage providing a template to Query EASM at regular intervals to get Asset data and integrate into your desired storage solution.
5 |
6 | 1. The playbook queries MDEASM Inventory using the 'filter' parameter and saves the API response in a specified folder in OneDrive Storage as JSON Files with datetimestamp in the file name.
7 | 2. The default 'filter' parameter is set to query all Inventory Assets in the "Approved Inventory" Status. the parameter is made available to set your inventory query to match your requirements. Refer MDEASM API documentation for more details on this.
8 | 3. The playbook uses OneDrive Logic Apps Connector
9 | 4. This same process can be used to download newly added and updated assets in Inventory on a daily basis or at a set run frequency by including parameter "recentDays" to 1.
10 |
11 | ## Prerequisites
12 | 1. MDEASM API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
13 | 2. OneDrive connection requires authorization using your login and access to the folder path where the files need to be saved.
14 | 3. MDEASM filter parameter needs to be set to an appropriate value to query inventory assets. Refer MDEASM API documentation
15 |
16 | ## Deployment
17 |
18 |
19 |
23 |
24 |
25 | ### Post-Deployment Instructions
26 | After deploying the playbook, you must authorize the connections leveraged.
27 |
28 | 1. Visit the playbook resource.
29 | 2. Under "Development Tools" (located on the left), click "API Connections".
30 | 3. Ensure each connection has been authorized.
31 |
32 | The playbook can be edited if any custom or parameter changes needed.
33 |
--------------------------------------------------------------------------------
/Automation/MDTI-MDEASM-Integration/Readme.md:
--------------------------------------------------------------------------------
1 | # MDEASM: MDTI Domain Check
2 |
3 | ## Overview
4 | Playbook demonstrates automation to check all Approved domains in MDEASM and check them against MDTI articles, intel profiles and reputation scores. An email is sent if there is a match on any of these checks.
5 |
6 | 1. The playbook queries MDEASM Inventory using the 'filter' parameter to get all confirmed domains, sends them to MDTI and creates and email alert to review the results
7 | 2. The playbook has a 'RunFrequency' parameter (In Days) can be used to change the schedule to run the playbook as needed. By default it is run every 7 days
8 | 3. The playbook checks if the approved domains are associated to any articles, intel profiles or reputation scores
9 | 4. The playbook uses Azure Logic Apps Office365 Connector as an example for sending Emails. Any other available Email connector can be used in place of this as needed by users.
10 |
11 | ## Prerequisites
12 | 1. MDEASM API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
13 | 2. MDTI API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
14 | 3. Office365 connection requires authorization via login and destination email addresses where Alerts need to be sent
15 |
16 | ## Deployment
17 |
18 |
19 |
23 |
24 |
25 | ### Post-Deployment Instructions
26 | After deploying the playbook, you must authorize the connections leveraged.
27 |
28 | 1. Visit the playbook resource.
29 | 2. Under "Development Tools" (located on the left), click "API Connections".
30 | 3. Ensure each connection has been authorized.
31 |
32 | The playbook can be edited if any custom changes needed.
33 |
--------------------------------------------------------------------------------
/Automation/Qualys-VulnManagement-Integration/Readme.md:
--------------------------------------------------------------------------------
1 | # MDEASM: Qualys Vulnerability Management Integration
2 |
3 | ## Overview
4 | Playbook demonstrates automation to integrate MDEASM Inventory Assets with Qualys Vulnerability Management tool. The solution is customizable by querying MDEASM for certain vulnerabilities or set criteria from your MDEASM Inventory and selected Host IP Addresses are transmitted to Qualys and tracked via labels in MDEASM.
5 |
6 | 1. The playbook queries MDEASM Inventory using the 'filter' parameter for "Host" Asset type and transmits these Assets to Qualys.
7 | 2. The playbook has inbuilt trigger condition to run only when Assets are returned by the EASM Query, this allows the playbook to run near-realtime frequency and not add any additional Azure cost. the 'RunFrequency' parameter (In Seconds) can be used to change the schedule to run the playbook as needed. By default it is run very 3600 seconds (hourly)
8 | 3. The playbook also adds/updates User-defined label to the MDEASM Asset detail field 'label' for reference and tracking. this also avoids creating duplicate transactions for the same asset/s.
9 | 4. The playbook solution uses "Add Assets" Qualys API to integrate with it and below Prerequisities cover the requirements
10 |
11 | ## Prerequisites
12 | 1. MDEASM API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
13 | 2. Office365 connection requires authorization via login and destination email addresses where Alerts need to be sent
14 | 3. MDEASM filter parameter needs to be set to an appropriate value to query inventory assets. Refer MDEASM API documentation
15 | For Example: here's an example of a MDEASM query
16 | state="confirmed" and kind = "HOST" and ipAddress !empty and ipv4 = true and cvssScore >= 7
17 | Reference for filtering, https://github.com/Azure/MDEASM-Solutions/blob/main/API%20Postman%20Collection/EASM%20Filter%20Mappings.xlsx
18 | 4. Qualys "Add Assets" API is being utilized for this Integration which requires Qualys API Keys generated with "Unit Manager" permissions to Add Assets with specific Asset Group withiun Qualys.
19 | For Qualys API Documentation, https://qualysguard.qg2.apps.qualys.com/qwebhelp/fo_portal/api_doc/assets/index.htm#t=asset_ips%2Fadd_ips.htm
20 | 5. Qualys Asset Group creation is required beforehand for MD EASM Assets to be transmitted to a specific Asset Group within Qualys, which needs to be enter in the Azure deployment parameter "Qualys Asset Group"
21 | 6. The solution also requires users to enter the correct region URL for Qualys API in the parameter "Qualys Base Url". For Reference on this see, https://www.qualys.com/platform-identification/
22 |
23 |
24 | ## Deployment
25 |
26 |
27 |
31 |
32 |
33 | ### Post-Deployment Instructions
34 |
35 |
36 | The playbook can be edited if any custom changes needed.
37 |
--------------------------------------------------------------------------------
/Automation/Rapid7-VulnManagement-Integration/Readme.md:
--------------------------------------------------------------------------------
1 | # MDEASM: Rapid7 InsightVM Vulnerability Management Integration
2 |
3 | ## Overview
4 | Playbook demonstrates automation to integrate MDEASM Inventory Assets with Rapid7 InsightVM Vulnerability Management tool. The solution is customizable by querying MDEASM for certain vulnerabilities or set criteria from your MDEASM Inventory and selected Host IP Addresses are transmitted to Rapid7 InsightVM and tracked via labels in MDEASM.
5 |
6 | 1. The playbook queries MDEASM Inventory using the 'filter' parameter for "Host" Asset type and transmits these Assets to Rapid7 InsightVM.
7 | 2. The playbook has inbuilt trigger condition to run only when Assets are returned by the EASM Query, this allows the playbook to run near-realtime frequency and not add any additional Azure cost. the 'RunFrequency' parameter (In Seconds) can be used to change the schedule to run the playbook as needed. By default it is run very 3600 seconds (hourly)
8 | 3. The playbook also adds/updates User-defined label to the MDEASM Asset detail field 'label' for reference and tracking. this also avoids creating duplicate transactions for the same asset/s.
9 | 4. The playbook solution uses "Create Assets" Rapid7 InsightVM API to integrate with it and below Prerequisities cover the requirements
10 |
11 | ## Prerequisites
12 | 1. MDEASM API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
13 | 2. MDEASM filter parameter needs to be set to an appropriate value to query inventory assets. Refer MDEASM API documentation
14 | For Example: here's an example of a MDEASM query
15 | state="confirmed" and kind = "HOST" and ipAddress !empty and ipv4 = true and cvssScore >= 7
16 | Reference for filtering, https://github.com/Azure/MDEASM-Solutions/blob/main/API%20Postman%20Collection/EASM%20Filter%20Mappings.xlsx
17 | 3. Rapid7 InsightVM "Create Assets" API is being utilized for this Integration which requires Rapid7 InsightVM API Keys (Username & Password) generated with write permissions to Add Assets within Rapid7.
18 | For Rapid7 InsightVM API Documentation, https://help.rapid7.com/insightvm/en-us/api/index.html#operation/createAsset
19 | 4. The solution also requires users to enter the correct server name or hostname with port number used for hosting the InsightVM instance. these values are available as parameters in this Azure Template as "Rapid7-Hostname" and "Rapid7-HostPort"
20 |
21 |
22 | ## Deployment
23 |
24 |
25 |
29 |
30 |
31 | ### Post-Deployment Instructions
32 |
33 |
34 | The playbook can be edited if any custom changes needed.
35 |
--------------------------------------------------------------------------------
/Automation/Readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## About
4 | This repo contains sample playbooks for security automation, orchestration and response (SOAR). Each folder contains a Azure Logic App playbook ARM template using Microsoft Defender External Attack Surface Management (MDEASM) API.
5 |
6 | ## Instructions for deploying a custom template
7 | After selecting a playbook, in the Azure portal:
8 | 1. Search for deploy a custom template
9 | 2. Click build your own template in the editor
10 | 3. Paste the contents from the GitHub playbook
11 | 4. Click **Save**
12 | 5. Fill in needed data and click **Review+Create**
13 |
14 | Once deployment is complete, you will need to authorize each connection.
15 | 1. For Example, Click the Service-now connection resource
16 | 2. Click edit API connection
17 | 3. Click Authorize
18 | 4. Sign in
19 | 5. Click Save
20 | 6. Repeat steps for other connections
21 |
22 | You can now edit the playbook in Azure Logic apps.
23 |
24 | MDEASM API documentation can be found here, https://learn.microsoft.com/en-us/rest/api/defenderforeasm/
25 |
26 | ## Suggestions and feedback
27 | We value your feedback. Let us know if you run into any problems or share your suggestions and feedback to MDEASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com
28 |
--------------------------------------------------------------------------------
/Automation/Tenable-VulnManagement-Integration/Readme.md:
--------------------------------------------------------------------------------
1 | # MDEASM: Tenable Vulnerability Management Integration
2 |
3 | ## Overview
4 | Playbook demonstrates automation to integrate MDEASM Inventory Assets with Tenable Vulnerability Management tool. The solution is customizable by querying MDEASM for certain vulnerabilities or set criteria from your MDEASM Inventory and selected Host IP Addresses are transmitted to Tenable and tracked via labels in MDEASM.
5 |
6 | 1. The playbook queries MDEASM Inventory using the 'filter' parameter for "Host" Asset type and transmits these Assets to tenable.
7 | 2. The playbook has inbuilt trigger condition to run only when Assets are returned by the EASM Query, this allows the playbook to run near-realtime frequency and not add any additional Azure cost. the 'RunFrequency' parameter (In Seconds) can be used to change the schedule to run the playbook as needed. By default it is run very 3600 seconds (hourly)
8 | 3. The playbook also adds/updates User-defined label to the MDEASM Asset detail field 'label' for reference and tracking. this also avoids creating duplicate transactions for the same asset/s.
9 | 4. The playbook solution uses "Import Assets" Tenable API to integrate with it and below Prerequisities cover the requirements
10 |
11 | ## Prerequisites
12 | 1. MDEASM API in this playbook supports Azure AD Authentication which requires you to have an App registration or Service Principal setup and used for authorization
13 | 2. Office365 connection requires authorization via login and destination email addresses where Alerts need to be sent
14 | 3. MDEASM filter parameter needs to be set to an appropriate value to query inventory assets. Refer MDEASM API documentation
15 | For Example: here's an example of a MDEASM query
16 | state="confirmed" and kind = "HOST" and ipAddress !empty and ipv4 = true and cvssScore >= 7
17 | Reference for filtering, https://github.com/Azure/MDEASM-Solutions/blob/main/API%20Postman%20Collection/EASM%20Filter%20Mappings.xlsx
18 | 4. Tenable "Import Assets" API is being utilized for this Integration which requires Tenable API Keys generated with "ADMINISTRATOR [64] user permissions and CAN EDIT [64] scan permissions"
19 | Tenable API reference, https://developer.tenable.com/reference/assets-import/
20 | https://developer.tenable.com/docs/authorization/
21 | https://developer.tenable.com/docs/add-asset-data-to-tenableio/
22 |
23 | ## Deployment
24 |
25 |
26 |
30 |
31 |
32 | ### Post-Deployment Instructions
33 |
34 |
35 | The playbook can be edited if any custom changes needed.
36 |
--------------------------------------------------------------------------------
/Automation/Tenable-VulnManagement-Integration/Tenable-VulnIntegration.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "metadata": {
5 | "comments": "Automation: Azure Logic App process to integrate MDEASM Inventory Host IP Addresses with Tenable Vulnerability Management Tool using a predefined/custom Inventory query and also label the Assets in Inventory selected for Tenable Vuln scanning.",
6 | "author": "MD EASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com"
7 | },
8 | "parameters": {
9 | "workflows_TenableVulnIntegration_name": {
10 | "defaultValue": "Tenable-VulnIntegration",
11 | "type": "String"
12 | },
13 | "ClientId": {
14 | "defaultValue": "Client-ID",
15 | "type": "String"
16 | },
17 | "ClientSecret": {
18 | "defaultValue": "Client-Secret",
19 | "type": "SecureString"
20 | },
21 | "EASMWorkspaceName": {
22 | "defaultValue": "WorkspaceName",
23 | "type": "String"
24 | },
25 | "RunFrequency": {
26 | "defaultValue": 3600,
27 | "type": "Int"
28 | },
29 | "api-version": {
30 | "defaultValue": "2022-11-01-preview",
31 | "type": "String"
32 | },
33 | "LabelName": {
34 | "defaultValue": "InTenable",
35 | "type": "String"
36 | },
37 | "filter": {
38 | "defaultValue": "state=\"confirmed\" and kind=\"host\" and ipAddress !empty and ipv4=true",
39 | "type": "String"
40 | },
41 | "maxpagesize": {
42 | "defaultValue": "49",
43 | "type": "String"
44 | },
45 | "Tenable-AccessKey": {
46 | "defaultValue": "Tenable-AccessKey",
47 | "type": "String"
48 | },
49 | "Tenable-SecretKey": {
50 | "defaultValue": "Tenable-SecretKey",
51 | "type": "SecureString"
52 | }
53 | },
54 | "variables": {},
55 | "resources": [
56 | {
57 | "type": "Microsoft.Logic/workflows",
58 | "apiVersion": "2017-07-01",
59 | "name": "[parameters('workflows_TenableVulnIntegration_name')]",
60 | "location": "[resourceGroup().location]",
61 | "properties": {
62 | "state": "Enabled",
63 | "definition": {
64 | "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
65 | "contentVersion": "1.0.0.0",
66 | "parameters": {
67 | "ClientId": {
68 | "defaultValue": "Client-ID",
69 | "type": "String"
70 | },
71 | "ClientSecret": {
72 | "defaultValue": "Client-Secret",
73 | "type": "SecureString"
74 | },
75 | "EASMWorkspaceName": {
76 | "defaultValue": "workSpaceName",
77 | "type": "String"
78 | },
79 | "LabelName": {
80 | "defaultValue": "InTenable",
81 | "type": "String"
82 | },
83 | "Region": {
84 | "defaultValue": "[resourceGroup().location]",
85 | "type": "String"
86 | },
87 | "ResourceGroupName": {
88 | "defaultValue": "[resourceGroup().name]",
89 | "type": "String"
90 | },
91 | "RunFrequency": {
92 | "defaultValue": 3600,
93 | "type": "Int"
94 | },
95 | "SubscriptionId": {
96 | "defaultValue": "[subscription().subscriptionId]",
97 | "type": "String"
98 | },
99 | "Tenable-AccessKey": {
100 | "defaultValue": "Tenable-AccessKey",
101 | "type": "String"
102 | },
103 | "Tenable-SecretKey": {
104 | "defaultValue": "Tenable-SecretKey",
105 | "type": "SecureString"
106 | },
107 | "TenantId": {
108 | "defaultValue": "[subscription().tenantId]",
109 | "type": "String"
110 | },
111 | "api-version": {
112 | "defaultValue": "2022-11-01-preview",
113 | "type": "String"
114 | },
115 | "filter": {
116 | "defaultValue": "state=\"confirmed\" and kind=\"host\" and ipAddress !empty and ipv4=true",
117 | "type": "String"
118 | },
119 | "maxpagesize": {
120 | "defaultValue": "49",
121 | "type": "String"
122 | }
123 | },
124 | "triggers": {
125 | "Scheduled_Query_to_EASM": {
126 | "recurrence": {
127 | "frequency": "Second",
128 | "interval": "@parameters('RunFrequency')"
129 | },
130 | "evaluatedRecurrence": {
131 | "frequency": "Second",
132 | "interval": 86400
133 | },
134 | "type": "Http",
135 | "inputs": {
136 | "authentication": {
137 | "audience": "https://easm.defender.microsoft.com/",
138 | "clientId": "@parameters('ClientId')",
139 | "secret": "@parameters('ClientSecret')",
140 | "tenant": "@parameters('TenantId')",
141 | "type": "ActiveDirectoryOAuth"
142 | },
143 | "headers": {
144 | "Content-Type": "application/json",
145 | "User-Agent": "GitHub-TenableVM"
146 | },
147 | "method": "GET",
148 | "queries": {
149 | "api-version": "@parameters('api-version')",
150 | "filter": "@{parameters('filter')} and label != @{parameters('LabelName')}",
151 | "mark": "*",
152 | "maxpagesize": "@parameters('maxpagesize')"
153 | },
154 | "retryPolicy": {
155 | "count": 6,
156 | "interval": "PT20S",
157 | "type": "fixed"
158 | },
159 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
160 | },
161 | "conditions": [
162 | {
163 | "expression": "@greater(triggerBody()?.totalElements,0)"
164 | }
165 | ],
166 | "runtimeConfiguration": {
167 | "concurrency": {
168 | "runs": 1
169 | }
170 | }
171 | }
172 | },
173 | "actions": {
174 | "Condition": {
175 | "actions": {
176 | "Create_Label": {
177 | "runAfter": {},
178 | "limit": {
179 | "timeout": "PT90S"
180 | },
181 | "type": "Http",
182 | "inputs": {
183 | "authentication": {
184 | "audience": "https://management.core.windows.net/",
185 | "clientId": "@parameters('ClientId')",
186 | "secret": "@parameters('ClientSecret')",
187 | "tenant": "@parameters('TenantId')",
188 | "type": "ActiveDirectoryOAuth"
189 | },
190 | "body": {},
191 | "headers": {
192 | "Content-Type": "application/json",
193 | "User-Agent": "GitHub-TenableVM"
194 | },
195 | "method": "PUT",
196 | "queries": {
197 | "api-version": "2022-04-01-preview"
198 | },
199 | "retryPolicy": {
200 | "count": 10,
201 | "interval": "PT20S",
202 | "type": "fixed"
203 | },
204 | "uri": "https://management.azure.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups@{parameters('ResourceGroupName')}/providers/Microsoft.Easm/workspaces/@{parameters('EASMWorkspaceName')}/labels/@{parameters('LabelName')}"
205 | }
206 | },
207 | "Update_Assets": {
208 | "runAfter": {
209 | "Create_Label": [
210 | "Succeeded"
211 | ]
212 | },
213 | "limit": {
214 | "timeout": "PT90S"
215 | },
216 | "type": "Http",
217 | "inputs": {
218 | "authentication": {
219 | "audience": "https://easm.defender.microsoft.com/",
220 | "clientId": "@parameters('ClientId')",
221 | "secret": "@parameters('ClientSecret')",
222 | "tenant": "@parameters('TenantId')",
223 | "type": "ActiveDirectoryOAuth"
224 | },
225 | "body": {
226 | "labels": {
227 | "@{parameters('LabelName')}": true
228 | }
229 | },
230 | "headers": {
231 | "Content-Type": "application/json",
232 | "User-Agent": "GitHub-TenableVM"
233 | },
234 | "method": "PATCH",
235 | "queries": {
236 | "api-version": "@parameters('api-version')",
237 | "filter": "name in (\"@{body('Join')}\")"
238 | },
239 | "retryPolicy": {
240 | "count": 10,
241 | "interval": "PT20S",
242 | "type": "fixed"
243 | },
244 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
245 | }
246 | }
247 | },
248 | "runAfter": {
249 | "Update_EASM_Asset": [
250 | "Failed",
251 | "TimedOut"
252 | ]
253 | },
254 | "expression": {
255 | "and": [
256 | {
257 | "equals": [
258 | "@outputs('Update_EASM_Asset')['statusCode']",
259 | 400
260 | ]
261 | }
262 | ]
263 | },
264 | "type": "If",
265 | "description": "If label does not exist, this path creates it and then updates assets with newly created label"
266 | },
267 | "For_each_Host_asset": {
268 | "foreach": "@body('Parse_JSON')?['content']",
269 | "actions": {
270 | "loop_through_IP_Array": {
271 | "foreach": "@items('For_each_Host_asset')['asset']['ipAddresses']",
272 | "actions": {
273 | "Append_to_Host_IP_array_variable": {
274 | "runAfter": {},
275 | "type": "AppendToArrayVariable",
276 | "inputs": {
277 | "name": "Host IP",
278 | "value": "@items('loop_through_IP_Array')?['value']"
279 | }
280 | }
281 | },
282 | "runAfter": {},
283 | "type": "Foreach"
284 | }
285 | },
286 | "runAfter": {
287 | "Initialize_Host_IP_Var": [
288 | "Succeeded"
289 | ]
290 | },
291 | "type": "Foreach"
292 | },
293 | "Initialize_Host_IP_Var": {
294 | "runAfter": {
295 | "Parse_JSON": [
296 | "Succeeded"
297 | ]
298 | },
299 | "type": "InitializeVariable",
300 | "inputs": {
301 | "variables": [
302 | {
303 | "name": "Host IP",
304 | "type": "array"
305 | }
306 | ]
307 | }
308 | },
309 | "Initialize_deduplicate_Host_IP_variable": {
310 | "runAfter": {
311 | "For_each_Host_asset": [
312 | "Succeeded"
313 | ]
314 | },
315 | "type": "InitializeVariable",
316 | "inputs": {
317 | "variables": [
318 | {
319 | "name": "finalIP",
320 | "type": "array"
321 | }
322 | ]
323 | }
324 | },
325 | "Join": {
326 | "runAfter": {
327 | "Set_deduplicate_Host_IP_variable": [
328 | "Succeeded"
329 | ]
330 | },
331 | "type": "Join",
332 | "inputs": {
333 | "from": "@union(variables('finalIP'), variables('finalIP'))",
334 | "joinWith": "\",\""
335 | }
336 | },
337 | "Parse_JSON": {
338 | "runAfter": {},
339 | "type": "ParseJson",
340 | "inputs": {
341 | "content": "@triggerBody()",
342 | "schema": {
343 | "properties": {
344 | "content": {
345 | "items": {
346 | "properties": {
347 | "asset": {
348 | "properties": {
349 | "domain": {
350 | "type": "string"
351 | },
352 | "host": {
353 | "type": "string"
354 | },
355 | "ipAddresses": {
356 | "items": {
357 | "properties": {
358 | "firstSeen": {
359 | "type": "string"
360 | },
361 | "lastSeen": {
362 | "type": "string"
363 | },
364 | "recent": {
365 | "type": "boolean"
366 | },
367 | "sources": {
368 | "type": "array"
369 | },
370 | "value": {
371 | "type": "string"
372 | }
373 | },
374 | "required": [
375 | "value"
376 | ],
377 | "type": "object"
378 | },
379 | "type": "array"
380 | }
381 | },
382 | "type": "object"
383 | },
384 | "auditTrail": {
385 | "items": {
386 | "properties": {
387 | "displayName": {},
388 | "id": {},
389 | "kind": {
390 | "type": "string"
391 | },
392 | "name": {
393 | "type": "string"
394 | },
395 | "reason": {}
396 | },
397 | "required": [
398 | "id",
399 | "name",
400 | "displayName",
401 | "kind",
402 | "reason"
403 | ],
404 | "type": "object"
405 | },
406 | "type": "array"
407 | },
408 | "createdDate": {
409 | "type": "string"
410 | },
411 | "discoGroupName": {
412 | "type": "string"
413 | },
414 | "displayName": {
415 | "type": "string"
416 | },
417 | "externalId": {},
418 | "id": {
419 | "type": "string"
420 | },
421 | "kind": {
422 | "type": "string"
423 | },
424 | "labels": {
425 | "type": "array"
426 | },
427 | "name": {
428 | "type": "string"
429 | },
430 | "reason": {},
431 | "state": {
432 | "type": "string"
433 | },
434 | "updatedDate": {
435 | "type": "string"
436 | },
437 | "uuid": {
438 | "type": "string"
439 | },
440 | "wildcard": {
441 | "type": "boolean"
442 | }
443 | },
444 | "required": [
445 | "id",
446 | "name",
447 | "displayName",
448 | "kind",
449 | "uuid",
450 | "asset",
451 | "createdDate",
452 | "updatedDate",
453 | "state",
454 | "externalId",
455 | "labels",
456 | "wildcard",
457 | "discoGroupName",
458 | "auditTrail",
459 | "reason"
460 | ],
461 | "type": "object"
462 | },
463 | "type": "array"
464 | },
465 | "first": {
466 | "type": "boolean"
467 | },
468 | "last": {
469 | "type": "boolean"
470 | },
471 | "mark": {
472 | "type": "string"
473 | },
474 | "number": {
475 | "type": "integer"
476 | },
477 | "numberOfElements": {
478 | "type": "integer"
479 | },
480 | "size": {
481 | "type": "integer"
482 | },
483 | "totalElements": {
484 | "type": "integer"
485 | },
486 | "totalPages": {
487 | "type": "integer"
488 | }
489 | },
490 | "type": "object"
491 | }
492 | }
493 | },
494 | "Send_to_Tenable": {
495 | "runAfter": {
496 | "Join": [
497 | "Succeeded"
498 | ]
499 | },
500 | "limit": {
501 | "timeout": "PT60S"
502 | },
503 | "type": "Http",
504 | "inputs": {
505 | "body": {
506 | "assets": [
507 | {
508 | "ipv4": "@union(variables('finalIP'), variables('finalIP'))"
509 | }
510 | ],
511 | "source": "MDEASM"
512 | },
513 | "headers": {
514 | "Content-Type": "application/json",
515 | "X-ApiKeys": "accessKey=@{parameters('Tenable-AccessKey')};secretKey=@{parameters('Tenable-SecretKey')}"
516 | },
517 | "method": "POST",
518 | "retryPolicy": {
519 | "count": 10,
520 | "interval": "PT20S",
521 | "type": "fixed"
522 | },
523 | "uri": "https://cloud.tenable.com/import/assets"
524 | }
525 | },
526 | "Set_deduplicate_Host_IP_variable": {
527 | "runAfter": {
528 | "Initialize_deduplicate_Host_IP_variable": [
529 | "Succeeded"
530 | ]
531 | },
532 | "type": "SetVariable",
533 | "inputs": {
534 | "name": "finalIP",
535 | "value": "@variables('Host IP')"
536 | }
537 | },
538 | "Update_EASM_Asset": {
539 | "runAfter": {
540 | "Send_to_Tenable": [
541 | "Succeeded"
542 | ]
543 | },
544 | "limit": {
545 | "timeout": "PT90S"
546 | },
547 | "type": "Http",
548 | "inputs": {
549 | "authentication": {
550 | "audience": "https://easm.defender.microsoft.com/",
551 | "clientId": "@parameters('ClientId')",
552 | "secret": "@parameters('ClientSecret')",
553 | "tenant": "@parameters('TenantId')",
554 | "type": "ActiveDirectoryOAuth"
555 | },
556 | "body": {
557 | "labels": {
558 | "@{parameters('LabelName')}": true
559 | },
560 | "transfers": [
561 | "host"
562 | ]
563 | },
564 | "headers": {
565 | "Content-Type": "application/json",
566 | "User-Agent": "GitHub-TenableVM"
567 | },
568 | "method": "PATCH",
569 | "queries": {
570 | "api-version": "@parameters('api-version')",
571 | "filter": "name in (\"@{body('Join')}\")"
572 | },
573 | "retryPolicy": {
574 | "count": 10,
575 | "interval": "PT20S",
576 | "type": "fixed"
577 | },
578 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets"
579 | },
580 | "description": "Update Alerted EASM Assets with a label to track history "
581 | }
582 | },
583 | "outputs": {}
584 | },
585 | "parameters": {
586 | "ClientId": {
587 | "value": "[parameters('ClientId')]"
588 | },
589 | "ClientSecret": {
590 | "value": "[parameters('ClientSecret')]"
591 | },
592 | "EASMWorkspaceName": {
593 | "value": "[parameters('EASMWorkspaceName')]"
594 | },
595 | "RunFrequency": {
596 | "value": "[parameters('RunFrequency')]"
597 | },
598 | "LabelName": {
599 | "value": "[parameters('LabelName')]"
600 | },
601 | "api-version": {
602 | "value": "[parameters('api-version')]"
603 | },
604 | "filter": {
605 | "value": "[parameters('filter')]"
606 | },
607 | "maxpagesize": {
608 | "value": "[parameters('maxpagesize')]"
609 | },
610 | "Tenable-AccessKey": {
611 | "value": "[parameters('Tenable-AccessKey')]"
612 | },
613 | "Tenable-SecretKey": {
614 | "value": "[parameters('Tenable-SecretKey')]"
615 | }
616 | }
617 | }
618 | }
619 | ]
620 | }
--------------------------------------------------------------------------------
/Automation/logic_app_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/MDEASM-Solutions/0fcf868649fc05e83622d5533e4caddf3c7f9ee0/Automation/logic_app_logo.png
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/Inventory Queries/DefaultOpenPages.txt:
--------------------------------------------------------------------------------
1 | # Please edit/add the filter parameters in order to identify Default Open Pages for Apache, IIS & Nginx
2 |
3 | kind = "PAGE" and status = "confirmed" and rootUrl = "true" and pageTitle ~ "Index of" or pageTitle ~ "Apache" or pageTitle ~ "IIS Windows Server" or pageTitle = "nginx"
4 |
--------------------------------------------------------------------------------
/Inventory Queries/EASM Filter Mappings.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/MDEASM-Solutions/0fcf868649fc05e83622d5533e4caddf3c7f9ee0/Inventory Queries/EASM Filter Mappings.xlsx
--------------------------------------------------------------------------------
/Inventory Queries/Readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## About
4 | This repo contains the filters which can be used to label the attack surface for specific use cases.
5 |
6 | ## Instructions for adding the filter
7 | The filters can be used in the API or in the logic apps.
8 | MDEASM API documentation can be found here, https://learn.microsoft.com/en-us/rest/api/defenderforeasm/
9 | These filters can also be added to Logic Apps such as Inventory-Alerts-Email, https://github.com/Azure/MDEASM-Solutions/tree/main/Automation/Inventory-Alerts-Email
10 |
11 |
12 | After selecting a playbook from https://github.com/Azure/MDEASM-Solutions:
13 | 1. Click "Deploy to Azure"
14 | 2. Wait for Microsoft Azure to load
15 | 3. Edit all the relevant fields such as the Label Name, Run Frequency and Filter (located in each txt file within this directory)
16 | 4. Click **Review+Create**
17 |
18 | Once deployment is complete, you will need to authorize each connection.
19 | 1. For Example, Click the Email Connection resource
20 | 2. Select a Email Connection or create a new Email Connection
21 | 3. Click Authorize
22 | 4. Sign in
23 | 5. Click Save
24 | 6. Repeat steps for other connections
25 |
26 | You can now edit the playbook in Azure Logic apps.
27 |
28 | ## Suggestions and feedback
29 | We value your feedback. Let us know if you run into any problems or share your suggestions and feedback to MDEASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com
--------------------------------------------------------------------------------
/Jupyter-Notebooks/README.md:
--------------------------------------------------------------------------------
1 | ## MDEASM API sample Jupyter Notebooks
2 | This repo contains sample notebooks for using the Microsoft Defender External Attack Surface Management (MDEASM) API.
3 |
4 | These Jupyter Notebooks demonstrate the usage of the MDEASM API endpoints that allow users to access their attack surface data easily using PowerShell or Python in an interactive environment.
5 |
6 | Available endpoints/actions:
7 | Assets - List
8 | Assets - Get
9 | Assets - Update
10 | Tasks - Get
11 | Tasks - List
12 | Tasks - Cancel
13 | Bonus Function - Get Common Assets
14 | Labels - Create And Update
15 | Labels - List
16 | Labels - Get
17 | Labels - Delete
18 | Labels - Update
19 |
20 |
21 | ## Instructions to use the notebooks
22 | Recommended - Use VS Code and Extensions
23 | Python notebook, follow these steps:
24 | 1. Install [VS Code](https://code.visualstudio.com/)
25 | 2. Add the [Python Extension for VS Code](https://marketplace.visualstudio.com/items?itemName=ms-python.python) once configured, `pip install requests`
26 | 3. Add the [Jupyter Extension for VS Code](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter)
27 |
28 | PowerShell notebook, follow these steps:
29 | 1. Install [VS Code](https://code.visualstudio.com/)
30 | 2. Add the [PowerShell Extension for VS Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell)
31 | 3. Add the [.NET Extension Pack](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.vscode-dotnet-pack) which includes Jupyter support
32 |
33 | Non-VS Code setups vary by language preference and operating systems...
34 |
35 | 4. Enter in the required MDEASM information (tenantId, subscriptionId, resourceGroupName, workspaceName, region, service principal clientId, & clientSecret)
36 | 5. See the helper file [**EASM Filter Mappings.xlsx**](https://github.com/Azure/MDEASM-Solutions/blob/main/API%20Postman%20Collection/EASM%20Filter%20Mappings.xlsx) for finding queryable field names for Asset Search parameter "filter"
37 |
38 | MDEASM API documentation can be found here, https://learn.microsoft.com/en-us/rest/api/defenderforeasm/
39 |
40 | Azure AD Authentication details can be found here, https://docs.microsoft.com/en-us/rest/api/azure/#how-to-call-azure-rest-apis-with-postman
41 |
42 |
43 |
44 | ## Suggestions and feedback
45 | We value your feedback. Let us know if you run into any problems or share your suggestions and feedback to MDEASM Go-To-Production (GTP) Customer Experience Engineering (CxE) Team. Email: mdeasm_cxe@microsoft.com
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
5 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
6 |
7 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide
8 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
9 | provided by the bot. You will only need to do this once across all repos using our CLA.
10 |
11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
14 |
15 | ## Trademarks
16 |
17 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
18 | trademarks or logos is subject to and must follow
19 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
20 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
21 | Any use of third-party trademarks or logos are subject to those third-party's policies.
22 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # TODO: The maintainer of this repo has not yet edited this file
2 |
3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project?
4 |
5 | - **No CSS support:** Fill out this template with information about how to file issues and get help.
6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps.
7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide.
8 |
9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.*
10 |
11 | # Support
12 |
13 | ## How to file issues and get help
14 |
15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing
16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or
17 | feature request as a new Issue.
18 |
19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE
20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER
21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**.
22 |
23 | ## Microsoft Support Policy
24 |
25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above.
26 |
--------------------------------------------------------------------------------
/Scripts/billable_assets.py:
--------------------------------------------------------------------------------
1 | #imports
2 | from azure.defender.easm import EasmClient
3 | from azure.mgmt.defendereasm import EasmMgmtClient
4 | from azure.identity import ClientSecretCredential
5 | import xlsxwriter
6 | import sys
7 |
8 | # Script parameters
9 | client_id = ''
10 | # App Client secret
11 | client_secret = ''
12 | # Tenant ID
13 | tenant_id = ''
14 | # Subscription ID
15 | subcription_id = ''
16 | # Resource Group Name Where EASM resides
17 | resource_group = ''
18 | # EASM Region
19 | region = ''
20 | # Name of EASM resource
21 | workspace_name = ''
22 |
23 | # Get credentials and create client
24 | completeCredential = ClientSecretCredential(tenant_id, client_id, client_secret)
25 | dataEndpoint = f'{region}.easm.defender.microsoft.com'
26 | dataClient = EasmClient(dataEndpoint, resource_group, subcription_id, workspace_name, completeCredential)
27 | controlClient = EasmMgmtClient(completeCredential, subcription_id)
28 | workbook = xlsxwriter.Workbook('AssetBreakdown.xlsx', {'strings_to_urls': False})
29 | worksheet = workbook.add_worksheet('Assets')
30 | assetType_list = ["billable_ip_addresses", "billable_domains", "billable_hosts"]
31 |
32 |
33 | def get_billable_list(assetType, count):
34 | page = 0
35 | last_page = False
36 | while last_page is False:
37 | billable = dataClient.reports.snapshot(body={"metric": assetType, "page": page, "size": 100})
38 | last_page = billable['assets']['last']
39 | page += 1
40 | for each_biilable_asset in billable['assets']['content']:
41 | print(each_biilable_asset['name'])
42 | worksheet.write(count, 0, assetType)
43 | worksheet.write(count, 1, each_biilable_asset['name'])
44 | count += 1
45 | return count
46 |
47 | def create_headers():
48 | # Headers
49 | worksheet.write(0, 0, "Asset Type")
50 | worksheet.write(0, 1, "Asset Name")
51 |
52 |
53 | def main():
54 | create_headers()
55 | AssetPageCount = 1
56 | for each_assetType in assetType_list:
57 | AssetPageCount = get_billable_list(each_assetType, AssetPageCount)
58 | workbook.close()
59 |
60 |
61 | if __name__ == '__main__':
62 | sys.exit(main())
63 |
--------------------------------------------------------------------------------
/Workbook/.images/image_workbook_consolidated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure/MDEASM-Solutions/0fcf868649fc05e83622d5533e4caddf3c7f9ee0/Workbook/.images/image_workbook_consolidated.png
--------------------------------------------------------------------------------
/Workbook/README.md:
--------------------------------------------------------------------------------
1 | # MDEASM
2 | MD External Attack Surface Management workbook for connecting to either a Log Analytics or Azure Data Explorer source
3 |
4 | ### Conolidated workbook with all visualizations in either a single scrollable page or clickable tabs
5 |
6 | If your `EASM Workspace Name` dropdown fails to populate, then you have one (or more) of the following problems:
7 | 1. your Azure Data Explorer Cluster URI and/or Database name are wrong
8 | 2. your Log Analytics workspace name and/or Resource Group name were entered incorrectly when you deployed the workbook
9 | 3. your Azure Data Explorer and/or Log Analytics do(es) not have data (empty tables; best to confirm this directly within `Azure Data Explorer/Query` or `Log Analytics/Logs`)
10 |
11 | If you only have a single snapshot of data, then the charts and visuals will populate with that information.
12 | As soon as there is more than one snapshot of data, the Asset and Risk data from the oldest snapshot will be ignored in order to minimize the large variance that can show between pre-built EASM workspaces and those same workspaces after discovery has run.
13 |
14 | [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FMDEASM-Solutions%2Fmain%2FWorkbook%2Fmdeasm_workbook_template.json)
15 | 
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # Starter pipeline
2 | # Start with a minimal pipeline that you can customize to build and deploy your code.
3 | # Add steps that build, run tests, deploy, and more:
4 | # https://aka.ms/yaml
5 |
6 | trigger:
7 | - main
8 |
9 | pool:
10 | vmImage: ubuntu-latest
11 |
12 | steps:
13 | - script: echo Hello, world!
14 | displayName: 'Run a one-line script'
15 |
16 | - script: |
17 | echo Add other tasks to build, test, and deploy your project.
18 | echo See https://aka.ms/yaml
19 | displayName: 'Run a multi-line script'
20 |
--------------------------------------------------------------------------------