Nix on macOS Catalina, risks with unencrypted Nix store, possibilities for encrypted Nix store

I just installed Nix on my MacBook Pro 2017, which unfortunately doesn’t possess a T2 chip. I therefore installed using an unencrypted Nix store mounted as a separate volume.

I’ve read the documentation and there are a few options for installing Nix on macOS and I chose the recommended one. I do not like having unencrypted volumes on my Mac however.

What are the risks with having the Nix store on an unencrypted volume? What information about the system can be deduced from the Nix store? What vulnerabilities am I exposing myself to?

Knowing the state of the Nix/NixOS documentation and the tendency for it to be outdated sometimes, I’m wondering if there are other options than those documented? Is it possible to have an encrypted Nix store at this stage? Has someone figured it out?

I’m also open to the idea of rebuilding packages with an alternative path (/opt/nix for example). I have three Macs I’d like to use Nix on, should I set up my own binary cache with packages built with an alternative path?

On a machine without a T2, if the volume isn’t encrypted, someone with physical access to your machine can extract your hard drive and read the volume. This has two primary risks in the context of Nix:

  1. The attacker can see what software you have installed in your profile, since profiles are (by default) part of the Nix volume.
  2. Everything you compile using Nix gets copied into the Nix store, so if you use Nix to compile a closed-source project, that source is on the volume. This does not apply to using Nix merely to satisfy dependencies (e.g. with nix-shell or similar).

For what it’s worth, in the next few weeks I am planning on investigating the best way to deal with an encrypted Nix volume such that it’s available prior to GUI session login.

One example of dangerous behavior of @lilyball’s 2nd point- you make a custom derivation and the derivation’s source.nix contains a secret. You delete source.nix but a copy is still stored in /nix, so you’re at risk. (That’s how I’ve interpreted previous points on this topic, haven’t verified personally)

@lilyball You may have already seen the links at the end of this comment, but it sounds like some folks at Shopify have a working ruby implementation in their dev bootstrap code; may narrow your scope to translation/validation?

1 Like

I think the doc covers all of the ~viable options. The ruby implementation I mentioned in my previous post is technically/supposedly an improvement over the situation the doc describes. It needs to be translated/tested/vetted before I’d be comfortable recommending it to anyone who isn’t prepared to do those 3 things themselves.

I think/hope the doc is fairly clear here:

If you like, you can also add encryption to the recommended approach taken by the installer.

It’s absolutely possible, but there are a lot of caveats. There’s no supported one-size-fits-all well-vetted process yet. The doc sticks to what we feel comfortable recommending to general users who may not know what they’re getting themselves into. Caveat emptor, etc.

This has two primary risks in the context of Nix

Couldn’t an attacker inject data into the Nix store, too? Such as replacing the bash (or firefox or whatever) binary with something malicious?

I have not previously considered the notion of an attacker removing the physical media, modifying the volume, and then putting it back. I suppose that could indeed work.

Thank you for the link! I had not seen that before. Putting the password into the System keychain was going to be the first thing I tested. The ruby implementation is helpful because it’s granting access off the bat to two processes, which is good information to have.

I still have to figure out if there’s any chance LaunchDaemons will be deferred until it mounts or if I still need to use wait4path in daemons. And there’s the mild worry that Apple will decide a new process needs access to the password, but in my case I don’t actually need an unattended install, and OS upgrades aren’t unattended either. It would surprise me for Apple to make any changes of this nature outside of major OS releases though.

I’m also hoping to get a Big Sur VM set up, so I can test that Nix still works there, and that the Nix volume mounting also works.

I’ve been led to believe that the system keychain skirts this need–so I’m optimistic. However, since some people appear to have done fine with a login keychain and no specific effort to mitigate the race condition, I’m on the fence until someone who has faced the issue can verify it.

I have not previously considered the notion of an attacker removing the physical media, modifying the volume, and then putting it back . I suppose that could indeed work.

Oh, I wasn’t thinking of removing the physical media. I was more thinking of booting from a Live USB to tamper with the partition.

However, these are very different threats:

  1. Laptop is stolen, technically competent thief/buyer reads secrets in Nix store
  2. Laptop is tampered with, without the owner knowing

Maybe the second shouldn’t be considered at all, since once someone has physical access, they could do a lot more than worry about Nix.

Ah! I almost forgot about a few small notes I saved out. They may not be useful here, but just in case. :slight_smile:

While looking into the performance issue with syspolicyd executable assessments I stumbled on two commands that may help with this t2/encryption work and that we don’t appear to have been aware of back when we were actively working on the installer update:

  • /usr/libexec/remotectl dumpstate lists information on the actual T2 chip. We’re currently using xartutil to infer the presence of the chip.
  • sudo sysadminctl -filesystem status may be a simpler way to figure out if they have filevault on than the current multi-step process. Here are some output examples with and without FDE:
    $ sudo sysadminctl -filesystem status
    2019-10-13 10:16:41.266 sysadminctl[61797:3404423] Boot volume CS FDE: NO
    2019-10-13 10:16:41.298 sysadminctl[61797:3404423] Boot volume APFS FDE: YES
    $ sudo sysadminctl -filesystem status
    2020-07-16 13:41:30.970 sysadminctl[18361:2709433] Boot volume CS FDE: NO
    2020-07-16 13:41:31.010 sysadminctl[18361:2709433] Boot volume APFS FDE: NO
    

I won’t pretend to have any deep experience here or have gamed this out previously, but I had a hodgepodge of thoughts:

  1. I assume this would work on pre-T2 hardware.

  2. I imagine the attacker will need some knowledge of Nix or a very brute-force approach to succeed.

    • They’ll be flying blind to some extent unless the user keeps a very well-groomed store. (I don’t think it will be obvious which executables are included in the system/user profile; they’d probably have to crawl the entire tree and bulk-replace, say, every shell and hope the user is even using a Nix-installed shell, etc?)

    • You might be at slightly greater risk here if your entire config is public, since it’d be easier to know what to prepare for.

  3. I’m not certain FileVault (alone) would keep you safe from this on pre-T2 hardware? The system would need to be smart enough to refuse to mount a “strange” partition in the event that someone live-booted the system, nuked your encrypted store partition, and replaced it with an unencrypted one.

  4. For anyone in this position (i.e., pre-T2 Mac) that feels like they’re interesting enough of a target to attract the attention of someone sophisticated enough to mount this attack:

    • Unless it’s completely out of the question, I’d personally recommend investing in newer T2 hardware before spending much time/thought on other mitigations.

    • Likewise, it’s probably prudent to just assume any hardware is compromised once it’s been out of your custody.

    • I imagine it’s feasible to guard against this by checksumming the profile on build, storing that information on the primary encrypted volume, and validating it on boot before running anything on the partition.

    • If you value security over boot time, you could probably nullify this by checking/verifying/repairing the store on boot with nix-store --repair --verify --check-contents. (I guess they could compromise the nix executable/daemon; you might still need a more basic checksum approach to spot that and panic?)

Oh whoops, I only meant to suggest that injection would be possible for an unencrypted disk. I agree that an attack on an encrypted partition is unrealistic. For most people, an attack on even an unencrypted disk is unrealistic, too.

I guess they could compromise the nix executable/daemon

I mean, at that point, if your main partition is unencrypted, they might as well just swipe your ssh keys etc.

You communicated it clearly :slight_smile:

I’m just wondering aloud how much incremental security is added by encrypting the second volume. If the system can detect and reject a replaced partition, it adds a lot. If the system will happily mount a new malicious unencrypted store partition, it’s just a marginal improvement.

I’m assuming a T2-encrypted boot volume. But AFAIK if your store is on another one, Nix should be:

$ readlink --canonicalize $(type -p nix)
/nix/store/aizhr07dljmlbf17wfrj40x3s0b5iv3d-nix-2.3.4/bin/nix

So, to validate the store with your normal Nix binary, you’d have to be able to trust it :slight_smile:

1 Like

I very explicitly am not using an encrypted Nix partition on my machines precisely because keeping it in the login keychain is problematic (in particular, Terminal.app tries to restore its tabs before the Nix volume is mounted, and I use a Nix-installed shell as my login shell, so I lose all of my tabs on reboot).

This is interesting. I wonder if there’s any other way too, to explicitly query “are disks encrypted at rest” rather than “do we have a T2 chip”. I notice that diskutil ap list on my unencrypted Nix volume says “FileVault: No (Encrypted at rest)” on my T2 machine and just says “FileVault: No” on my non-T2 machine (in the plist output this seems to be represented by the separate Encryption and FileVault keys). But I don’t know if diskutil can tell me whether volumes will be encrypted at rest prior to creation. I suppose we could create the volume unencrypted, then check if it’s encrypted at rest, and if not then destroy the volume and error out.

/usr/bin/fdesetup isactive also exists and returns FDE status (“true” with status 0 if enabled, “false” with status 1 if disabled). It doesn’t even require admin rights to query.

1 Like

Yep. I have the same setup, and your experience here warded me off of trying.

Using it as a proxy definitely makes me uneasy and feels fragile over the long run. It may be moot if you find the system keychain to be a good encryption flow that we can use for any mac with FDE enabled. IIRC the only reason to detect it was to try and cover one extra group of users–T2, but no FDE–with the current install flow.