{ description = "Manage local secrets for Nix configurations"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-20.09"; outputs = { self, nixpkgs }: let supportedSystems = [ "x86_64-linux" "i686-linux" "aarch64-linux" ]; forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system); in { nixosModules.localsecrets = import ./modules/localsecrets; lib = rec { writeSecret = { pkgs, name, secret }: let runtimeDirectory="secret-${name}"; in '' systemd-run \ --wait \ -p DynamicUser=true \ -p RuntimeDirectory=${runtimeDirectory} \ -p RuntimeDirectoryMode=${secret.mode} \ -p RuntimeDirectoryPreserve=true \ -p WorkingDirectory=/run/${runtimeDirectory} \ -p PrivateTmp=true \ ${pkgs.bash}/bin/bash -c '${secret.generator}' rm -rf "${secret.privateDir}" || true chown "${secret.user}:${secret.group}" "/run/${runtimeDirectory}/private" chmod "${secret.mode}" "/run/${runtimeDirectory}/private" mv "/run/${runtimeDirectory}/private" "${secret.privateDir}" rm -rf "${secret.publicDir}" || true mv "/run/${runtimeDirectory}/public" "${secret.publicDir}" ''; writeSecrets = nixosConfiguration: let pkgs = nixosConfiguration.pkgs; cfg = nixosConfiguration.config.localsecrets; lib = pkgs.lib; in pkgs.writeScriptBin "write-secrets" '' umask 0022 mkdir -p /var/lib/${cfg.stateDir}/public mkdir -p /var/lib/${cfg.stateDir}/private ${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: secret: writeSecret { inherit pkgs name secret; }) cfg.secrets)} ''; makeSyncerPackages = { nixosConfigurations, sshAccessor }: forAllSystems (system: let pkgs = import nixpkgs { inherit system; }; syncConfig = nixosConfiguration: let generator = writeSecrets nixosConfiguration; in '' nix copy -s --to ssh://${sshAccessor nixosConfiguration} ${generator} ssh ${sshAccessor nixosConfiguration} ${generator}/bin/write-secrets ''; in { localsecrets-syncer = pkgs.writeScriptBin "localsecrets-syncer" '' echo "Starting sync..." ${pkgs.lib.concatMapStrings syncConfig nixosConfigurations} echo "Done" ''; } ); }; packages = self.lib.makeSyncerPackages { nixosConfigurations = builtins.attrValues self.nixosConfigurations; sshAccessor = nixosConfiguration: let host = nixosConfiguration.config.networking.hostName; in "root@dragon.orbekk.com"; }; checks = forAllSystems (system: { test = let testing = import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }; in testing.makeTest { nodes.client = { pkgs, lib, ... }: { imports = [ self.nixosModules.localsecrets ]; localsecrets.enable = true; localsecrets.secrets.test-secret = { generator = pkgs.writeScript "test-secret.sh" '' #! ${pkgs.bash}/bin/bash PATH=${lib.makeBinPath (with pkgs; [ coreutils ])} mkdir -p private public echo hello > private/key.private echo world > public/key.public ''; }; }; testScript = '' start_all() client.wait_for_unit("multi-user.target") private = "/var/lib/localsecrets/private/test-secret/key.private" public = "/var/lib/localsecrets/public/test-secret/key.public" client.succeed("grep hello {}".format(private)) client.fail("sudo -u nobody cat {}".format(private)) client.succeed("grep world {}".format(public)) client.succeed("sudo -u nobody cat {}".format(public)) ''; }; }); nixosConfigurations.container = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ self.nixosModules.localsecrets ({lib, pkgs, ...}: { localsecrets.secrets.test-secret = { generator = pkgs.writeScript "test-secret.sh" '' #! ${pkgs.bash}/bin/bash PATH=${lib.makeBinPath (with pkgs; [ coreutils ])} mkdir -p private public echo hello > private/key.private echo world > public/key.public ''; }; boot.isContainer = true; } ) ]; }; }; }