Skip to content

Commit

Permalink
Support installing Nix on macOS on AWS EC2, without requiring a manua…
Browse files Browse the repository at this point in the history
…l full-disk-access approval (#1210)

* Add support for macOS without requiring FDA on EC2

This PR adds a flag to the installer for macOS that allows installing and using Nix on EC2 without a manual process of enabling full disk access.

On EC2, macOS requires the user to grant Full Disk Access to the Nix daemon or determinate-nixd for it to function.
However, the actual permission issue is access to removable volumes.
Users can provide a macOS policy (via MDM or manually) that allows access to removable volumes, but this also requires a manual setup process.

The key insight of this pull request is that by using the internal hard disk, we escape the "removable volume" limitation.

This PR's new flag sets the default root disk target to use the internal disk, instead of the disk that macOS is running from.
Note that this is feature-locked to determinate-nixd, because determinate-nixd accounts for a quirk of AWS's macOS deployment.
AWS's macOS infrastructure assumes all internal disks are unmounted, and will occasionally unmount the Nix Store.

Also:

* Switch to using init away from a stop-after in daemon
* flake.lock: Update

Flake lock file updates:

• Updated input 'determinate':
    'https://api.flakehub.com/f/pinned/DeterminateSystems/determinate/0.1.110%2Brev-cb916a7dd1b85d547edd6ba2f782a578ca4ef480/01923596-e372-7668-a456-5b32177e0dda/source.tar.gz?narHash=sha256-M9Z7OMrQHAmZQnuMYxdyqzV%2B7ApIXVbA2GXl62l1GTo%3D' (2024-09-27)
  → 'https://api.flakehub.com/f/pinned/DeterminateSystems/determinate/0.1.136%2Brev-ec5f982bd53acbece1c3a72a0dbf074ab5d79e10/019244a6-0aa7-72b5-9d85-a7bb7885aad3/source.tar.gz?narHash=sha256-sSGQJP7isahkRAzlOiLJjvoz/MijCsoFa6FgQIqbcFE%3D' (2024-09-30)
• Updated input 'determinate/determinate-nixd-aarch64-darwin':
    'https://install.determinate.systems/determinate-nixd/rev/2c18a8f38492d35be64d4e497b720938f17cc9f5/macOS?narHash=sha256-tmW%2BSqn9cautArLTych0mnKXD1abtaAuJGCUCrtUmeo%3D'
  → 'https://install.determinate.systems/determinate-nixd/rev/51ecec5a3148baef87c2015536aa12dd18e4c4ad/macOS?narHash=sha256-OhG8joS/uN3Kdw4h9w8F/6ZIVTFZ8J9Fb4NGn/KK5/s%3D'
• Updated input 'determinate/determinate-nixd-aarch64-linux':
    'https://install.determinate.systems/determinate-nixd/rev/2c18a8f38492d35be64d4e497b720938f17cc9f5/aarch64-linux?narHash=sha256-z5dg%2BqwLOjA4pjiCLReESa9qNYOtMxlaPXQQWNhEymA%3D'
  → 'https://install.determinate.systems/determinate-nixd/rev/51ecec5a3148baef87c2015536aa12dd18e4c4ad/aarch64-linux?narHash=sha256-AGcHQSIdb%2BKEJlhJzMB4YyFxbjdLZEDDf6bv6Zi3wqM%3D'
• Updated input 'determinate/determinate-nixd-x86_64-linux':
    'https://install.determinate.systems/determinate-nixd/rev/2c18a8f38492d35be64d4e497b720938f17cc9f5/x86_64-linux?narHash=sha256-8sENexNuv7gsVAeQx1xuJd8IQtociheylIeEjFRYbQI%3D'
  → 'https://install.determinate.systems/determinate-nixd/rev/51ecec5a3148baef87c2015536aa12dd18e4c4ad/x86_64-linux?narHash=sha256-kU4dqHoYe3sFf4LDAUj4fyl9uGV8IHtE22%2BDdMeRN0s%3D'
• Updated input 'nixpkgs':
    'https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.685764%2Brev-1925c603f17fc89f4c8f6bf6f631a802ad85d784/01923479-4bef-7480-a7b0-72f6d33a5318/source.tar.gz?narHash=sha256-J%2BPeFKSDV%2BpHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI%3D' (2024-09-26)
  → 'https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.687049%2Brev-06cf0e1da4208d3766d898b7fdab6513366d45b9/019243b7-0a9f-79f7-b57a-4e0cfd13a578/source.tar.gz?narHash=sha256-S5kVU7U82LfpEukbn/ihcyNt2%2BEvG7Z5unsKW9H/yFA%3D' (2024-09-29)
  • Loading branch information
grahamc authored Oct 1, 2024
1 parent 50a237a commit c70ddc7
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 52 deletions.
38 changes: 19 additions & 19 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/action/common/configure_init_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ impl Action for ConfigureInitService {
})?;
}

crate::action::macos::retry_bootstrap(&domain, &service, &service_dest)
crate::action::macos::retry_bootstrap(domain, service, service_dest)
.await
.map_err(Self::error)?;

Expand Down
2 changes: 1 addition & 1 deletion src/action/macos/bootstrap_launchctl_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl Action for BootstrapLaunchctlService {
}

if !*is_present {
crate::action::macos::retry_bootstrap(DARWIN_LAUNCHD_DOMAIN, &service, &path)
crate::action::macos::retry_bootstrap(DARWIN_LAUNCHD_DOMAIN, service, path)
.await
.map_err(Self::error)?;
}
Expand Down
6 changes: 5 additions & 1 deletion src/action/macos/create_determinate_nix_volume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct CreateDeterminateNixVolume {
disk: PathBuf,
name: String,
case_sensitive: bool,
use_ec2_instance_store: bool,
create_directory: StatefulAction<CreateDirectory>,
create_or_append_synthetic_conf: StatefulAction<CreateOrInsertIntoFile>,
create_synthetic_objects: StatefulAction<CreateSyntheticObjects>,
Expand All @@ -51,6 +52,7 @@ impl CreateDeterminateNixVolume {
name: String,
case_sensitive: bool,
force: bool,
use_ec2_instance_store: bool,
) -> Result<StatefulAction<Self>, ActionError> {
let disk = disk.as_ref();
let create_or_append_synthetic_conf = CreateOrInsertIntoFile::plan(
Expand Down Expand Up @@ -87,6 +89,7 @@ impl CreateDeterminateNixVolume {
let setup_volume_daemon = CreateDeterminateVolumeService::plan(
VOLUME_MOUNT_SERVICE_DEST,
VOLUME_MOUNT_SERVICE_NAME,
use_ec2_instance_store,
)
.await
.map_err(Self::error)?;
Expand All @@ -106,6 +109,7 @@ impl CreateDeterminateNixVolume {
disk: disk.to_path_buf(),
name,
case_sensitive,
use_ec2_instance_store,
create_directory,
create_or_append_synthetic_conf,
create_synthetic_objects,
Expand Down Expand Up @@ -219,7 +223,7 @@ impl Action for CreateDeterminateNixVolume {
.map_err(Self::error)?;

let mut command = Command::new("/usr/local/bin/determinate-nixd");
command.args(["--stop-after", "mount", "daemon"]);
command.args(["init", "--stop-after", "mount"]);
command.stderr(std::process::Stdio::piped());
command.stdout(std::process::Stdio::piped());
tracing::trace!(command = ?command.as_std(), "Mounting /nix");
Expand Down
31 changes: 18 additions & 13 deletions src/action/macos/create_determinate_volume_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,22 @@ pub struct CreateDeterminateVolumeService {
path: PathBuf,
mount_service_label: String,
needs_bootout: bool,
use_ec2_instance_store: bool,
}

impl CreateDeterminateVolumeService {
#[tracing::instrument(level = "debug", skip_all)]
pub async fn plan(
path: impl AsRef<Path>,
mount_service_label: impl Into<String>,
use_ec2_instance_store: bool,
) -> Result<StatefulAction<Self>, ActionError> {
let path = path.as_ref().to_path_buf();
let mount_service_label = mount_service_label.into();
let mut this = Self {
path,
mount_service_label,
use_ec2_instance_store,
needs_bootout: false,
};

Expand Down Expand Up @@ -67,9 +70,10 @@ impl CreateDeterminateVolumeService {
let discovered_plist: LaunchctlMountPlist =
plist::from_file(&this.path).map_err(Self::error)?;

let expected_plist = generate_mount_plist(&this.mount_service_label)
.await
.map_err(Self::error)?;
let expected_plist =
generate_mount_plist(&this.mount_service_label, use_ec2_instance_store)
.await
.map_err(Self::error)?;
if discovered_plist != expected_plist {
tracing::trace!(
?discovered_plist,
Expand Down Expand Up @@ -131,15 +135,16 @@ impl Action for CreateDeterminateVolumeService {
path,
mount_service_label,
needs_bootout,
use_ec2_instance_store,
} = self;

if *needs_bootout {
crate::action::macos::retry_bootout(DARWIN_LAUNCHD_DOMAIN, &mount_service_label, &path)
crate::action::macos::retry_bootout(DARWIN_LAUNCHD_DOMAIN, mount_service_label, path)
.await
.map_err(Self::error)?;
}

let generated_plist = generate_mount_plist(mount_service_label)
let generated_plist = generate_mount_plist(mount_service_label, *use_ec2_instance_store)
.await
.map_err(Self::error)?;

Expand Down Expand Up @@ -180,18 +185,18 @@ impl Action for CreateDeterminateVolumeService {
/// This function must be able to operate at both plan and execute time.
async fn generate_mount_plist(
mount_service_label: &str,
use_ec2_instance_store: bool,
) -> Result<LaunchctlMountPlist, ActionErrorKind> {
let mut arguments = vec!["/usr/local/bin/determinate-nixd".into(), "init".into()];
if use_ec2_instance_store {
arguments.push("--keep-mounted".into());
}
let mount_plist = LaunchctlMountPlist {
run_at_load: true,
label: mount_service_label.into(),
program_arguments: vec![
"/usr/local/bin/determinate-nixd".into(),
"--stop-after".into(),
"mount".into(),
"daemon".into(),
],
standard_out_path: "/var/log/determinate-nixd-mount.log".into(),
standard_error_path: "/var/log/determinate-nixd-mount.log".into(),
program_arguments: arguments,
standard_out_path: "/var/log/determinate-nix-init.log".into(),
standard_error_path: "/var/log/determinate-nix-init.log".into(),
};

Ok(mount_plist)
Expand Down
2 changes: 1 addition & 1 deletion src/action/macos/create_nix_hook_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl Action for CreateNixHookService {
} = self;

if *needs_bootout {
crate::action::macos::retry_bootout(DARWIN_LAUNCHD_DOMAIN, &service_label, &path)
crate::action::macos::retry_bootout(DARWIN_LAUNCHD_DOMAIN, service_label, path)
.await
.map_err(Self::error)?;
}
Expand Down
2 changes: 1 addition & 1 deletion src/action/macos/create_volume_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl Action for CreateVolumeService {
} = self;

if *needs_bootout {
crate::action::macos::retry_bootout(DARWIN_LAUNCHD_DOMAIN, &mount_service_label, &path)
crate::action::macos::retry_bootout(DARWIN_LAUNCHD_DOMAIN, mount_service_label, path)
.await
.map_err(Self::error)?;
}
Expand Down
16 changes: 16 additions & 0 deletions src/os/darwin/diskutil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,19 @@ pub struct DiskUtilApfsListVolume {
pub name: Option<String>,
pub encryption: bool,
}

#[derive(serde::Deserialize, Clone, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct DiskUtilList {
pub all_disks_and_partitions: Vec<DiskUtilListDisk>,
}

#[derive(serde::Deserialize, Clone, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct DiskUtilListDisk {
#[serde(rename = "OSInternal")]
pub os_internal: bool,
pub device_identifier: String,
#[serde(rename = "Size")]
pub size_bytes: u64,
}
Loading

0 comments on commit c70ddc7

Please sign in to comment.