fleet
fleet copied to clipboard
Microsoft (Intune) compliance partner: fleetdm.com proxy
Goal
| User story |
|---|
| As a Fleet contributor, |
| I want to hit fleetdm.com to get Fleet's Microsoft API token |
| so that I can use the API token, without hardcoding it, to build the Intune compliance partner features. |
Key result
Become a Microsoft compliance partner to enable first-party ZTA (zero-trust access) integration
Original requests
- #24423
Context
- Product designer: @noahtalerman + @lucasmrod
Changes
Product
- [ ] fleetdm.com changes:
- Add three new environment variables:
- Fleet's multi-tenant Entra ID “application ID” (aka client_id).
- Fleet's multi-tenant Entra ID "client secret" (aka client_secret).
- "MS-API-Key" to allow only cloud instances to use the proxy.
- Create skeleton code for the proxy so that many engineers can collaborate on the implementation of the endpoints.
- Add documentation on how to run the proxy locally on workstations (for Fleet server development which will use the APIs).
- Add the APIs defined below.
0. Authentication
All Microsoft Compliance API endpoints will require an authentication bearer token, "MS-API-Key". This is to prevent use of the MS APIs from non-Cloud instances.
The proxy will use the HTTP Origin header and store that on the integration record ("entra_tenant_id" and "origin URL" will be unique).
1. Add new "Create Microsoft compliance partner" API endpoint
POST fleetdm.com/api/v1/microsoft-compliance-partner
This endpoint creates the integration on the proxy database, but doesn't communicate with Microsoft yet.
It checks the origin header of requests to get the Fleet server URL and returns a badRequest response if it is not set. If a database record exists for that Fleet server URL, it will return a 409 response if the tenant is marked as setupCompleted = true, or delete the incomplete tenant record if setup has not been completed.
It then creates a database record with the following information:
{
fleetServerSecret: '....',// Randomly generated string
entraTenantId: '....',// Provided in the request body
fleetInstanceUrl: '....',// The value of the origin header
setupCompleted: false,
adminConsented: false,
}
It then responds to the Fleet server with the provided entra_tenant_id and randomly generated fleet_server_secret
All subsequent requests must send the "entra_tenant_id" + "fleet_server_secret" and on the request body/query.
Request from Fleet server:
{
"entraTenantId": "abc123"
}
Response to Fleet server:
{
"fleet_server_secret": "def456",
"entra_tenant_id": "abc123",
}
2. Add new "Get settings" API endpoint
GET /api/v1/microsoft-compliance-partner/settings?entra_tenant_id=abc123&fleet_server_secret=def456
Response to Fleet server:
{
"entra_tenant_id": "abc123",
"setup_done": true/false,
"admin_consented": true/false,
"admin_consent_url": "https://login.microsoftonline.com/{entraTenantId}/adminconsent?entraApplicationId=foo123&state=12345&redirect_uri=https%3A%2F%2Ffleetdm.com%2Fapi%2Fv1%2Fmicrosoft-compliance-partner%2Fadminconsent" // always set, regardless of admin_consented value.
"setup_error": "...."// Only set if there was an error when provisioning the tenant after the admin consents.
}
- Returns HTTP 404 if the integration associated to the provided
fleet_server_secretdoes not exist. - If
admin_consentedistrue, then "admin_consent_url" is not set in the response (not needed anymore). - If
admin_consented=false,The response will always include an admin consent URL, the Fleet server will redirect the user to the providedadmin_consent_url. - Fields in the
admin_consent_url:entraTenantIdentraApplicationIdthis is the "client_id" (configured in the proxy).redirect_uri: Is the URI of the webhook:https://fleetdm.com/api/v1/microsoft-compliance-partner/adminconsent(see webhook API endpoint number 8).state: should be a random token to authenticate the webhook request (see webhook API endpoint number 8). It should be stored on a column the integration row.
- If an error occurred when the user was redirected to the admin consent webhook (Either because there was an error setting up the new tenant or because the admin did not consent), it will be sent in the response body as a
setup_error.
3. Add new API endpoint for the admin consent webhook
GET fleetdm.com/api/v1/microsoft-compliance-partner/adminconsent?tenant=aaaabbbb-0000-cccc-1111-dddd2222eeee&state=state=12345&admin_consent=True
Webhook fields:
tenant:entraTenantId.state: This is used to authenticate the webook request.
After receiving this request, integration is marked as admin_consented=true, the state token is cleared from the database, and setups the created integration by using the Microsoft APIs to (1) provision the tenant and (2) create the necessary objects for the Compliance partner integration.
If the setup is done correctly then a 200 is returned without any response body and the proxy marks the integration as done (setup_done=true).
If there's an issue during the setup process, then a non-200 is returned and a "setupError" is set on the website record to that will be included in the response from the /api/v1/microsoft-compliance-partner/settings endpoint.
After the setup has been completed, the endpint redirects the user to their Fleet instance.
More information about this webhook can be found here.
4. Add new "DELETE Microsoft compliance partner" API endpoint
DELETE fleetdm.com/api/v1/microsoft-compliance-partner?entra_tenant_id=abc123&fleet_server_secret=def456
Response to Fleet server:
{
"error": "..."
}
The endpoint “deprovisions” the integration using the same API as the one used in the POST fleetdm.com/api/v1/microsoft-compliance-partner but with the “provisioned” argument set to “2” (meaning “deprovisioned”). Thereafter, it deletes the integration from the fleetdm.com database.
Response is 200 if it was successfully deprovisioned and deleted.
If there's an issue on the deletion then a non-200 is returned and an "error" field specifies the error in detail.
5. Add new API endpoint to "set the compliance status for the device on Intune":
Send compliance status for the device using the APIs outlined in “2.3 Partner Device Data Sync API”.
POST fleetdm.com/api/v1/microsoft-compliance-partner/device
Request from Fleet server:
{
"fleetServerSecret": "def456",
"entraTenantId": "abc123",
"deviceId": "bar123" // Entra ID “device ID”
"deviceName": "foobar123", // device friendly name (hosts.display_name)
"os": "macOS",
"osVersion": "15.3.1",
"userId": "user123" // Entra ID “user ID”.
"compliant": true/false,
"lastCheckInTime": 1740691819 // from hosts.details_updated_at timestamp
}
Response to Fleet server:
{
"message_id": "message123" // OperationLocation from the Microsoft API.
}
The proxy will need to store the "message_id" in the database with the status of the message ("not started", "running", "completed", "failed", etc.) and its "OperationLocation" which is to be used to check the status of the message.
6. Add new API endpoint to "get the result of setting the compliance status for the device on Intune"
Intune API is asynchronous thus we need to check if the POST fleetdm.com/api/v1/microsoft-compliance-partner/device was successful or not.
GET fleetdm.com/api/v1/microsoft-compliance-partner/device/message?entraTenantID=abc123&fleetServerSecret=def456&messageID=message123
Response to Fleet server:
{
"message_id": "message123",
"status": "completed",
"detail": "..." // detail is set if there's a failure
}
7. Add heartbeat implementation to the proxy
Implement heartbeat cron that runs daily which will use the “2.2.5 Tenant Heartbeat API” to keep all integrations alive.
- [x] UI changes: No changes.
- [x] CLI (fleetctl) usage changes: No changes.
- [x] YAML changes: No changes.
- [x] REST API changes: No changes.
- [x] Fleet's agent (fleetd) changes: No changes.
- [x] GitOps mode changes: No changes.
- [x] Activity changes: No changes.
- [x] Permissions changes: No changes.
- [x] Changes to paid features or tiers: Fleet Premium
- [x] Transparency changes: No changes.
- [x] First draft of test plan added: @noahtalerman: No test plan needed.
- [x] Other reference documentation changes: No changes.
- [x] Once shipped, requester has been notified
- [ ] Once shipped, dogfooding issue has been filed
Engineering
Remove this section because there's no Fleet product changes in this story.
QA
No test plan for this proxy work.
@lucasmrod passing this to you to add fleetdm.com API wireframes/specs.
Here's what we're doing for Android for reference: https://github.com/fleetdm/fleet/issues/26270
FYI @lucasmrod I updated URLs to /microsoft-compliance-partner instead of /microsoft/compliance-partner because I'm assuming we learn towards less nesting (flatter) for fleetdm.com API endpoints.
If we add API endpoints for another Microsoft service in the future we can do something like /microsoft-service-x
I could be wrong though. I think up to @eashaw.
Check to see if Fleet server is cloud-managed
Hey @lucasmrod just checking, do we know how this is going to work? Probably want to update fleetdm.com database to map between license key and cloud-managed true/false.
Left a comment in the other issue, but so we have it tracked here: we should make sure the fleetdm.com proxy has a record of which licenses belong to cloud-managed Fleet instances and throw an error if we try to use the integration for any self-hosted instances.
Left a comment in the other issue, but so we have it tracked here: we should make sure the fleetdm.com proxy has a record of which licenses belong to cloud-managed Fleet instances and throw an error if we try to use the integration for any self-hosted instances.
Thanks! We agreed the proxy will be allowing only one integration per cloud origin URL.
We met with @getvictor and @eashaw and agreed that the two proxies will look the same around using "fleet_server_key" as the secret that identifies each integration/customer (returned on the first POST to create the integration).
But the one difference with the Android proxy is that the fleetdm.com proxy for MS compliance partner (due to requirements) will require all requests to provide a shared API key as authentication bearer token (HTTP header).
We've updated the description to account for this.
/cc @noahtalerman
I've created https://github.com/fleetdm/fleet/issues/27200 to answer some questions during the development of the integration. (There's no public information to answer these, so we'll need to test the assumptions during the development of the integration.)
@lucasmrod For "7. Add new API endpoint for the admin consent webhook": Does the webhook need to do anything else after the database record for the tenant is updated, or should it just return a 200 response?
@lucasmrod For "7. Add new API endpoint for the admin consent webhook": Does the webhook need to do anything else after the database record for the tenant is updated, or should it just return a 200 response?
That should be it. Update columns in the integration (set admin_consented=true and clear state), and return 200.
The UI + Fleet server will be using the GET settings to "poll" when the user loads the integration settings.
That should be it. Update columns in the integration (set admin_consented=true and clear state), and return 200. The UI + Fleet server will be using the GET settings to "poll" when the user loads the integration settings.
@lucasmrod Sounds good! How would you like the webhook to respond if the admin does not grant permissions? https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#error-response
I currently have it returning a bad request response.
Sounds good! How would you like the webhook to respond if the admin does not grant permissions?
I believe we want to record the error in the integration row, like a admin_consented_error string or something like that and also return HTTP 200 (to indicate to Microsoft that we have processed the webhook successfully).
And we could improve the UI in the future to differentiate whether the admin has not yet consented or has denied.
@eashaw I see this is in the "In review" column but I don't see an associated PR. Would you please link this story to it? Thanks!
@xpkoala @sharon-fdm I am leaving this on the Orchestration project board and assigned to milestone 4.70.0 because it technically shipped and was announced. Once this reaches "Ready for release" state, please move it to the Drafting project and the "Confirm and celebrate" column. Thank you!
API tokens flow like rivers, Security in cloud's embrace, Fleet and Microsoft, together.