]> git.immae.eu Git - perso/Immae/Config/Nix.git/blobdiff - flakes/secrets/flake.nix
Squash changes containing private information
[perso/Immae/Config/Nix.git] / flakes / secrets / flake.nix
index ef74a30244f49ee28465ad0663312cbfedd6ca08..7bf04a4517fb2ed4f839ff56d14526294d9fbfcf 100644 (file)
@@ -3,6 +3,8 @@
 
   outputs = { self }: {
     nixosModule = { config, lib, pkgs, ... }: {
+      # Necessary for situations where flake gets included multiple times
+      key = builtins.hashString "sha256" (builtins.path { path = self.sourceInfo.outPath; name = "source"; });
       options.secrets = with lib; {
         keys = mkOption {
           type = types.attrsOf (types.submodule {
                 type = types.str;
                 description = "Content of the entry";
               };
+              keyDependencies = mkOption {
+                default = [];
+                type = types.listOf (types.either types.path types.package);
+                description = ''
+                  (public) system dependencies that needs to be
+                  uploaded with the key.
+
+                  keyDependencies + ignoredKeyDependencies should
+                  contain the exhaustive list of the text context.
+
+                  A warning will be thrown if there are remaning
+                  dependencies from the text.
+                '';
+              };
+              ignoredKeyDependencies = mkOption {
+                default = [];
+                type = types.listOf (types.either types.path types.package);
+                description = ''
+                  dependencies that must not be sent along with the key.
+
+                  keyDependencies + ignoredKeyDependencies should
+                  contain the exhaustive list of the text context.
+
+                  A warning will be thrown if there are remaning
+                  dependencies from the text.
+                '';
+              };
             };
           });
           default = {};
           description = "Keys attrs to upload to the server";
-          apply = lib.mapAttrsToList (dest: v: v // { inherit dest; });
+          apply = builtins.mapAttrs (dest: v: v // { inherit dest; });
         };
         gpgKeys = mkOption {
           type = types.listOf types.path;
         # Read-only variables
         fullPaths = mkOption {
           type = types.attrsOf types.path;
-          default = builtins.listToAttrs
-            (map (v: { name = v.dest; value = "${config.secrets.location}/${v.dest}"; }) config.secrets.keys);
+          default = builtins.mapAttrs
+            (n: v: "${config.secrets.location}/${n}") config.secrets.keys;
           readOnly = true;
           description = "set of full paths to secrets";
         };
 
       config = let
         location = config.secrets.location;
-        keys = config.secrets.keys;
+        keys = builtins.attrValues config.secrets.keys;
         empty = pkgs.runCommand "empty" { preferLocalBuild = true; } "mkdir -p $out && touch $out/done";
         fpath = v: "secrets/${v.dest}${lib.optionalString v.isTemplated ".gucci.tpl"}";
         dumpKey = v:
             exclPath = builtins.concatStringsSep " -o " (map (d: " -path $TMP/${d.dest}") dirs);
           in
             lib.optionalString (builtins.length dirs > 0) " -not \\( ${exclPath} \\) ";
+
+        checkKeyDependencies = key:
+          let
+            allDeps = builtins.map (n: if builtins.isPath n then "${n}" else n.drvPath) (key.keyDependencies ++ key.ignoredKeyDependencies);
+            context = builtins.attrNames (builtins.getContext key.text);
+            missing = builtins.foldl' (o: n: lib.remove n o) context allDeps;
+          in
+            lib.optional (!key.isDir && builtins.length missing > 0)
+              ''
+                Key ${key.dest} has non declared dependencies in its context: ${builtins.concatStringsSep " " missing}
+                Add them to ignoredKeyDependencies to ignore
+              '';
       in lib.mkIf (builtins.length keys > 0) {
+        warnings = lib.concatMap checkKeyDependencies keys;
+        # FIXME: Use lib.concatMap (k: k.keyDependencies) keys in latest nixpkgs
+        system.extraDependencies = lib.concatMap (k: builtins.map (dep:
+          if builtins.isPath dep then pkgs.writeText "extra-dep" "${dep}" else dep
+        ) k.keyDependencies) keys;
         system.activationScripts.secrets = {
           deps = [ "users" "wrappers" ];
           text = ''
             TMP=$(${pkgs.coreutils}/bin/mktemp -d)
             TMPWORK=$(${pkgs.coreutils}/bin/mktemp -d)
             chmod go-rwx $TMPWORK
-            if [ -n "$TMP" -a -n "$TMPWORK" ]; then
+            if [ -n "$TMP" -a -n "$TMPWORK" -a -f ${config.secrets.secretsVars} ]; then
               install -m0750 -o root -g keys -d $TMP
               ${pkgs.ssh-to-age}/bin/ssh-to-age -private-key -i ${config.secrets.decryptKey} -o $TMPWORK/keys.txt
               SOPS_AGE_KEY_FILE=$TMPWORK/keys.txt ${pkgs.sops}/bin/sops -d ${secrets} | ${pkgs.gnutar}/bin/tar --strip-components 1 -C $TMP -x
-              if [ -f ${config.secrets.secretsVars} ]; then
-                SOPS_AGE_KEY_FILE=$TMPWORK/keys.txt ${pkgs.sops}/bin/sops -d ${config.secrets.secretsVars} > $TMPWORK/vars.yml
-              fi
+              SOPS_AGE_KEY_FILE=$TMPWORK/keys.txt ${pkgs.sops}/bin/sops -d ${config.secrets.secretsVars} > $TMPWORK/vars.yml
               if [ -f $TMPWORK/vars.yml ]; then
                 find $TMP -name "*.gucci.tpl" -exec \
                   /bin/sh -c 'f="{}"; ${pkgs.gucci}/bin/gucci -f '$TMPWORK'/vars.yml "$f" > "''${f%.gucci.tpl}"; touch --reference "$f" ''${f%.gucci.tpl} ; chmod --reference="$f" ''${f%.gucci.tpl} ; chown --reference="$f" ''${f%.gucci.tpl}' \;