My talk on PTN 11

Note

Aug 3, 2024

· ~3 min read
pwnwriter's talk in owasp Kathmandu

PTN — Pentester Nepal, is a community for security folks in Nepal. They organize events, meetups, and challenges. PTN 11 was their 11th anniversary event, and I got to speak there.

My talk was on OS as Code: Using Nix on Apple Silicon.

What even is Nix?

Nix is three things at once — a purely functional programming language, a package manager, and an entire Linux distro (NixOS) built around it.

The package repo, nixpkgs, lives on GitHub and is honestly the largest and most up-to-date collection of packages I’ve seen. Everything is a derivation.

NixOS

If you take Nix the package manager and build an entire OS around it, you get NixOS. Your whole system — packages, services, users, networking — lives in a single configuration.nix file. That’s the “OS as Code” part. You commit it to git, push it, and spin up the exact same machine anywhere. Wipe and reinstall? Just run nixos-rebuild switch. Back to exactly where you were.

Why Nix though?

The main idea is declarative configuration. Instead of running:

$ apt install git

You write:

{
  environment.systemPackages = with pkgs; [ git ];
}

And you get the exact same result every time, on every machine. That’s the whole point — reproducible environments. No more “works on my machine” nonsense.

It’s also immutable by default. All packages live in /nix/store with their hash in the path. Nothing overwrites anything. Rollbacks are trivial.

The learning curve is real though. New filesystem layout, new language, a whole rabbit hole — but once it clicks, it clicks.

Installing

The cleanest way to install Nix (not NixOS, just the package manager) is via the Determinate Systems installer:

curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install

It comes with flake support out of the box, it’s easy to uninstall, and it’s written in Rust — so obviously I like it.

Flakes and Direnv

A flake.nix has two parts — inputs (your dependencies) and outputs (what you’re providing). It pins everything, so unlike the old nix-shell approach, you’re not at the mercy of whatever channel your system has.

Pair that with direnv and nix-direnv, and your dev shell loads automatically when you cd into a directory. The presentation repo itself is an example of this — just direnv allow and you’re in.

Home Manager and nix-darwin

Home Manager lets you manage all your dotfiles and user packages declaratively through Nix. One fun example from the talk — building a starship prompt that shows a different icon depending on whether you’re on macOS or Linux, all in Nix.

For Apple Silicon specifically, nix-darwin brings the NixOS-style declarative config to macOS. You get the same environment.systemPackages and module system but on Darwin.

This is what makes “OS as Code” actually work on a Mac — nix-darwin handles the system layer, home-manager handles the user layer, and flakes tie it all together.

The presentation itself was built and rendered using presenterm, inside a Nix flake, on NixOS. Bit of a meta moment.

You can find the slides at github:pwnwriter/PTN11.

↞  Back to notes