Skip to content
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

[Azure] Add Monitor App Service Logs data stream #4818

Merged
merged 4 commits into from
Jul 21, 2023

Conversation

lucian-ioan
Copy link
Contributor

@lucian-ioan lucian-ioan commented Dec 13, 2022

What does this PR do?

Adds App Service data stream with support for the following log categories:

  • HTTP logs
  • App Service Console Logs
  • App Service Application Logs
  • Access Audit Logs
  • IPSecurity Audit logs
  • App Service Platform logs

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have verified that all data streams collect metrics or logs.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.

Author's Checklist

Document providing instruction on how to collect each log category:
https://docs.google.com/document/d/1AJREQvAE2mc1QU19YKgZ4QJB6OHsyw8fy_WlLRYJV74

  • Research how to collect HTTP logs
  • Research how to collect App Service Console Logs
  • Research how to collect App Service Application Logs
  • Research how to collect Access Audit Logs
  • Research how to collect IPSecurity Audit logs
  • Research how to collect App Service Platform logs

How to test this PR locally

Related issues

-Relates elastic/obs-infraobs-team#826

Screenshots

@elasticmachine
Copy link

elasticmachine commented Dec 13, 2022

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview preview

Expand to view the summary

Build stats

  • Start Time: 2023-07-20T21:27:37.747+0000

  • Duration: 14 min 29 sec

Test stats 🧪

Test Results
Failed 0
Passed 8
Skipped 0
Total 8

🤖 GitHub comments

Expand to view the GitHub comments

To re-run your PR in the CI, just comment with:

  • /test : Re-trigger the build.

@lucian-ioan lucian-ioan changed the title [Azure] Add Monitor App Service HTTP Logs data stream [Azure] Add Monitor App Service Logs data stream Dec 21, 2022
@elasticmachine
Copy link

elasticmachine commented Dec 21, 2022

🌐 Coverage report

Name Metrics % (covered/total) Diff
Packages 100.0% (1/1) 💚
Files 87.5% (7/8) 👎 -12.5
Classes 87.5% (7/8) 👎 -12.5
Methods 75.0% (18/24) 👎 -25.0
Lines 77.808% (284/365) 👎 -9.023
Conditionals 100.0% (0/0) 💚

Copy link
Contributor

@zmoog zmoog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This first iteration on AppServiceAuditLogs and AppServiceHTTPLogs looks promising.

I added a few comments I'd love to hear you about.

storage_account_container: {{storage_account_container}}
{{else}}
{{#if eventhub}}
storage_account_container: filebeat-firewalllogs-{{eventhub}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this firewalllogs is a leftover, isn't it?

Comment on lines 3 to 34
processors:
- rename:
field: azure.appservices.ResourceId
target_field: azure.resource.id
ignore_missing: true
- rename:
field: azure.appservices.Category
target_field: azure.appservices.category
- rename:
field: azure.appservices.OperationName
target_field: azure.appservices.operation_name
- rename:
field: azure.appservices.Properties.Protocol
target_field: azure.appservices.properties.protocol
- rename:
field: azure.appservices.Properties.User
target_field: azure.appservices.properties.user
- rename:
field: azure.appservices.Properties.UserAddress
target_field: azure.appservices.properties.user_address
- rename:
field: azure.appservices.Properties.UserDisplayName
target_field: azure.appservices.properties.user_display_name
- convert:
field: azure.appservices.properties.user_address
type: ip
ignore_missing: true
- remove:
field:
- azure.appservices.Properties
ignore_missing: true
on_failure:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By removing the azure.appservices.Properties field, we risk dropping sub-fields that we are unaware of or Azure may add in the future.

What if we rename Properties into properties first and then rename the other fields? We won't lose unexpected field this way.

Comment on lines 1 to 78
- name: azure.appservices
type: group
fields:
- name: category
type: keyword
description: The category of the operation.
- name: operation_name
type: keyword
description: The operation name.
- name: properties
type: group
fields:
- name: protocol
type: keyword
description: Authentication protocol.
- name: user
type: keyword
description: Username used for publishing access.
- name: user_address
type: ip
description: Client IP address of the publishing user.
- name: user_display_name
type: keyword
description: Email address of a user in case publishing was authorized via AAD authentication.
- name: client_ip
type: ip
description: IP address of the client.
- name: computer_name
type: keyword
description: The name of the server on which the log file entry was generated.
- name: cookie
type: keyword
description: Cookie on HTTP request.
- name: cs_bytes
type: long
description: Number of bytes received by server.
- name: cs_host
type: keyword
description: Host name header on HTTP request.
- name: cs_method
type: keyword
description: The request HTTP verb.
- name: cs_uri_query
type: keyword
description: URI query on HTTP request.
- name: cs_uri_stem
type: keyword
description: The target of the request.
- name: cs_username
type: keyword
description: The name of the authenticated user on HTTP request.
- name: referer
type: keyword
description: The site that the user last visited. This site provided a link to the current site.
- name: result
type: keyword
description: Success / Failure of HTTP request.
- name: s_port
type: keyword
description: Server port number.
- name: sc_bytes
type: long
description: Number of bytes sent by server.
- name: sc_status
type: long
description: HTTP status code.
- name: sc_substatus
type: keyword
description: Substatus error code on HTTP request.
- name: sc_win32status
type: keyword
description: Windows status code on HTTP request.
- name: time_taken
type: long
description: Time taken by HTTP request in milliseconds.
- name: user_agent
type: keyword
description: User agent on HTTP request.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about grouping the fields in this list by log categories?

Adding comments to visually separate the shared ones from those belonging to a specific log category can be helpful.

@zmoog zmoog self-assigned this Dec 29, 2022
@zmoog zmoog added enhancement New feature or request Team:Cloud-Monitoring Label for the Cloud Monitoring team labels Dec 29, 2022
@zmoog zmoog assigned lucian-ioan and unassigned zmoog Dec 29, 2022
@zmoog
Copy link
Contributor

zmoog commented Dec 29, 2022

What log categories are you working on right now?

@zmoog
Copy link
Contributor

zmoog commented Dec 29, 2022

Let me know which log categories you are working on, and I'll try to pick at least one or two of the other ones to find the sample logs.

@lucian-ioan
Copy link
Contributor Author

Currently, I have samples for the 4 log categories marked and will update this PR to contain the yaml for the other 2.

@zmoog
Copy link
Contributor

zmoog commented Jan 24, 2023

Hey @lucianpy, how is the log hunting going? Please let me know if you need help with the log collection, testing, or field/pipeline building!

@lucian-ioan
Copy link
Contributor Author

Hey @zmoog, no new progress as of yet. Worst case I will just push the 4 categories that I do have. Still want to try to get them this week. If not succesful, I will ask for your help on Monday.

@zmoog
Copy link
Contributor

zmoog commented Feb 1, 2023

Hey @zmoog, no new progress as of yet. Worst case I will just push the 4 categories that I do have. Still want to try to get them this week. If not succesful, I will ask for your help on Monday.

Hey @lucianpy, can I help with something?

@lucian-ioan
Copy link
Contributor Author

lucian-ioan commented Feb 2, 2023

Hey @zmoog, could you take a look at IPSecurity Audit Logs ?

It probably needs some IP rules set up and then just an access to the application by a restricted IP for example might trigger it.
You can also review the HTTP logs.

@lucian-ioan
Copy link
Contributor Author

lucian-ioan commented Feb 16, 2023

As an update here, I now have all of the 6 log categories that we need.

Unfortunately, App Service Platform Logs and App Service Console Logs can't be processed directly due to double newlines apearing in some fields similar to: elastic/beats#34092

Currently looking at a fix for this issue.

@lucian-ioan
Copy link
Contributor Author

lucian-ioan commented Feb 23, 2023

One thing that needs to be decided is what to do in case of same name fields for different log categories.
For example, the CIp field for HTTPLogs is just a usual IP address whereas the CIp for IPSecAuditLogs is a socket (ip:port).

A solution that I found is to modify the fields for each log category, such as azure.appservices.client_id becomes azure.appservices.httplogs.client_id. The disadvantage to this is that the json that ends up in Kibana will be more verbose. What do you think @zmoog ?

Also, updated the PR with the document providing instructions on how to collect all the log categories!

@zmoog
Copy link
Contributor

zmoog commented Mar 2, 2023

Quick update after the sync over zoom in the last few days to discuss the following two topics.


One thing that needs to be decided is what to do in case of same name fields for different log categories.

We decided to try to map the source document into a destination field as an object.

For example, if the source has an IP address only, we can use a destination field like this:

{
  "ip": {
    "address": "10.1.0.1"
  }
}

Instead, if it has an IP address and a port, we can use:

{
  "ip": {
    "address": "10.1.0.1",
    "port": 8080
  }
}

This is only an example, not the recommended names 😄 , I suggest exploring what other integration are doing and the reference names and structure in the Elastic Common Schema (ECS).


Unfortunately, App Service Platform Logs and App Service Console Logs can't be processed directly due to double newlines appearing in some fields similar to: elastic/beats#34092

We need to reproduce this issue to share our findings with the Azure folks to understand this issue better.

Suppose this turns out to be something we can't avoid. In that case, one possible approach is the update the azure-eventhub input at https://github.com/elastic/beats/blob/main/x-pack/filebeat/input/azureeventhub/input.go#L167-L203, and the sanitize the []byte we receive from the Event Hub before trying to unmarshal it to unpack the elements in the records list.

@zmoog
Copy link
Contributor

zmoog commented Mar 2, 2023

@lucianpy how is it going with the newlines issue? Are you and Gabriel able to reproduce the issue again?

@lucian-ioan
Copy link
Contributor Author

@zmoog we were not able to reproduce the issue so I will add the sanitization just in case it ever happens again.

@lucian-ioan
Copy link
Contributor Author

lucian-ioan commented Mar 14, 2023

To be noted here that there's a pretty big discrepancy between the fields I was able to fetch for Console Logs, Platform Logs and App Logs and the azure official documentation.

Initially I thought there might be some optional fields that only come up in specific instances but some fields are not in the documentation at all, like EventStampType, EventStampName etc.

Wasn't able to fetch any different variation of logs than those I have here. What do you think about this issue @zmoog?

@lucian-ioan
Copy link
Contributor Author

lucian-ioan commented Mar 14, 2023

Suppose this turns out to be something we can't avoid. In that case, one possible approach is the update the azure-eventhub input at https://github.com/elastic/beats/blob/main/x-pack/filebeat/input/azureeventhub/input.go#L167-L203, and the sanitize the []byte we receive from the Event Hub before trying to unmarshal it to unpack the elements in the records list.

I found I can only sanitize the event for appservices in integrations, since this is where the issue was found. The advantage of this is not modifying the azure-eventhub code directly in beats. What do you think @zmoog?

@zmoog
Copy link
Contributor

zmoog commented Mar 14, 2023

To be noted here that there's a pretty big discrepancy between the fields I was able to fetch for Console Logs, Platform Logs and App Logs and the azure official documentation.

Initially I thought there might be some optional fields that only come up in specific instances but some fields are not in the documentation at all, like EventStampType, EventStampName etc.

Wasn't able to fetch any different variation of logs than those I have here. What do you think about this issue @zmoog?

I had similar experiences in other log categories. The docs do not seem 100% accurate, and on average there are ~5% of the fields that are different (present, not present, or with a slightly different name).

I usually link to the docs, but take the log samples as a de-factor spec.

@zmoog
Copy link
Contributor

zmoog commented Mar 14, 2023

I found I can only sanitize the event for appservices, since this is where the issue was found. The advantage of this is not modifying the azure-eventhub code directly in beats. What do you think @zmoog?

There is one main issue in trying to "patch" the invalid JSON string in the pipeline vs. the input.

The diagnostic setting sends data to the event hub in batches, so the input receives something like this:

{
  "records": [
    {
      "time": "2023-03-08T10:33:13.8810000Z",
      "resourceId": "/SUBSCRIPTIONS/6b173463-3d87-43c5-98bb-90af439f1be0/RESOURCEGROUPS/WHATEVER/PROVIDERS/MICROSOFT.INSIGHTS/COMPONENTS/WHATEVER-2",
      "ResourceGUID": "0e1fdb93-b4b6-468b-9408-70ee34e56b22",
      "Type": "AppRequests",
      "AppRoleInstance": "Maurizios-MacBook-Pro.local",
      "AppRoleName": "Web",
      "ClientIP": "0.0.0.0",
      "ClientOS": "Darwin 22.3.0",
      "ClientType": "PC",
      "IKey": "89c2be53-f9c7-4ac0-8191-fb31898b774c",
      "_BilledSize": 976,
      "OperationName": "GET /",
      "OperationId": "ba20ab37cafe455c96db689d52c6b4a9",
      "ParentId": "ba20ab37cafe455c96db689d52c6b4a9",
      "SDKVersion": "node:2.3.5",
      "Properties": {
        "_MS.ProcessedByMetricExtractors": "(Name:'Requests', Ver:'1.1')"
      },
      "Id": "|ba20ab37cafe455c96db689d52c6b4a9.",
      "Name": "GET /",
      "Url": "http://localhost:3000/",
      "Success": true,
      "ResultCode": "200",
      "DurationMs": 1,
      "PerformanceBucket": "<250ms",
      "ItemCount": 1
    },
    {
      "time": "2023-03-08T10:33:13.8810000Z",
      "resourceId": "/SUBSCRIPTIONS/6b173463-3d87-43c5-98bb-90af439f1be0/RESOURCEGROUPS/WHATEVER/PROVIDERS/MICROSOFT.INSIGHTS/COMPONENTS/WHATEVER-2",
      "ResourceGUID": "0e1fdb93-b4b6-468b-9408-70ee34e56b22",
      "Type": "AppRequests",
      "AppRoleInstance": "Maurizios-MacBook-Pro.local",
      "AppRoleName": "Web",
      "ClientIP": "0.0.0.0",
      "ClientOS": "Darwin 22.3.0",
      "ClientType": "PC",
      "IKey": "89c2be53-f9c7-4ac0-8191-fb31898b774c",
      "_BilledSize": 976,
      "OperationName": "GET /",
      "OperationId": "ba20ab37cafe455c96db689d52c6b4a9",
      "ParentId": "ba20ab37cafe455c96db689d52c6b4a9",
      "SDKVersion": "node:2.3.5",
      "Properties": {
        "_MS.ProcessedByMetricExtractors": "(Name:'Requests', Ver:'1.1')"
      },
      "Id": "|ba20ab37cafe455c96db689d52c6b4a9.",
      "Name": "GET /",
      "Url": "http://localhost:3000/",
      "Success": true,
      "ResultCode": "200",
      "DurationMs": 1,
      "PerformanceBucket": "<250ms",
      "ItemCount": 1
    }
  ]
}

In this case, we have two records.

When the input fails to parse the JSON, it packs the whole { "records": [...] } batch of two records into the message field and sends it to the data stream as one document, instead of creating one two documents (one for each record).

In a case like this, the pipeline receives one document with two records, and I am not sure if it is possible to create two documents out of it. My understaning is that the pipeline in:out ratio is 1:1.

In this example, we have two records, but it is common to have ten or more records in a batch.

@lucian-ioan
Copy link
Contributor Author

lucian-ioan commented Mar 15, 2023

@zmoog, took a second look at your example and you are right, there are issues with doing it directly from integrations.

Should I open a different PR in beats for this?

@zmoog
Copy link
Contributor

zmoog commented Mar 15, 2023

@zmoog, took a second look at your example and you are right, there are issues with doing it directly from integrations.

Should I open a different PR in beats for this?

I believe we need to tackle this at the input level with a PR on Beats, but it’s better to double-check; let's ask other team members and hear their advice.

(We're asking offline, we'll update this conversation afterwards)

@lucian-ioan
Copy link
Contributor Author

As an update here, the consensus of the team is to takle this directly in Beats.

Currently waiting on the sanitization PR there to merge before moving forward.

@botelastic
Copy link

botelastic bot commented Apr 27, 2023

Hi! We just realized that we haven't looked into this PR in a while. We're sorry! We're labeling this issue as Stale to make it hit our filters and make sure we get back to it as soon as possible. In the meantime, it'd be extremely helpful if you could take a look at it as well and confirm its relevance. A simple comment with a nice emoji will be enough :+1. Thank you for your contribution!

@botelastic
Copy link

botelastic bot commented Jun 1, 2023

Hi! We just realized that we haven't looked into this PR in a while. We're sorry! We're labeling this issue as Stale to make it hit our filters and make sure we get back to it as soon as possible. In the meantime, it'd be extremely helpful if you could take a look at it as well and confirm its relevance. A simple comment with a nice emoji will be enough :+1. Thank you for your contribution!

@botelastic botelastic bot added the Stalled label Jun 1, 2023
@botelastic
Copy link

botelastic bot commented Jul 1, 2023

Hi! This PR has been stale for a while and we're going to close it as part of our cleanup procedure. We appreciate your contribution and would like to apologize if we have not been able to review it, due to the current heavy load of the team. Feel free to re-open this PR if you think it should stay open and is worth rebasing. Thank you for your contribution!

@botelastic botelastic bot closed this Jul 1, 2023
@lucian-ioan lucian-ioan reopened this Jul 4, 2023
@botelastic botelastic bot removed the Stalled label Jul 4, 2023
@lucian-ioan lucian-ioan marked this pull request as ready for review July 11, 2023 05:16
@lucian-ioan lucian-ioan requested a review from a team as a code owner July 11, 2023 05:16
Copy link
Contributor

@zmoog zmoog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢

Comment on lines 7 to 9
{{#if eventhub}}
storage_account_container: filebeat-firewalllogs-{{eventhub}}
{{/if}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove it? We need a default value, don't you think?

Copy link
Contributor

@zmoog zmoog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During a chat with @lucian-ioan, @gpop63, and @devamanv, we agreed that the best way forward for this App Service integration is the following:

  • Move the App Services integration from Azure Logs into an independent integration package.
  • Release App Services as:
    • maturity level: experimental
    • version: v0.0.1
    • no dashboards

This approach allow us to:

  • Add a metrics data stream in the App Services package so that we can have everything about App Services in a single package.
  • Have the option to add a dedicated data stream for each log category instead of using a single data stream as of today.
  • Collect user feedback to adjust field mapping, ingest pipelines, and dashboards.

@lalit-satapathy @rameshelastic @SubhrataK let us know if you think we should take a different route. We plan to move forward with this in the current sprint.

@lucian-ioan lucian-ioan merged commit 32b759e into elastic:main Jul 21, 2023
1 check passed
@elasticmachine
Copy link

Package azure_app_service - 0.0.1 containing this change is available at https://epr.elastic.co/search?package=azure_app_service

gizas pushed a commit that referenced this pull request Sep 5, 2023
* standalone app service integration

* default value for storage_account_container

* add code owner
@lucian-ioan lucian-ioan deleted the add_azure_http-logs branch September 6, 2023 11:36
Copy link

@hooooh2 hooooh2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{{#signal.rule.references}} {{.}} {{/signal.rule.references}}
Uploading IMG_0060.jpeg…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Integration:azure_app_service Azure App Service New Integration Team:Cloud-Monitoring Label for the Cloud Monitoring team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants