fleetdm / fleet

Open-source platform for IT, security, and infrastructure teams. (Linux, macOS, Chrome, Windows, cloud, data center)
https://fleetdm.com
Other
3.01k stars 418 forks source link

back-end bits for MDM Puppet module #12019

Closed roperzh closed 1 year ago

roperzh commented 1 year ago

Related user story

11185

Task

We need two endpoints, one endpoint to "pre-assign" a set of profiles to a host, and a separate endpoint to match the preassigned profiles to a team, and assign the host to that team.

roperzh commented 1 year ago

@mna worth chatting about two things:

  1. Any ideas for the API endpoints? I was using POST /api/_version_/fleet/mdm/apple/profiles/preassign and POST /api/_version_/fleet/mdm/apple/profiles/match, but open to anything! just need to agree on an API.
  2. The team matching is complicated enough that might grant a separate ticket. I'll ping you as soon as I'm done with the Ruby code to see if I can be of help!
roperzh commented 1 year ago

@mna not really helpful, but I was just getting started with this and here's what I've got so far: https://github.com/fleetdm/fleet/pull/12021

mna commented 1 year ago

@roperzh some comments/questions/thoughts (I should be able to start work on that first thing tomorrow morning):

To recap, the endpoints payload would look like that:

POST /api/_version_/fleet/mdm/apple/profiles/preassign: JSON body

{
  "external_host_identifier": "puppet-specific-unique-per-host",
  "host_uuid": "fleet-mdm-host-uuid",
  "profile": "base64-encoded-raw-xml-bytes",
  "group": "user-provided-team-name-part"
}

Just to be sure: we're certain the profile bytes payload will be properly base64-encoded as expected by Go's JSON marshaling?

POST /api/_version_/fleet/mdm/apple/profiles/match: JSON body

{
  "external_host_identifier": "puppet-specific-unique-per-host"
}
roperzh commented 1 year ago

@mna

Endpoints sound good to me, is it correct to say that POST /api/version/fleet/mdm/apple/profiles/preassign will be called H * P times where H is the number of hosts and P the number of profiles assigned per host (although the number of Ps can vary per H but just as a loose calculation)

Yes! absolutely correct to say that.

POST /api/version/fleet/mdm/apple/profiles/match is called only once per H, and is guaranteed to be called after any call to preassign?

It is called once per H, and we can guarantee that, when called, it will be after any call to preassign. I'm not 100% sure we can guarantee it'll always be called (ie: probably a good idea to add an expiration to the stored keys, maybe around ~30mins/1 hour?)

My initial understanding was that we'd always create the teams based on the "preassign" data received from puppet, but I think I see now that this is not a single-use puppet module that will run only when Fleet is initialized (has no existing team), right? It will possibly run more times after that, even when teams already exist in Fleet, which is why you mention looking for an existing team that has that exact set of profiles, so we don't always create new teams?

This is correct, this cycle of preassignment + matching will happen once per H every time the puppet agent checks in (we can assume ~30 minutes)

My initial understanding (again) was that we'd receive a single API request at the end, is there something that prevents that and requires that we receive one per host?

sorry, I think I wasn't clear on that! we can't do a "match" call for all the hosts because hosts check in asynchronously at different times. The mechanism is very similar to how we handle detail queries for osquery, hosts check in all the time at different times.

I would've triggered a worker job from that single request, but that may still be a good idea to do that even if it's one request per host, as it may generate a lot of load in a small time window. At least something to keep in mind as a future improvement, and we can start by doing the work in the request handler directly.

That sounds good, or to your point of having a "match" call for various jobs, we could do it in a cron job too.

roperzh commented 1 year ago

@mna sorry for the double ping, I see I missed two questions:

Just to be sure: we're certain the profile bytes payload will be properly base64-encoded as expected by Go's JSON marshaling?

Absolutely 👍

To recap, the endpoints payload would look like that:

both payloads look great!

mna commented 1 year ago

@roperzh

probably a good idea to add an expiration to the stored keys, maybe around ~30mins/1 hour?

Yes, definitely!

we can't do a "match" call for all the hosts because hosts check in asynchronously at different times. The mechanism is very similar to how we handle detail queries for osquery, hosts check in all the time at different times.

Oh interesting! My mental model of it was that a puppet run was triggered at some point and executed for all hosts, but what you describe makes a lot of sense.

Thanks for the extra details!

fleet-release commented 1 year ago

Puppet module blooms, Profiles matched, teams unite, Cloud city thrives, calm.