pnp / cli-microsoft365

Manage Microsoft 365 and SharePoint Framework projects on any platform
https://aka.ms/cli-m365
MIT License
882 stars 312 forks source link

Enable Audit Logs request #4677

Open Audinick opened 1 year ago

Audinick commented 1 year ago

Hello,

I would like to request the ability to enable/disable audit logs be included in available commands.

The use case is that myself and approximately 100 coworkers have to enable this on new M365 tenants each week.

If more information is needed please let me know.

Thank you.

nicodecleyre commented 1 year ago

Hi @Audinick, thank you for creating an issue! When you say you have to enable it on a new M365 tenant, do you mean you enable it from the purview compliance portal? (https://compliance.microsoft.com/auditlogsearch)

It will help us understand in which way we can maybe provide a command for your question

Audinick commented 1 year ago

Hello @nicodecleyre. That is correct. My apologies for not being more clear.

nicodecleyre commented 1 year ago

Hello @nicodecleyre. That is correct. My apologies for not being more clear.

No apologies needed! You were very clear, I just wanted to be sure 😄

So from a high level it seems that Organization Customization needs to be Enabled first. This can be done by doing: PATCH https://compliance.microsoft.com/api/OrganizationCustomization/Enable,

Then you will be notified that it may take 24 to 48 hours before it is activated (in the UI). However, from a new tenant I just set up, it only took 30 minutes.

After that you have to do a: PATCH https://compliance.microsoft.com/api/adminauditlogconfig/EnableUnifiedAuditLogIngestion.

But the question is, how do we do it from the cli since it needs a certain permission level: image

Audinick commented 1 year ago

Most, if not all of my coworkers would have global admin rights to the tenant if that helps.

waldekmastykarz commented 1 year ago

@nicodecleyre the first step is to find out which API it uses and which service principal we'd need to grant API access to. I assume you captured this API call from the UI. If that's the case, could you please capture the access token and see for which audience it's been issued? It would help us check if it's something that's even possible for us to do or if it's something that's just open to Microsoft's own apps.

nicodecleyre commented 1 year ago

@nicodecleyre the first step is to find out which API it uses and which service principal we'd need to grant API access to. I assume you captured this API call from the UI. If that's the case, could you please capture the access token and see for which audience it's been issued? It would help us check if it's something that's even possible for us to do or if it's something that's just open to Microsoft's own apps.

That's correct, I captured the api's from the ui. unfortanately, it doesn't use an access token but a cookie with a sccauth

nicodecleyre commented 1 year ago

Most, if not all of my coworkers would have global admin rights to the tenant if that helps.

That's the right role when working in the UI. The CLI works a little different, it uses an Enterprise Application in Azure AD where all the needed api permissions are defined

waldekmastykarz commented 1 year ago

That's correct, I captured the api's from the ui. unfortanately, it doesn't use an access token but a cookie with a sccauth

I'm afraid that we won't be able to support this, as there's no way for us to obtain such cookie without hacks that aren't a sustainable way forward. I suggest we put this functionality on-hold and close this issue until we get proper APIs that can be used by third parties.

Audinick commented 1 year ago

That's correct, I captured the api's from the ui. unfortanately, it doesn't use an access token but a cookie with a sccauth

I'm afraid that we won't be able to support this, as there's no way for us to obtain such cookie without hacks that aren't a sustainable way forward. I suggest we put this functionality on-hold and close this issue until we get proper APIs that can be used by third parties.

Completely understand and appreciate the effort that was done looking into it.

milanholemans commented 1 year ago

Just did a quick check and found a REST endpoint we could use with a bearer token. The request looks like this:

POST https://outlook.office365.com/adminapi/beta/<tenant ID>/InvokeCommand
Authorization: Bearer ....
{
  "CmdletInput": {
    "CmdletName": "Set-AdminAuditLogConfig",
    "Parameters": {
      "UnifiedAuditLogIngestionEnabled": true
    }
  }
}

The decoded accesstoken looks like this:

{
  "aud": "https://outlook.office365.com",
  "iss": "https://sts.windows.net/<omitted>/",
  "iat": 1679868356,
  "nbf": 1679868356,
  "exp": 1679959936,
  "acct": 0,
  "acr": "1",
  "aio": "ATQAy/8TAAAAbdkT7ALZuvGpe1kIDqL99bL5Y/H7LyQkxpZLGw+N2lQpG/cj8lmZOcjP9cWSLqQW",
  "amr": [
    "pwd"
  ],
  "app_displayname": "Microsoft Exchange REST API Based Powershell",
  "appid": "fb78d390-0c51-40cd-8e17-fdbfab77341b",
  "appidacr": "0",
  "deviceid": "f55a5b98-4d8c-4254-88c0-0c4eabae53c0",
  "enfpolids": [],
  "family_name": "<omitted>",
  "given_name": "<omitted>",
  "ipaddr": "<omitted>",
  "name": "<omitted>",
  "oid": "<omitted>",
  "puid": "1003200032DA22CA",
  "rh": "0.ATEAWJeF9XoxM0WHCEV4Hpg8agIAAAAAAPEPzgAAAAAAAAAxAHc.",
  "scp": "AdminApi.AccessAsUser.All FfoPowerShell.AccessAsUser.All RemotePowerShell.AccessAsUser.All VivaFeatureAccessPolicy.Manage.All",
  "sid": "97a2c9d9-692d-44c6-a798-4421fcd6ec73",
  "sub": "4N0EscezfH3n_aqbqXdG0lFN0Hw8Jq3dx20rnoBdPbg",
  "tid": "<omitted>",
  "unique_name": "<omitted>",
  "upn": "<omitted>",
  "uti": "ZJLedVJuw0mBNOL9AJICAA",
  "ver": "1.0",
  "wids": [
    "62e90394-69f5-4237-9190-012177145e10",
    "b79fbf4d-3ef9-4689-8143-76b194e85509"
  ],
  "xms_cc": [
    "cp1"
  ],
  "xms_ssm": "1"
}

Just did a quick check in Azure AD API permissions but didn't really find any useful audience there. @waldekmastykarz could you have a look if this audience is available as API permission?

waldekmastykarz commented 1 year ago

It seems that the audience (albeit with a trailing /) belongs to Office 365 Exchange Online (c804741f-fc70-40ba-b2ae-52ba0d40b59d). Let's see if we could get it to work with that API.

martinlingstuyl commented 1 year ago

Interesting! What did you do @milanholemans? Intercept a PowerShell commandlet using fiddler?

milanholemans commented 1 year ago

Interesting! What did you do @milanholemans? Intercept a PowerShell commandlet using fiddler?

I'm not saying yes, I'm not saying no 😉

milanholemans commented 1 year ago

It seems that the audience (albeit with a trailing /) belongs to Office 365 Exchange Online (c804741f-fc70-40ba-b2ae-52ba0d40b59d). Let's see if we could get it to work with that API.

Thank you checking this. Managed to grant permissions in Azure with this audience and seems to be working 👍. I've played around a bit with the APIs and here are my findings:

Disabling audit logging

Disabling audit logging works like a charm. When I execute following request, the audit logging is disabled:

POST https://outlook.office365.com/adminapi/beta/<tenant ID>/InvokeCommand
Accept: application/json;odata.metadata=none
Authorization: Bearer ...
{
  "CmdletInput": {
    "CmdletName": "Set-AdminAuditLogConfig",
    "Parameters": {
      "UnifiedAuditLogIngestionEnabled": false
    }
  }
}

At such moments, a person gains hope. But .....

Enabling audit logging

This one is very annoying. Executed following request:

POST https://outlook.office365.com/adminapi/beta/<tenant ID>/InvokeCommand
Accept: application/json;odata.metadata=none
Authorization: Bearer ...
{
  "CmdletInput": {
    "CmdletName": "Set-AdminAuditLogConfig",
    "Parameters": {
      "UnifiedAuditLogIngestionEnabled": true
    }
  }
}

But this is resulting every time in this:

400 Bad request
{
    "error": {
        "code": "BadRequest",
        "message": "Cmdlet needs proxy. Current Server FQDN : AS8P190MB1862.EURP190.PROD.OUTLOOK.COM, Required Server FQDN : GV1P190MB2019.EURP190.PROD.OUTLOOK.COM",
        "innererror": {
            "message": "Cmdlet needs proxy. Current Server FQDN : AS8P190MB1862.EURP190.PROD.OUTLOOK.COM, Required Server FQDN : GV1P190MB2019.EURP190.PROD.OUTLOOK.COM",
            "type": "Microsoft.Exchange.Admin.OData.Core.ODataServiceException",
            "stacktrace": "   at Microsoft.Exchange.AdminApi.CommandInvocation.CommandInvocation.InvokeCommand(QueryContext queryContext, CmdletInvokeInputType cmdletInvokeInputType)\r\n   at Microsoft.Exchange.Admin.OData.Core.PathSegmentToExpressionTranslator.Translate(OperationImportSegment segment)\r\n   at Microsoft.Exchange.Admin.OData.Core.QueryContext.ResolveQuery(ODataContext context, Int32 level)\r\n   at Microsoft.Exchange.Admin.OData.Core.Handlers.OperationHandler.Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage)\r\n   at Microsoft.Exchange.Admin.OData.Core.Handlers.RequestHandler.Process(Stream requestStream)"
        }
    }
}

Fun fact: when I enable the audit logging with the PS cmdlet, the request mentioned above is not failing anymore, but returning a 200 status with a success message. When I disable the audit logging again, I'm getting the error mentioned above again when I try to re-enable it.

The request above is failing, unless I remove the bearer token I'm using and replace it with the bearer token used within the PS cmdlet.

Summary

So disabling audit logging doesn't seems to be a problem, but enabling it again is for some reason more complex, I'm kinda stuck here right now.

nicodecleyre commented 1 year ago

@milanholemans great research!

Do you see any difference between the access tokens which returns a 400 and the one from PS?

milanholemans commented 1 year ago

@milanholemans great research!

Do you see any difference between the access tokens which returns a 404 and the one from PS?

Compared them, but not really a huge difference: https://www.diffchecker.com/whDfvGMC/ Custom app is on the left, PS on the right.

nicodecleyre commented 1 year ago

@milanholemans great research! Do you see any difference between the access tokens which returns a 404 and the one from PS?

Compared them, but not really a huge difference: https://www.diffchecker.com/whDfvGMC/ Custom app is on the left, PS on the right.

Thx! Really helpfull with diffchecker!

Must be related to the scopes where the PS access token has an AccessAsUser scope?

milanholemans commented 1 year ago

Maybe, but this is not a valid scope for the audience I'm using. I read somewhere that you need the scope Exchange.Manage to edit this setting. This seems to be working, but only when the audit logs are turned on. I can't switch it from the off to the on state.

waldekmastykarz commented 1 year ago

Have you compared the full request? I wonder if it could be something else like a custom request header that we're missing. I also wonder if the proxy server mismatch is not indicative of the API being meant for use by the Microsoft's app only and being filtered based on its ID on the server.

milanholemans commented 1 year ago

Have you compared the full request? I wonder if it could be something else like a custom request header that we're missing. I also wonder if the proxy server mismatch is not indicative of the API being meant for use by the Microsoft's app only and being filtered based on its ID on the server.

Yes, tried to include all request headers, but same result. When I just replace the bearer token with the one used in the PS cmdlet, everything works just fine.

waldekmastykarz commented 1 year ago

So it could be app-based filtering after all. Shame 😞