-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[ASIM] Web Session AWS WAF #14496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
yummyblabla
merged 6 commits into
Azure:master
from
manuelhauch:bluevoyant/asimwebsession/awswaf
Jun 22, 2026
+1,425
−20
Merged
[ASIM] Web Session AWS WAF #14496
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
c792049
Adding a ASIM WebSession parser for AWS WAF
1ed4e66
Merge remote-tracking branch 'upstream/master' into bluevoyant/asimwe…
cd45e49
Added the Github pull request number and link in the Changelog
67d0b3a
Addressed Copilot and reviewer comments.
fa90af6
Renaming artefacts
aa9d355
Renamed Sample data file due to parser renaming
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
145 changes: 145 additions & 0 deletions
145
.script/tests/KqlvalidationsTests/CustomTables/AWSWAF.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| { | ||
| "Name": "AWSWAF", | ||
| "Properties": [ | ||
| { | ||
| "name": "TenantId", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "Action", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "Args", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "CaptchaResponse", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "ChallengeResponse", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "ClientIp", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "Country", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "ExcludedRules", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "FormatVersion", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "Headers", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "HttpMethod", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "HttpRequest", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "HttpSourceId", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "HttpSourceName", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "HttpVersion", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "Ja3Fingerprint", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "Labels", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "NonTerminatingMatchingRules", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "OversizeFields", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "RateBasedRuleList", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "RequestHeadersInserted", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "RequestId", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "ResponseCodeSent", | ||
| "type": "Int32" | ||
| }, | ||
| { | ||
| "name": "RuleGroupId", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "RuleGroupList", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "TerminatingRule", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "TerminatingRuleId", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "TerminatingRuleMatchDetails", | ||
| "type": "Object" | ||
| }, | ||
| { | ||
| "name": "TerminatingRuleType", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "TimeGenerated", | ||
| "type": "DateTime" | ||
| }, | ||
| { | ||
| "name": "Uri", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "WebAclId", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "SourceSystem", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "Type", | ||
| "type": "String" | ||
| }, | ||
| { | ||
| "name": "_ItemId", | ||
| "type": "String" | ||
| } | ||
| ] | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
Parsers/ASimWebSession/ARM/ASimWebSessionAWSWAF/ASimWebSessionAWSWAF.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| { | ||
| "$schema": "https://schema.management.azure.com/schemas/2019-08-01/deploymentTemplate.json#", | ||
| "contentVersion": "1.0.0.0", | ||
| "parameters": { | ||
| "Workspace": { | ||
| "type": "string", | ||
| "metadata": { | ||
| "description": "The Microsoft Sentinel workspace into which the function will be deployed. Has to be in the selected Resource Group." | ||
| } | ||
| }, | ||
| "WorkspaceRegion": { | ||
| "type": "string", | ||
| "defaultValue": "[resourceGroup().location]", | ||
| "metadata": { | ||
| "description": "The region of the selected workspace. The default value will use the Region selection above." | ||
| } | ||
| } | ||
| }, | ||
| "resources": [ | ||
| { | ||
| "type": "Microsoft.OperationalInsights/workspaces/savedSearches", | ||
| "apiVersion": "2020-08-01", | ||
| "name": "[concat(parameters('Workspace'), '/ASimWebSessionAWSWAF')]", | ||
| "location": "[parameters('WorkspaceRegion')]", | ||
| "properties": { | ||
| "etag": "*", | ||
| "displayName": "Web Session ASIM parser for AWS Web Application Firewall", | ||
| "category": "ASIM", | ||
| "FunctionAlias": "ASimWebSessionAWSWAF", | ||
| "query": "let parser = (\n disabled:bool=false,\n pack:bool=false\n)\n{\n //According to AWS documentation: https://docs.aws.amazon.com/waf/latest/developerguide/logging-fields.html\n let ActionLookup = datatable(Action:string, DvcAction:string, EventResult:string, EventSeverity:string)\n [\n 'ALLOW', 'Allow', 'Success', 'Informational',\n 'BLOCK', 'Deny', 'Failure', 'Low',\n 'CAPTCHA', 'Deny', 'Failure', 'Low',\n 'CHALLENGE', 'Deny', 'Failure', 'Low',\n '', '', 'NA', 'Informational'\n ];\n AWSWAF\n | where not(disabled)\n //Mandatory common fields\n | extend\n EventCount = int(1),\n EventStartTime = TimeGenerated,\n EventEndTime = TimeGenerated,\n EventType = 'HTTPsession',\n EventVendor = 'AWS',\n EventProduct = 'WAF',\n EventSchema = 'WebSession',\n EventSchemaVersion = '0.2.7'\n | extend Dvc = coalesce(WebAclId, strcat(EventVendor, '/', EventProduct))\n | lookup ActionLookup on Action\n //Recommended common fields\n | extend DvcId = Dvc,\n DvcIdType = 'Other',\n EventUid = _ItemId\n | project-rename DvcOriginalAction = Action\n // AWS WAF populates ResponseCodeSent only when a custom block response is configured; the field is empty for allowed requests and default-response blocks.\n | extend EventResultDetails = tostring(ResponseCodeSent)\n | extend HttpStatusCode = EventResultDetails\n //HTTP session fields\n | extend parsedRequest = parse_json(HttpRequest)\n //Network Source fields\n | extend SrcIpAddr = tostring(parsedRequest.clientIp),\n Src = tostring(parsedRequest.clientIp),\n SrcGeoCountry = tostring(parsedRequest.country)\n | extend headers = iff(array_length(parsedRequest.headers) > 0, parsedRequest.headers, dynamic([{}]))\n | mv-apply header = headers on (\n summarize\n HttpHost = take_anyif(tostring(header.value), tostring(header.name) =~ 'host'),\n HttpUserAgent = take_anyif(tostring(header.value), tostring(header.name) =~ 'user-agent'),\n HttpReferrer = take_anyif(tostring(header.value), tostring(header.name) =~ 'referer'),\n HttpCookie = take_anyif(tostring(header.value), tostring(header.name) =~ 'Cookie'),\n HttpRequestXff = take_anyif(tostring(header.value), tostring(header.name) =~ 'X-Forwarded-For')\n )\n | extend\n scheme = tostring(parsedRequest.scheme),\n host = coalesce(tostring(parsedRequest.host), HttpHost),\n uri = tostring(parsedRequest.uri),\n args = tostring(parsedRequest.args)\n | extend Url = case(\n isnotempty(scheme) and isnotempty(host),\n strcat(scheme, '://', host, uri, iff(isnotempty(args), strcat('?', args), '')),\n isnotempty(host),\n strcat(host, uri, iff(isnotempty(args), strcat('?', args), '')),\n uri\n ),\n HttpVersion = tostring(parsedRequest.httpVersion),\n HttpRequestMethod = tostring(parsedRequest.httpMethod),\n HttpRequestHeaderCount = toint(array_length(parsedRequest.headers)),\n UserAgent = HttpUserAgent\n //Network session fields\n | extend NetworkApplicationProtocol = toupper(scheme),\n NetworkSessionId = tostring(parsedRequest.requestId)\n //Network destination fields\n | project-rename DstDvcId = HttpSourceId\n | extend DstDvcIdType = 'Other',\n DstPortNumber = case(\n scheme =~ 'https', toint(443),\n scheme =~ 'http', toint(80),\n int(null)\n )\n // Normalize: unwrap bracketed IPv6 [::1]:443 -> ::1 ; strip :port from host:port (but not from bare IPv6)\n | extend _hostNoPort = case(\n host startswith '[', extract(@'^\\[(.+?)\\]', 1, host), // [IPv6] or [IPv6]:port\n host matches regex @'^[^:]+:\\d+$', tostring(split(host, ':')[0]), // host:port (single colon + digits)\n host // bare host or bare IPv6\n )\n | extend _hostIsIp =\n isnotnull(parse_ipv4(_hostNoPort))\n or (_hostNoPort contains ':' and isnotnull(parse_ipv6(_hostNoPort)))\n | extend _hostIsIpShaped =\n _hostIsIp\n or _hostNoPort matches regex @'^\\d{1,3}(\\.\\d{1,3}){3}$' // padded/oversized dotted-quads e.g. 083.130.061.x\n | extend _hostIsClean = _hostNoPort matches regex @'^[A-Za-z0-9\\.\\-\\_]+$' or _hostIsIp\n | extend _hostHasDomain = _hostIsClean and not(_hostIsIpShaped) and array_length(split(_hostNoPort, '.')) > 1\n | extend\n DstIpAddr = iff(_hostIsIp, _hostNoPort, ''), // strict: only real IPs\n DstHostname = case(\n _hostIsIp, _hostNoPort, // valid IP; keep\n _hostIsIpShaped, '', // IP-shaped junk is blank, not a fake hostname\n _hostIsClean, tostring(split(_hostNoPort, '.')[0]),\n ''\n ),\n DstFQDN = iff(_hostHasDomain, _hostNoPort, ''),\n DstDomain = iff(_hostHasDomain, strcat_array(array_slice(split(_hostNoPort, '.'), 1, -1), '.'), '')\n | extend DstDomainType = iff(isnotempty(DstDomain), 'FQDN', '')\n //Network Inspection fields\n | project-rename RuleName = TerminatingRuleId\n //Additional, non-normalized fields\n | extend AdditionalFields = iff(\n pack,\n bag_pack(\n 'HttpSourceName', HttpSourceName,\n 'TerminatingRuleType', TerminatingRuleType,\n 'TerminatingRuleMatchDetails', TerminatingRuleMatchDetails,\n 'RuleGroupList', RuleGroupList,\n 'RateBasedRuleList', RateBasedRuleList,\n 'Labels', Labels,\n 'JA3', Ja3Fingerprint\n ),\n dynamic({})\n )\n //Aliases\n | extend\n IpAddr = SrcIpAddr,\n Hostname = DstHostname,\n Dst = DstDvcId,\n EventOriginalUid = NetworkSessionId,\n SessionId = NetworkSessionId,\n Rule = RuleName\n //Select fields\n | project\n // -- Mandatory\n TimeGenerated,\n EventCount,\n EventStartTime,\n EventEndTime,\n EventType,\n EventResult,\n EventProduct,\n EventVendor,\n EventSchema,\n EventSchemaVersion,\n Dvc,\n Url,\n Dst,\n // -- Recommended\n EventResultDetails,\n EventSeverity,\n EventUid,\n DvcAction,\n DvcOriginalAction,\n DvcId,\n DvcIdType,\n HttpRequestMethod,\n HttpStatusCode,\n DstHostname,\n SrcIpAddr,\n // -- Event optional\n EventOriginalUid,\n // -- HTTP optional\n HttpVersion,\n HttpRequestHeaderCount,\n HttpHost,\n HttpUserAgent,\n HttpReferrer,\n HttpCookie,\n HttpRequestXff,\n // -- Destination optional\n DstDvcId,\n DstDvcIdType,\n DstIpAddr,\n DstPortNumber,\n DstFQDN,\n DstDomain,\n DstDomainType,\n // -- Source optional\n SrcGeoCountry,\n // -- Network fields\n NetworkApplicationProtocol,\n NetworkSessionId,\n // -- Inspection fields\n RuleName,\n Rule,\n // -- Additional\n AdditionalFields,\n // -- Aliases\n IpAddr,\n UserAgent,\n Hostname,\n SessionId,\n Src,\n // -- Source table\n Type\n};\nparser(\n disabled=disabled,\n pack=pack\n)\n", | ||
| "version": 1, | ||
| "functionParameters": "disabled:bool=False,pack:bool=False" | ||
| } | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # AWS WAF ASIM WebSession Normalization Parser | ||
|
|
||
| ARM template for ASIM WebSession schema parser for AWS WAF. | ||
|
|
||
| This ASIM parser supports normalizing AWS Web Application Firewall (WAF) web session logs from the AWSWAF table to the ASIM Web Session normalized schema. | ||
|
|
||
|
|
||
| The Advanced Security Information Model (ASIM) enables you to use and create source-agnostic content, simplifying your analysis of the data in your Microsoft Sentinel workspace. | ||
|
|
||
| For more information, see: | ||
|
|
||
| - [Normalization and the Advanced Security Information Model (ASIM)](https://aka.ms/AboutASIM) | ||
| - [Deploy all of ASIM](https://aka.ms/DeployASIM) | ||
| - [ASIM WebSession normalization schema reference](https://aka.ms/ASimWebSessionDoc) | ||
|
|
||
| For the changelog, see: | ||
| - [CHANGELOG](https://github.com/Azure/Azure-Sentinel/blob/master/Parsers/ASimWebSession/CHANGELOG/ASimWebSessionAWSWAF.md) | ||
|
|
||
| <br> | ||
|
|
||
| [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FParsers%2FASimWebSession%2FARM%2FASimWebSessionAWSWAF%2FASimWebSessionAWSWAF.json) [](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FParsers%2FASimWebSession%2FARM%2FASimWebSessionAWSWAF%2FASimWebSessionAWSWAF.json) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.