Nix SSL path set incorrectly in the daemon on macOS #226

Open
opened 2024-04-06 00:52:37 +00:00 by lunaphied · 6 comments
Owner

There's a bug in scripts/nix-profile-daemon.sh.in (and debatably all the other activation scripts) where on macOS, if you don't for some reason have system certificates in a path matching a Linux distribution (not a default configuration), it will try to find one in the default or user profile, which if you've accidentally misconfigured them without certificates, will then break, as there's no fallback for macOS.

It will then set the environment variable to a "random" broken path within the last profile

specifically, there's a state where it runs the /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh without having set NIX_SSL_CONF_FILE first, and that's not darwin'ized, so if your profiles get fucked, the fallback in here fails:

# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
if [ -n "${NIX_SSL_CERT_FILE:-}" ]; then
    : # Allow users to override the NIX_SSL_CERT_FILE
elif [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch
    export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
elif [ -e /etc/ssl/ca-bundle.pem ]; then # openSUSE Tumbleweed
    export NIX_SSL_CERT_FILE=/etc/ssl/ca-bundle.pem
elif [ -e /etc/ssl/certs/ca-bundle.crt ]; then # Old NixOS
    export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
elif [ -e /etc/pki/tls/certs/ca-bundle.crt ]; then # Fedora, CentOS
    export NIX_SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt
else
  # Fall back to what is in the nix profiles, favouring whatever is defined last.
  check_nix_profiles() {
    if [ -n "$ZSH_VERSION" ]; then
      # Zsh by default doesn't split words in unquoted parameter expansion.
      # Set local_options for these options to be reverted at the end of the function
      # and shwordsplit to force splitting words in $NIX_PROFILES below.
      setopt local_options shwordsplit
    fi
    for i in $NIX_PROFILES; do
      if [ -e "$i/etc/ssl/certs/ca-bundle.crt" ]; then
        export NIX_SSL_CERT_FILE=$i/etc/ssl/certs/ca-bundle.crt
      fi
    done
  }
  check_nix_profiles
  unset -f check_nix_profiles
fi
There's a bug in `scripts/nix-profile-daemon.sh.in` (and debatably all the other activation scripts) where on macOS, if you don't for some reason have system certificates in a path matching a Linux distribution (not a default configuration), it will try to find one in the default or user profile, which if you've accidentally misconfigured them without certificates, will then break, as there's no fallback for macOS. It will then set the environment variable to a "random" broken path within the last profile > specifically, there's a state where it runs the `/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh` without having set `NIX_SSL_CONF_FILE` first, and that's not darwin'ized, so if your profiles get fucked, the fallback in here fails: ```bash # Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work. if [ -n "${NIX_SSL_CERT_FILE:-}" ]; then : # Allow users to override the NIX_SSL_CERT_FILE elif [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt elif [ -e /etc/ssl/ca-bundle.pem ]; then # openSUSE Tumbleweed export NIX_SSL_CERT_FILE=/etc/ssl/ca-bundle.pem elif [ -e /etc/ssl/certs/ca-bundle.crt ]; then # Old NixOS export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt elif [ -e /etc/pki/tls/certs/ca-bundle.crt ]; then # Fedora, CentOS export NIX_SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt else # Fall back to what is in the nix profiles, favouring whatever is defined last. check_nix_profiles() { if [ -n "$ZSH_VERSION" ]; then # Zsh by default doesn't split words in unquoted parameter expansion. # Set local_options for these options to be reverted at the end of the function # and shwordsplit to force splitting words in $NIX_PROFILES below. setopt local_options shwordsplit fi for i in $NIX_PROFILES; do if [ -e "$i/etc/ssl/certs/ca-bundle.crt" ]; then export NIX_SSL_CERT_FILE=$i/etc/ssl/certs/ca-bundle.crt fi done } check_nix_profiles unset -f check_nix_profiles fi ```
lunaphied added the
bug
label 2024-04-06 00:52:37 +00:00
lunaphied added the
E/easy
E/help wanted
labels 2024-04-06 00:55:59 +00:00
Author
Owner

This is worse than expected for extremely silly reasons.

It turns out that on macOS, the daemon itself never even actually sees /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh because that file is loaded by (amongst other places that are unused) /etc/bashrc. Nix's default daemon is launched via non-interactive, non-login /bin/sh which runs /bin/bash in compatibility mode on macOS.

This means that it will not even see /etc/profile in the first place. So we try running it as a login shell right? Well. Not quite enough either. That will process /etc/profile and it will recognize itself as running under bash with $BASH being set, and properly source /etc/bashrc, except, that won't even get to the line that loads the environment for the Lix daemon, because it starts by checking if there's a $PS1 set already as a proxy for "are we running interactively".

What a mess. Let's just manually include the proper sourcing of the environment...

This is worse than expected for extremely silly reasons. It turns out that on macOS, the daemon itself never even actually *sees* `/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh` because that file is loaded by (amongst other places that are unused) `/etc/bashrc`. Nix's default daemon is launched via non-interactive, non-login `/bin/sh` which runs `/bin/bash` in compatibility mode on macOS. This means that it will not even *see* `/etc/profile` in the first place. So we try running it as a login shell right? Well. Not quite enough either. That will process `/etc/profile` and it will recognize itself as running under bash with `$BASH` being set, and properly source `/etc/bashrc`, except, that won't even get to the line that loads the environment for the Lix daemon, because it starts by checking if there's a `$PS1` set already as a proxy for "are we running interactively". What a mess. Let's just manually include the proper sourcing of the environment...
jade added the
OS/macOS
label 2024-10-18 22:11:15 +00:00
jade added the
Area/fetching
label 2024-10-20 01:04:57 +00:00
Member

Lix looks at /etc/ssl/certs/ca-certificates.crt and /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt by default for the ssl-cert-file option, which it will then override if NIX_SSL_CERT_FILE or SSL_CERT_FILE is defined. So the nix-daemon.sh script doesn't really matter here. If /etc/ssl/certs/ca-certificates.crt doesn't exist and all profiles have uninstalled ca-certificates then we don't have certificates to even find regardless of the environment. A proper fix here is to teach Lix to read the system certificates out of the keychain and synthesize a file for itself. Either that or to have Lix itself depend on pkgs.cacert to use as a fallback path if the system doesn't have any.

If we want to get system certs without writing a bunch of keychain code we could run security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain to print all the system roots in PEM format.

Lix looks at `/etc/ssl/certs/ca-certificates.crt` and `/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt` by default for the `ssl-cert-file` option, which it will then override if `NIX_SSL_CERT_FILE` or `SSL_CERT_FILE` is defined. So the `nix-daemon.sh` script doesn't really matter here. If `/etc/ssl/certs/ca-certificates.crt` doesn't exist and all profiles have uninstalled `ca-certificates` then we don't _have_ certificates to even find regardless of the environment. A proper fix here is to teach Lix to read the system certificates out of the keychain and synthesize a file for itself. Either that or to have Lix itself depend on `pkgs.cacert` to use as a fallback path if the system doesn't have any. If we want to get system certs without writing a bunch of keychain code we could run `security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain` to print all the system roots in PEM format.

Does this issue mean that all fresh lix macOS installed does not really work? I tried following the instructions from the website and ends up with an installation where I cannot basically do anything:

Output

andreas@flax ~ % curl -sSf -L https://install.lix.systems/lix | sh -s -- install
info: downloading installer https://install.lix.systems/lix/lix-installer-aarch64-darwin
`lix-installer` needs to run as `root`, attempting to escalate now via `sudo`...
Password:


Welcome to the Lix installer! Just a couple of quick questions.

Flakes are an experimental feature, but widely used in the community.
You can change this later in `/etc/nix/nix.conf`.

Enable flakes? ([Y]es/[n]o): y

QUICK NOTE: we've enabled the experimental nix command for you!
Be aware that commands starting with `nix ` such as `nix build` may change syntax.

Lix install plan (v0.17.1)
Planner: macos (with default settings)

Planned actions:
* Create an encrypted APFS volume `Nix Store` for Nix on `disk3` and add it to `/etc/fstab` mounting on `/nix`
* Fetch `https://releases.lix.systems/lix/lix-2.91.1/lix-2.91.1-aarch64-darwin.tar.xz` to `/nix/temp-install-dir`
* Create a directory tree in `/nix`
* Move the downloaded Nix into `/nix`
* Create build users (UID 351-382) and group (GID 350)
* Configure Time Machine exclusions
* Setup the default Nix profile
* Place the Nix configuration in `/etc/nix/nix.conf`
* Configure the shell profiles
* Configuring zsh to support using Nix in non-interactive shells
* Create a `launchctl` plist to put Nix into your PATH
* Configure Nix daemon related settings with launchctl
* Remove directory `/nix/temp-install-dir`


Proceed? ([Y]es/[n]o/[e]xplain): y
 INFO Step: Create an encrypted APFS volume `Nix Store` for Nix on `disk3` and add it to `/etc/fstab` mounting on `/nix`
 INFO Step: Provision Nix
 INFO Step: Create build users (UID 351-382) and group (GID 350)
 INFO Step: Configure Time Machine exclusions
 INFO Step: Configure Nix
 INFO Step: Configuring zsh to support using Nix in non-interactive shells
 INFO Step: Create a `launchctl` plist to put Nix into your PATH
 INFO Step: Configure Nix daemon related settings with launchctl
 INFO Step: Remove directory `/nix/temp-install-dir`
Nix was installed successfully!
To get started using Nix, open a new shell or run `. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish`

andreas@flax ~ % . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish
/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish:5: parse error near `else'
andreas@flax ~ % . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh 
andreas@flax ~ % nix run nixpkgs#hello
warning: unable to download 'https://cache.lix.systems/nix-cache-info': Problem with the SSL CA cert (path? access rights?) (77)
error: unable to download 'https://cache.nixos.org/8fpvkfwr8fm91xlzznsgh3g1fcw0hfnh.narinfo': Problem with the SSL CA cert (path? access rights?) (77)


Does this issue mean that all fresh lix macOS installed does not really work? I tried following the instructions from the website and ends up with an installation where I cannot basically do anything: <details><summary>Output</summary> ```log andreas@flax ~ % curl -sSf -L https://install.lix.systems/lix | sh -s -- install info: downloading installer https://install.lix.systems/lix/lix-installer-aarch64-darwin `lix-installer` needs to run as `root`, attempting to escalate now via `sudo`... Password: Welcome to the Lix installer! Just a couple of quick questions. Flakes are an experimental feature, but widely used in the community. You can change this later in `/etc/nix/nix.conf`. Enable flakes? ([Y]es/[n]o): y QUICK NOTE: we've enabled the experimental nix command for you! Be aware that commands starting with `nix ` such as `nix build` may change syntax. Lix install plan (v0.17.1) Planner: macos (with default settings) Planned actions: * Create an encrypted APFS volume `Nix Store` for Nix on `disk3` and add it to `/etc/fstab` mounting on `/nix` * Fetch `https://releases.lix.systems/lix/lix-2.91.1/lix-2.91.1-aarch64-darwin.tar.xz` to `/nix/temp-install-dir` * Create a directory tree in `/nix` * Move the downloaded Nix into `/nix` * Create build users (UID 351-382) and group (GID 350) * Configure Time Machine exclusions * Setup the default Nix profile * Place the Nix configuration in `/etc/nix/nix.conf` * Configure the shell profiles * Configuring zsh to support using Nix in non-interactive shells * Create a `launchctl` plist to put Nix into your PATH * Configure Nix daemon related settings with launchctl * Remove directory `/nix/temp-install-dir` Proceed? ([Y]es/[n]o/[e]xplain): y INFO Step: Create an encrypted APFS volume `Nix Store` for Nix on `disk3` and add it to `/etc/fstab` mounting on `/nix` INFO Step: Provision Nix INFO Step: Create build users (UID 351-382) and group (GID 350) INFO Step: Configure Time Machine exclusions INFO Step: Configure Nix INFO Step: Configuring zsh to support using Nix in non-interactive shells INFO Step: Create a `launchctl` plist to put Nix into your PATH INFO Step: Configure Nix daemon related settings with launchctl INFO Step: Remove directory `/nix/temp-install-dir` Nix was installed successfully! To get started using Nix, open a new shell or run `. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish` andreas@flax ~ % . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish:5: parse error near `else' andreas@flax ~ % . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh andreas@flax ~ % nix run nixpkgs#hello warning: unable to download 'https://cache.lix.systems/nix-cache-info': Problem with the SSL CA cert (path? access rights?) (77) error: unable to download 'https://cache.nixos.org/8fpvkfwr8fm91xlzznsgh3g1fcw0hfnh.narinfo': Problem with the SSL CA cert (path? access rights?) (77) ``` </details>

I did run into this problem: https://github.com/NixOS/nix/issues/2899. Even though I used lix-installer uninstall and manually removed a bunch of stuff from previous installs. I had a bad/broken symlink in /etc/ssl/certs/ca-certificates.crt which made it fail.

I did run into this problem: https://github.com/NixOS/nix/issues/2899. Even though I used lix-installer uninstall and manually removed a bunch of stuff from previous installs. I had a bad/broken symlink in `/etc/ssl/certs/ca-certificates.crt` which made it fail.
Member

I haven't run a fresh install in ages, my recollection is it sets up the default profile with both lix and pkgs.cacert, and that default profile is how it should find the certs. If you have a broken /etc/ssl/certs/ca-certificates.crt symlink though that will certainly break things. Perhaps we should detect the broken link when looking for certs?

I haven't run a fresh install in ages, my recollection is it sets up the default profile with both lix and `pkgs.cacert`, and that default profile is how it should find the certs. If you have a broken `/etc/ssl/certs/ca-certificates.crt` symlink though that will certainly break things. Perhaps we should detect the broken link when looking for certs?
Member

I filed #560 about the broken symlink.

I filed https://git.lix.systems/lix-project/lix/issues/560 about the broken symlink.
Sign in to join this conversation.
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lix-project/lix#226
No description provided.