fleetdm / fleet

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

Use dynamic SCEP challenges in MDM enrollment profile #8477

Open michalnicp opened 1 year ago

michalnicp commented 1 year ago

Goal

As a IT admin, I want to know that Fleet secures their MDM enrollment profiles so that I can provide this as argument to the security team when pitching Fleet.

Problem

SCEP challenges should be considered sensitive. If compromised, the SCEP challenge can be used to get a valid certificate from the SCEP server and used to enroll with MDM.

See https://github.com/micromdm/micromdm/pull/642#issuecomment-586377065

https://support.apple.com/en-ca/guide/deployment/dep24dbdcf9e/web https://macadmins.slack.com/archives/C023Z6A2DL0/p1665684709030399?thread_ts=1665682926.697109&cid=C023Z6A2DL0 https://macadmins.slack.com/archives/C023Z6A2DL0/p1658861677026219

How?

Requirements

roperzh commented 1 year ago

Adding a note that this is also recommended by RFC 8894:

It is RECOMMENDED that the challengePassword be a one- time authenticator value to limit the ability of an attacker who can capture the authenticator from the client or CA and reuse it to request further certificates.

zhumo commented 1 year ago

@roperzh @michalnicp If the dynamic SCEP token expires, then after downloading the mobileconfig file, the user must install and accept it within a certain time frame right?

roperzh commented 1 year ago

@zhumo that's right. For DEP enrollment that shouldn't be a problem, but I can see manual enrollment failing because of that.

In that case, the user must get another enrollment profile with a new token.

zhumo commented 1 year ago

@roperzh What is the expiration time that we should apply? And so if I install a mobileconfig then I try to install that same mobileconfig on another device, the second device should refuse it, if I'm doing dynamic SCEP?

roperzh commented 1 year ago

What is the expiration time that we should apply?

@zhumo what I have seen other solutions do is 1 hour, which makes sense to me, but I can investigate and give you better data. cc: @GuillaumeRoss maybe has opinions?

And so if I install a mobileconfig then I try to install that same mobileconfig on another device, the second device should refuse it, if I'm doing dynamic SCEP?

exactly, you'll get an error in the macOS UI saying that the challenge is invalid. I can try to make it happen and capture a screenshot if that helps!

zhumo commented 1 year ago

@roperzh yes please

mna commented 1 year ago

@roperzh @noahtalerman @zhumo I think at a high level it can be pretty straightforward, as I understand it it would go like this:

I do have some questions for Roberto about the implementation details. What happens as part of the 3rd bullet above (when the user actually installs the profile in their settings) is a bit blurry to me. Does that call the SCEP URL that is embedded in the enrollment profile (i.e. <key>URL</key><string>{{ .SCEPURL }}</string> in the profile template)? Can you point me where we handle those requests in the prototype (is that here: https://github.com/fleetdm/fleet/blob/main/cmd/fleet/apple_mdm.go#L68-L90)? And do you know what the operation code is, and what we actually receive as part of the request (i.e. is it just the challenge token)?

roperzh commented 1 year ago

Does that call the SCEP URL that is embedded in the enrollment profile (i.e. URL{{ .SCEPURL }} in the profile template)?

exactly! it calls that URL, but the process has many steps, which are differentiated by the operation query` param (I think this the operation code you mention so apologies if you already know this.)

those details are all handled by github.com/micromdm/scep/v2/server

Can you point me where we handle those requests in the prototype (is that here: https://github.com/fleetdm/fleet/blob/main/cmd/fleet/apple_mdm.go#L68-L90)?

that's correct, that's where we "delegate" the SCEP endpoints, I think the way to go about this is to use challenge.Middleware (declared in github.com/micromdm/scep/v2/challenge) instead of scepserver.ChallengeMiddleware, this middleware receives an store with this interface:

type Store interface {
    SCEPChallenge() (string, error)
    HasChallenge(pw string) (bool, error)
}

then it's a matter of defining the methods somewhere, if we follow https://github.com/jessepeterson/mysqlscepserver (linked above) the functions could go in apple_mdm.SCEPMySQLDepot but I think that's up to you.

edit: challenge.Middleware is so simple that if we don't like that store interface we could make our own 🤔 , as long as we reject the request in a middleware somehow if the challenge is invalid, we should be alright.

edit II: and seems like challenge.Middleware is doing the check on all SCEP operations, but there's a TODO to maybe do it only for PKCSReq

roperzh commented 1 year ago

@mna forgot to mention you! ☝️

mna commented 1 year ago

@roperzh many thanks, that clears up a lot of things about that workflow! One thing about this:

edit II: and seems like challenge.Middleware is doing the check on all SCEP operations, but there's a TODO to maybe do it only for PKCSReq

This would be a problem if we want the challenge token to be single-use, time-limited. It looks like the initial operation is PKCSReq (or actually "PKIOperation") so that would be the time to validate and delete the token so it can't be reused. I'm guessing that from then on the challenge becomes irrelevant, but the description in the RFC has me worried a bit re: RenewalReq: https://datatracker.ietf.org/doc/html/rfc8894#name-pkcsreq-renewalreq. Do you know if a renewal implies a new enrollment profile? If not, the old enrollment profile will have a now-invalid challenge token and the renewal request would fail.

roperzh commented 1 year ago

@mna my understanding (which can be wrong) is that macOS won't ping the MDM server for renewals, instead the server has to send a InstallProfile command with a new enrollment profile before the current certificate expires.

This new enrollment profile will contain the new challenge, and the host will request a new certificate instead of a renewal.

A few things to note:

  1. I have read (not confirmed myself) that some MDM solutions just issue certificates that expire in something like ~10 years to not have to worry about renewals
  2. The new enrollment profile you send via InstallProfile cannot update some fields like the server url and the restrictions/permissions.
mna commented 1 year ago

@roperzh Yeah reading a bit more, that seems to be covered in the RFC (that renewal is an optionally supported feature):

If the CA supports certificate renewal and the CA policy permits, then a new certificate with new validity dates can be issued, even though the old one is still valid. To renew an existing certificate, the client uses the RenewalReq message[...]

gillespi314 commented 1 year ago

FWIW, I like the idea of trying to match the MicroMDM SCEP server interfaces where we can.

gillespi314 commented 1 year ago

See if smallstep/ca has support for dynamic challenges (proposed in https://github.com/fleetdm/fleet/issues/8269)

@roperzh @mna have y'all had a chance to look at smallstep? I just had a quick look and it looks like it could be really handy for lots of the certificate management/public key infrastructure stuff.

mna commented 1 year ago

@roperzh @gillespi314

have y'all had a chance to look at smallstep?

I took an admittedly quick look at it, but it seemed to me like it would be a lot of work to swap out our code based on micromdm for it, for (what seems from that quick look like) not much benefit. I don't think implementing the dynamic scep challenge on our own will be very hard (we already have the db table for it AFAICT). That's assuming that we haven't run into any major issues with micromdm.

That being said it's possible that I missed some important benefit that would make it worth the switch!

lukeheath commented 1 year ago

@mna Two questions for upcoming sprint planning:

  1. Roberto mentioned you already started work on this ticket. About how much work do you feel remains? We may decide to defer this to the next sprint unless you have already made significant progress.

  2. Is this ticket strictly needed to complete the associated epic? If not, we may separate this ticket from that epic and address this later.

Thanks for your feedback!

mna commented 1 year ago

@lukeheath there's probably a couple of days left on this, I haven't started coding much, just had time to explore the problem and figure out what would need to be done. I can certainly park it and come back to it later if there's more urgent things that require my attention.

I don't think it's strictly needed to complete the epic, the only thing is that as long as we don't have this, then we still need to keep around the (prototype) flag to set a static SCEP challenge on the fleet instance.

lukeheath commented 1 year ago

@mna Thanks for the update! Let's discuss on sprint planning.

mna commented 1 year ago

@lukeheath sounds good, in the meantime I've added some pointers (in the form of TODO(mna):) in the code as reminders of the changes needed when I (or someone else) comes back to implement this ticket. It's in the mna-8477-dynamic-scep-challenge branch.

noahtalerman commented 1 year ago

UPDATE: During today's sprint planning call (2022-01-16) we decided to defer working on this issue. It's not required to call the "Turn on MDM" story done.

TODO Noah: Decide if this should stay prioritized or get deferred further in the future.

noahtalerman commented 1 year ago

Hey @lukeheath @mna @roperzh I think we should punt on this now.

That said, I think this is something we should come back to before the April public launch of MDM so I left the ":product" label applied.

Also, I added this goal to the issue description that describes the story: "As a IT admin, I want to know that Fleet secures their MDM enrollment profiles so that I can provide this as argument to the security team when pitching Fleet."

Curious to hear your thoughts on this^

roperzh commented 1 year ago

@noahtalerman the big drawback of not doing this is that anyone with the secret will be able to enroll into MDM and get things like certificates, secrets, passwords, etc.

One example that comes to mind: if you unenroll somebody, but they grabbed the secret, they can use it to enroll again silently.

noahtalerman commented 1 year ago

big drawback of not doing this is that anyone with the secret will be able to enroll into MDM and get things like certificates, secrets, passwords, etc.

Makes sense 👍

We will address this before the public launch. Let's punt for now because it's not required to test/dogfood enrollment, profiles, and OS updates.

@lukeheath heads up, I think this is a good issue to estimate and bring into a sprint if we have extra capacity.

noahtalerman commented 1 year ago

cc @roperzh ^

lukeheath commented 1 year ago

Noah: We need to finish this before public MDM launch on 4/7.

zhumo commented 1 year ago

Hi @noahtalerman , this story did not make it into the current sprint, so I'm de-prioritizing it. Please bring it back to FF if necessary.

noahtalerman commented 3 months ago

Hey @roperzh, do you know if Jamf has dynamic SCEP challenges?

roperzh commented 3 months ago

@noahtalerman as far as I remember it does, but there might be an option to turn it off.

noahtalerman commented 2 months ago

Hey @zayhanlon heads up that we didn't get to designing this in the current design sprint. Pulling it off the drafting board for now.

I think we'll get to this (or something similar soon). It contributes to Jamf parity.

zayhanlon commented 2 months ago

@noahtalerman okay thanks - are you recommending that i don't bring this back to FF?

noahtalerman commented 2 months ago

@zayhanlon yes!