-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
darwin: encrypt nix volume if filevault is enabled #4181
Conversation
Broad strokes - mount the volume with a launchdaemon instead of fstab; fstab isn't processed at the right time to avoid race conditions for mounting and decrypting /nix in time for programs that need to restore - generate a random credential and store it in keychain; both the system and login keychains appear to be compatible with this approach
This should make the keychain entry we add compatible with the way the system tries to check keychain for entries (it appears to look for an entry with a "service" or "where" field == VolumeUUID).
Making the FS overridable makes it easier to play with 'Case-sensitive APFS' in CI or on local systems. This will help people explore whether it improves compatibility with nixpkgs (or creates more trouble than it's worth...).
I could use help hammering out an issue with as many nix+macOS stakeholders as we can round up on short notice. I have opinions here, but my overriding interest is finding the quickest path to single-invocation macOS Nix installs for Catalina and Big Sur that Just Work without making prospective users crawl through glass anymore. I'm going to try to sketch out the facts and and opinions I'm already aware of without staking anyone down by naming names. Please point out anything I'm missing! QuestionShould this approach apply to single-user installs, or not? (and, in either case, how) ContextMy rough understanding is that single-user installs are intended to be simpler, work even if Nix doesn't support the service manager, install without root, (and be simple to uninstall?) Starting with Catalina, I think it's fair to characterize both single and multi-user macOS installs as already violating:
The PR as it stands:
There are also some more general concerns here, like minimizing the number of possible install variants. Solutions?
I'll edit in any suggestions that don't boil down to one of the above, and note apparent votes/endorsements (but do correct me if I misrepresent you). Here's a related IRC discussion that has bearing on any path that makes multi-user the default:
|
As per my NixCon talk |
@domenkozar I thought you were in favor of getting rid of multi-user installs?
Hm, I have trouble parsing this... |
I am in favor of reducing complexity across whole Nix code base that impacts users and our support. One of the factors is branching of logic per installation method. I'm in favor of merging them, if that's the pragmatic solution for macOS by defaulting to multi-user installations. |
I completely agree. I've been solely using multi-user installs on all of my Macs for the past few years. It works reliably and is more secure than single-user, to boot. |
@abathur Thank you for all of your work on this. It's a (mostly) thankless task and full of corner cases, but greatly appreciated. |
I was actually planning on looking into this problem this very week, as I'm currently working on figuring out how to deploy Nix to my team 😅 I have not yet looked at what this PR does but here are my immediate thoughts:
|
Regarding the keychain thing, I wonder if someone can expend an Apple developer account incident to see if we can get in touch with an Apple filesystem engineer in order to confirm whether the "grant keychain access to these 2 processes" is reliable going forward, or whether there's any alternative supported mechanism. |
What is the reason for using |
scripts/create-darwin-volume.sh
Outdated
if ! test_voldaemon; then | ||
echo "Configuring LaunchDaemon to mount '$volume'..." >&2 | ||
generate_mount_daemon | sudo tee /Library/LaunchDaemons/org.nixos.darwin-store.plist >/dev/null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to check if the volume is encrypted first. If this is using a pre-existing unencrypted Nix volume, then the LaunchDaemon is superfluous (and the keychain entry won't exist).
For that matter, if it's using a pre-existing Nix volume at all, then there's no guarantee about the keychain entry's status. We should probably actually just skip this if we're not creating the volume. Anyone who creates their own volume is then on the hook for managing its mounting, and we can print a warning to this effect in the "Using existing volume" path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've wrestled with this a bit. The latest update may resolve it, though that's contingent on what people think of the "curing" approach (and it likely needs logical refinement).
Basically, I've cut attempts to infer user intent or do anything magic based on what exists. If the root is read-only and NIX_VOLUME_CREATE=1
(the default), the installer will want to create a volume (encrypted if filevault is on), and the "curing" version currently enabled asks the user for permission to remove anything that conflicts (volume, keychain credentials, fstab, synthetic.conf, daemon) before it'll install.
I've gone to a little pain to set up create-darwin-volume.sh so that it'll still behave roughly as it currently does if invoked with no arguments, but to also support passing a function to call when you source or invoke it. I won't say there's a clear path to it yet since I haven't thought through the logistics of scripting this exact case, but I'm inclined to close off some options for now and focus on getting the golden path right--but make the installer scripts flexible enough that people can leverage them rather than just copy and customize them?
Yes (with FileVault enabled, at least).
I tried automount a month or so back, but it was also too late to solve the problem. |
It may be late, but it should block any process trying to access a file there until the volume is mounted? And I am pretty sure you can automount local volumes as well. |
Yes.
Perhaps, but it didn't help apps restore and doesn't solve the problem. |
@mroi @lilyball I think I caught myself lying about I'm fairly sure it's a dead end by this point (after banging my head on it again today), but I revisited it to verify for sure whether or not I thought I made this work a month ago with a line in /etc/auto_master like I hadn't used If you have any success--I also recall having trouble getting it to mount at any root path. |
Replace the cumbersome two-step process, involving an expect script, for passing the generated password in to the security program.
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: |
I have not ever actually configured automount myself. I did look through the manpages the other day and was disappointed that it didn't have any direct examples of automounting a local volume. |
@mroi @lilyball I've been searching through some of the underlying components here to see if I can find any way we could trigger, on-demand, the system mechanism that unlocks from keychain. I stumbled on an interesting issue (openwall-com-au/BootUnlock#12) on a project (https://github.com/openwall-com-au/BootUnlock) that is picking at something similar. I haven't had time to read much of it yet, but a quick skim makes me think it may help answer some timeline questions. The repo also includes an approach to any process that can use security having access. I've seen this elsewhere but forgot about it. They're making/signing a copy of the security program, so that they can just permit that one.
Yes. Tricky to search, too. I assume I found an example somewhere, but I haven't been able to re-find it. |
We really should not go down that rabbit hole. We should refrain from putting anything else on the system outside of the normal Nix locations that's not strictly necessary (which is to say, removing the launch daemon plist should be sufficient to clean up the daemon behavior). And since the volume is expected to be mounted always while the system is running I really would not worry about trying to keep the password secure. Any attacker who has access to the running system can already inspect the contents of the volume, we're encrypting it to protect against offline access, and I don't think "attacker has access to running system but can only exfiltrate a few dozen bytes of data, wants to record the password so they can swipe the physical machine later and decrypt the Nix volume" is a practical threat model to care about. |
I agree. Mostly just find it interesting/telling that they haven't found anything better. Manually invoking diskarbitrationd, or killing it and letting launchd restart it, will both trigger a failed attempt to mount the volume (visible in the logs), so I'm not sure it's the originator of the requests that actually unlock it. If it is, there's just something different about the two contexts... I spent a while stepping through verbose logs, and tried restarting most of the other components I could spot as involved, but nothing triggered it to automatically mount. The log entries closest to the actual auth process appear to be |
We did :), but it requires a creation of a tool that is quite complex. The reverse engineering of Apple's SecurityAgentPlugins shows that the Now, the challenge is that all Apple tools ( |
Apologies for the radio silence. I've pushed a large ~WIP refactor (fair warning: I hope to obsolete & remove chunks of this, pending discussion) of this PR (and the existing installer). I think the most-important high-level changes are:
I have updated the installer in the first post if you'd like to try it. Otherwise, you can see it in action:
I'll also briefly outline ~motives in case it helps connect any dots. If the above makes (narrative?) sense to you, you can probably ignore the list below.
|
I've done some additional refactoring of the work here. I've changed enough that I think it merits a fresh look, so I've opened a new PR #4289 to take over the work here and am closing this one. If you're subscribed here, you'll probably want to subscribe to that one. |
Motive/Goal
Get single-invocation
curl -L https://nixos.org/nix/install | sh
installs working on macOS Catalina+Recap in case it helps anyone:
--darwin-use-unencrypted-nix-store-volume
scare-flag to make sure people with Opinions and/or compliance concerns would pay attention, and left the remainder (non-T2 devices with FileVault enabled) to manually prepare their volumes.We've recently confirmed that we can skirt the race condition by using a RunAtLoad LaunchDaemon to unlock and mount the volume. (I've tested straightforward cases like restoring editors with open files on the /nix volume, and restoring .apps managed by Nix. It may still be possible to force race conditions with multiple RunAtLoad daemons, but I think it's OK to work around those as-needed with
wait4path
.)Status
--no-daemonTo finish the code out, we need to haggle over how this should affect single-user mode and "default" macOS installs. (see upcoming 2nd post for more on this):blocked single-user macOS installsTry it out?
I have a temporary installer up at https://files.t-ravis.com/install-volume, so
curl https://files.t-ravis.com/install-volume | sh
should work. If you can't try it out, you can see output from the CI run (same one listed earlier). I refresh it to test larger functionality changes, but it may be a few commits behind if they don't merit the chore of regenerating. Here's a history of the versions it has pointed at, with the current at the bottom:4e3a3551668c39 (broken)b9657d5c95ce48366cb2b (install OK but service broken)eab5cb2 (install OK but service broken)97d946a (install OK but service broken)0c565a26541c0d385994d@LnL7 @lilyball @matthewbauer @dhess @mroi @domenkozar (others I'm forgetting are inevitably also interested; feel free to add people)