# Turns an instance repository into everything it describes. The instance follows a fixed layout: # spec/default.nix the specification (checked against spec/schema.nix of sov) # sites/ the websites' sources, referenced from the spec # secrets/server.yaml secrets the server reads (sops; recipients in .sops.yaml) # secrets/admin.yaml secrets only the owner's tools read # secrets/host_key.sops the server's SSH host key, its identity (owner only); host_key.pub # host/default.nix what is specific to the machine: hardware, disk, network # # Usage, in the instance's flake.nix: outputs = { self, sov }: sov.lib.instance { inherit self; }; inputs@{ self, nixpkgs, disko, sops-nix, nixos-anywhere, ... }: { self }: let sovFlake = inputs.self; instance = self; inherit (nixpkgs) lib; system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; sov = import ../spec/derive.nix { inherit lib; specification = instance + "/spec"; }; host = sov.spec.server.hostname; server = extra: args: lib.nixosSystem { inherit system; specialArgs = { inherit inputs sov instance; } // args; modules = [ disko.nixosModules.disko sops-nix.nixosModules.sops ../modules (instance + "/host") ] ++ extra; }; tool = name: deps: script: { type = "app"; program = toString (pkgs.writeShellScript name '' export PATH=${lib.makeBinPath deps}:$PATH exec ${script} "$@" ''); }; in { # The specification as data, for the sov command (nix eval .#spec.). inherit (sov) spec; # What the sov command needs from the system: the secrets catalogue and the heartbeats. sov = { inherit (instance.nixosConfigurations.${host}.config.sov) secrets heartbeats state; }; nixosConfigurations = { # The server, including the monthly recovery drill, which installs the copy below. ${host} = server [ ../modules/drill.nix ] { drill = instance.nixosConfigurations.drill.config.system.build; }; # The same server for the recovery drill, without effects on the outside world. drill = server [ ../modules/drill-target.nix ] { }; }; checks.${system} = { # Boots the shared base in a VM and checks its hardening. base = pkgs.testers.runNixOSTest (import ../tests/base.nix { inherit sov sops-nix; }); # The real system builds. server = instance.nixosConfigurations.${host}.config.system.build.toplevel; }; apps.${system} = { # Everything done from outside the server: nix run .#sov -- help sov = tool "sov" [ pkgs.python3 pkgs.sops pkgs.git pkgs.nix pkgs.openssh pkgs.ssh-to-age pkgs.age pkgs.qrencode pkgs.coreutils pkgs.gh ] "${pkgs.python3}/bin/python3 ${../tools/sov.py}"; # Wipes a VPS and installs this instance onto it: nix run .#install -- @ install = tool "install" [ pkgs.sops pkgs.coreutils pkgs.openssh nixos-anywhere.packages.${system}.default ] "${../tools/install.sh} ${host}"; }; # `nix develop`: the sov command as `sov`, plus sops and age. devShells.${system}.default = pkgs.mkShell { packages = [ (pkgs.writeShellScriptBin "sov" ''exec ${instance.apps.${system}.sov.program} "$@"'') pkgs.sops pkgs.age ]; }; }