From 53503cecc6000645b42cbba9d7af2fc4242e453a Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sun, 27 Mar 2022 18:28:45 +0000 Subject: [PATCH] feat: shared secrets expected owners --- --- a/crates/nixlike/Cargo.toml +++ b/crates/nixlike/Cargo.toml @@ -4,7 +4,7 @@ edition = "2021" [dependencies] -dprint-core = "0.50.0" +dprint-core = "0.51.0" linked-hash-map = "0.5.4" peg = "0.8.0" serde = "1.0.130" --- a/lib/default.nix +++ b/lib/default.nix @@ -1,47 +1,56 @@ { flake-utils }: { fleetConfiguration = { data, nixpkgs, hosts, ... }@allConfig: let + hostNames = nixpkgs.lib.attrNames hosts; config = builtins.removeAttrs allConfig [ "nixpkgs" "data" ]; fleetLib = import ./fleetLib.nix { - inherit nixpkgs hosts; + inherit nixpkgs hostNames; }; in - nixpkgs.lib.genAttrs flake-utils.lib.defaultSystems (system: rec { - root = nixpkgs.lib.evalModules { - modules = (import ../modules/fleet/_modules.nix) ++ [ config data ]; - specialArgs = { - inherit nixpkgs; - fleet = fleetLib; + nixpkgs.lib.genAttrs flake-utils.lib.defaultSystems (system: + let + root = nixpkgs.lib.evalModules { + modules = (import ../modules/fleet/_modules.nix) ++ [ config data ]; + specialArgs = { + inherit nixpkgs fleetLib; + }; }; - }; - configuredHosts = root.config.hosts; - configuredSecrets = root.config.secrets; - configuredSystems = nixpkgs.lib.listToAttrs ( - map - ( - name: { - inherit name; - value = nixpkgs.lib.nixosSystem { - system = configuredHosts.${name}.system; - modules = configuredHosts.${name}.modules ++ ( - if configuredHosts.${name}.system == "aarch64-linux" then [ (nixpkgs + "/nixos/modules/installer/sd-card/sd-image-aarch64-installer.nix") ] - else [ ] - ) ++ [ - ({ ... }: { - nixpkgs.system = system; - nixpkgs.localSystem.system = system; - nixpkgs.crossSystem = if system == configuredHosts.${name}.system then null else { - system = configuredHosts.${name}.system; - }; - }) - ]; - specialArgs = { - fleet = fleetLib.hostsToAttrs (host: configuredSystems.${host}.config); + failedAssertions = map (x: x.message) (nixpkgs.lib.filter (x: !x.assertion) root.config.assertions); + rootAssertWarn = + if failedAssertions != [ ] + then throw "Failed assertions:\n${nixpkgs.lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" + else nixpkgs.lib.showWarnings root.config.warnings root; + in + rec { + configuredHosts = rootAssertWarn.config.hosts; + configuredSecrets = rootAssertWarn.config.secrets; + configuredSystems = nixpkgs.lib.listToAttrs ( + map + ( + name: { + inherit name; + value = nixpkgs.lib.nixosSystem { + system = configuredHosts.${name}.system; + modules = configuredHosts.${name}.modules ++ ( + if configuredHosts.${name}.system == "aarch64-linux" then [ (nixpkgs + "/nixos/modules/installer/sd-card/sd-image-aarch64-installer.nix") ] + else [ ] + ) ++ [ + ({ ... }: { + nixpkgs.system = system; + nixpkgs.localSystem.system = system; + nixpkgs.crossSystem = if system == configuredHosts.${name}.system then null else { + system = configuredHosts.${name}.system; + }; + }) + ]; + specialArgs = { + inherit fleetLib; + fleet = fleetLib.hostsToAttrs (host: configuredSystems.${host}.config); + }; }; - }; - } - ) - (builtins.attrNames root.config.hosts) - ); #nixpkgs.lib.nixosSystem {} - }); + } + ) + (builtins.attrNames rootAssertWarn.config.hosts) + ); #nixpkgs.lib.nixosSystem {} + }); } --- a/lib/fleetLib.nix +++ b/lib/fleetLib.nix @@ -1,7 +1,5 @@ # Shared functions for fleet configuration, available as `fleet` module argument -{ nixpkgs, hosts }: with nixpkgs.lib; rec { - # Modules can't register hosts because of infinite recursion - hostNames = attrNames hosts; +{ nixpkgs, hostNames }: with nixpkgs.lib; rec { hostsToAttrs = f: listToAttrs ( map (name: { inherit name; value = f name; }) hostNames ); @@ -25,4 +23,7 @@ a = elemAt sorted 0; b = elemAt sorted 1; }; + hostPairName = this: other: + if this < other then "${this}-${other}" + else "${other}-${this}"; } --- a/modules/fleet/_modules.nix +++ b/modules/fleet/_modules.nix @@ -1,4 +1,5 @@ [ + ./assertions.nix ./meta.nix ./secrets.nix ] --- /dev/null +++ b/modules/fleet/assertions.nix @@ -0,0 +1,34 @@ +{ lib, ... }: + +with lib; + +{ + + options = { + + assertions = mkOption { + type = types.listOf types.unspecified; + internal = true; + default = [ ]; + example = [{ assertion = false; message = "you can't enable this for that reason"; }]; + description = '' + This option allows modules to express conditions that must + hold for the evaluation of the system configuration to + succeed, along with associated error messages for the user. + ''; + }; + + warnings = mkOption { + internal = true; + default = [ ]; + type = types.listOf types.str; + example = [ "The `foo' service is deprecated and will go away soon!" ]; + description = '' + This option allows modules to show warnings to users during + the evaluation of the system configuration. + ''; + }; + + }; + # impl of assertions is in +} --- a/modules/fleet/meta.nix +++ b/modules/fleet/meta.nix @@ -1,4 +1,4 @@ -{ lib, fleet, config, ... }: with lib; +{ lib, fleetLib, config, ... }: with lib; let host = with types; { options = { @@ -42,7 +42,7 @@ }; }; config = { - hosts = fleet.hostsToAttrs (host: { + hosts = fleetLib.hostsToAttrs (host: { modules = config.globalModules; }); globalModules = import ../../nixos/modules/module-list.nix; --- a/modules/fleet/secrets.nix +++ b/modules/fleet/secrets.nix @@ -1,14 +1,23 @@ -{ lib, fleet, config, ... }: with lib; +{ lib, fleetLib, config, ... }: with lib; with fleetLib; let sharedSecret = with types; { options = { owners = mkOption { type = listOf str; description = '' + For which owners this secret is currently encrypted, + if not matches expectedOwners - then this secret is considered outdated, and + should be regenerated/reencrypted + ''; + }; + expectedOwners = mkOption { + type = listOf str; + description = '' List of hosts to encrypt secret for Secrets would be decrypted and stored to /run/secrets/$\{name} on owners ''; + default = [ ]; }; generator = mkOption { type = package; @@ -67,7 +76,13 @@ description = "Host secrets"; }; }; - config = with fleet; { + config = { + assertions = mapAttrsToList + (name: secret: { + assertion = builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners; + message = "Shared secret ${name} is expected to be encrypted for ${builtins.toJSON secret.expectedOwners}, but it is encrypted for ${builtins.toJSON secret.owners}"; + }) + config.sharedSecrets; hosts = hostsToAttrs (host: { modules = let -- gitstuff