├── .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 | Postman 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 

", 483 | "Importance": "Normal", 484 | "Subject": "MDEASM Alert: @{body('Scheduled_Query_to_EASM')?['totalElements']} Assets detected matching your monitoring query", 485 | "To": "TestEmail@test.com" 486 | }, 487 | "host": { 488 | "connection": { 489 | "name": "@parameters('$connections')['office365']['connectionId']" 490 | } 491 | }, 492 | "method": "post", 493 | "path": "/v2/Mail" 494 | } 495 | }, 496 | "Update_EASM_Asset": { 497 | "runAfter": { 498 | "Send_an_email_(V2)": [ 499 | "Succeeded" 500 | ] 501 | }, 502 | "limit": { 503 | "timeout": "PT90S" 504 | }, 505 | "type": "Http", 506 | "inputs": { 507 | "authentication": { 508 | "audience": "https://easm.defender.microsoft.com/", 509 | "clientId": "@parameters('ClientId')", 510 | "secret": "@body('Get_secret')?['value']", 511 | "tenant": "@parameters('TenantId')", 512 | "type": "ActiveDirectoryOAuth" 513 | }, 514 | "body": { 515 | "labels": { 516 | "@{parameters('LabelName')}": true 517 | } 518 | }, 519 | "headers": { 520 | "Content-Type": "application/json", 521 | "User-Agent": "GitHub-LogicApps-EmailAlerts" 522 | }, 523 | "method": "PATCH", 524 | "queries": { 525 | "api-version": "@parameters('api-version')", 526 | "filter": "@{parameters('filter')} and label != @{parameters('LabelName')}" 527 | }, 528 | "retryPolicy": { 529 | "count": 10, 530 | "interval": "PT20S", 531 | "type": "fixed" 532 | }, 533 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets" 534 | }, 535 | "description": "Update Alerted EASM Assets with a label to track history " 536 | } 537 | }, 538 | "outputs": {} 539 | }, 540 | "parameters": { 541 | "$connections": { 542 | "value": { 543 | "keyvault_1": { 544 | "connectionId": "[resourceId('Microsoft.Web/connections', variables('KeyvaultConnectionName'))]", 545 | "connectionName": "[variables('KeyvaultConnectionName')]", 546 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/keyvault')]" 547 | }, 548 | "office365": { 549 | "connectionId": "[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", 550 | "connectionName": "[variables('Office365ConnectionName')]", 551 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/office365')]" 552 | } 553 | } 554 | }, 555 | "ClientId": { 556 | "value": "[parameters('ClientId')]" 557 | }, 558 | "EASMWorkspaceName": { 559 | "value": "[parameters('EASMWorkspaceName')]" 560 | }, 561 | "KeyVaultSecretName": { 562 | "value": "[parameters('KeyVaultSecretName')]" 563 | }, 564 | "LabelName": { 565 | "value": "[parameters('LabelName')]" 566 | }, 567 | "RunFrequency": { 568 | "value": "[parameters('RunFrequency')]" 569 | }, 570 | "api-version": { 571 | "value": "[parameters('api-version')]" 572 | }, 573 | "filter": { 574 | "value": "[parameters('filter')]" 575 | }, 576 | "Region": { 577 | "value": "[parameters('Region')]" 578 | }, 579 | "maxpagesize": { 580 | "value": "[parameters('maxpagesize')]" 581 | } 582 | } 583 | } 584 | } 585 | ] 586 | } -------------------------------------------------------------------------------- /Automation/Inventory-Alerts-Email-KeyVault/Readme.md: -------------------------------------------------------------------------------- 1 | # MDEASM: Inventory Email Alerts using Azure Keyvault 2 | 3 | ## Overview 4 | Playbook demonstrates automation to Monitor Inventory Assets and alert via Email notifications 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 email alerts for the inventory Asset results 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 User-defined label to the MDEASM Asset detail field 'label' for reference and tracking. this also avoids creating duplicate alerts for the same assets. 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. 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 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 | 20 | ## Deployment 21 | 22 | 23 | 24 | 25 | 26 | 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 

", 410 | "Importance": "Normal", 411 | "Subject": "MDEASM Alert: @{triggerBody()?['totalElements']} Assets detected matching your monitoring query", 412 | "To": "TestEmail@test.com" 413 | }, 414 | "host": { 415 | "connection": { 416 | "name": "@parameters('$connections')['office365']['connectionId']" 417 | } 418 | }, 419 | "method": "post", 420 | "path": "/v2/Mail" 421 | } 422 | }, 423 | "Update_EASM_Asset": { 424 | "runAfter": { 425 | "Send_an_email_(V2)": [ 426 | "Succeeded" 427 | ] 428 | }, 429 | "limit": { 430 | "timeout": "PT90S" 431 | }, 432 | "type": "Http", 433 | "inputs": { 434 | "authentication": { 435 | "audience": "https://easm.defender.microsoft.com/", 436 | "clientId": "@parameters('ClientId')", 437 | "secret": "@parameters('ClientSecret')", 438 | "tenant": "@parameters('TenantId')", 439 | "type": "ActiveDirectoryOAuth" 440 | }, 441 | "body": { 442 | "labels": { 443 | "@{parameters('LabelName')}": true 444 | } 445 | }, 446 | "headers": { 447 | "Content-Type": "application/json", 448 | "User-Agent": "GitHub-LogicApps-EmailAlerts" 449 | }, 450 | "method": "PATCH", 451 | "queries": { 452 | "api-version": "@parameters('api-version')", 453 | "filter": "@{parameters('filter')} and label != @{parameters('LabelName')}" 454 | }, 455 | "retryPolicy": { 456 | "count": 10, 457 | "interval": "PT20S", 458 | "type": "fixed" 459 | }, 460 | "uri": "https://@{parameters('Region')}.easm.defender.microsoft.com/subscriptions/@{parameters('SubscriptionId')}/resourceGroups/@{parameters('ResourceGroupName')}/workspaces/@{parameters('EASMWorkspaceName')}/assets" 461 | }, 462 | "description": "Update Alerted EASM Assets with a label to track history " 463 | } 464 | }, 465 | "outputs": {} 466 | }, 467 | "parameters": { 468 | "$connections": { 469 | "value": { 470 | "office365": { 471 | "connectionId": "[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", 472 | "connectionName": "[variables('Office365ConnectionName')]", 473 | "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/office365')]" 474 | } 475 | } 476 | }, 477 | "ClientId": { 478 | "value": "[parameters('ClientId')]" 479 | }, 480 | "ClientSecret": { 481 | "value": "[parameters('ClientSecret')]" 482 | }, 483 | "EASMWorkspaceName": { 484 | "value": "[parameters('EASMWorkspaceName')]" 485 | }, 486 | "RunFrequency": { 487 | "value": "[parameters('RunFrequency')]" 488 | }, 489 | "LabelName": { 490 | "value": "[parameters('LabelName')]" 491 | }, 492 | "api-version": { 493 | "value": "[parameters('api-version')]" 494 | }, 495 | "filter": { 496 | "value": "[parameters('filter')]" 497 | }, 498 | "maxpagesize": { 499 | "value": "[parameters('maxpagesize')]" 500 | } 501 | } 502 | } 503 | } 504 | ] 505 | } -------------------------------------------------------------------------------- /Automation/Inventory-Alerts-Email/Readme.md: -------------------------------------------------------------------------------- 1 | # MDEASM: Inventory Email Alerts 2 | 3 | ## Overview 4 | Playbook demonstrates automation to Monitor Inventory Assets and alert via Email notifications 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 email alerts for the inventory Asset results 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 User-defined label to the MDEASM Asset detail field 'label' for reference and tracking. this also avoids creating duplicate alerts for the same assets. 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. 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 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 | 18 | ## Deployment 19 | 20 | 21 | 22 | 23 | 24 | 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 | 29 | 30 | 31 | 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 | 21 | 22 | 23 | 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 | 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 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 | 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/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 | 28 | 29 | 30 | 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 | 26 | 27 | 28 | 29 | 30 | 31 | ### Post-Deployment Instructions 32 | 33 | 34 | The playbook can be edited if any custom changes needed. 35 | -------------------------------------------------------------------------------- /Automation/Readme.md: -------------------------------------------------------------------------------- 1 | LogicApps Logo 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 | 27 | 28 | 29 | 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 | LogicApps Logo 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 | [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FMDEASM-Solutions%2Fmain%2FWorkbook%2Fmdeasm_workbook_template.json) 15 | ![workbook_condolidated](https://raw.githubusercontent.com/Azure/MDEASM-Solutions/main/Workbook/.images/image_workbook_consolidated.png "workbook_condolidated") -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------