Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use nix-sops #81

Open
snylonue opened this issue Apr 10, 2024 · 9 comments
Open

Unable to use nix-sops #81

snylonue opened this issue Apr 10, 2024 · 9 comments
Labels
bug Something isn't working

Comments

@snylonue
Copy link

snylonue commented Apr 10, 2024

Describe the bug

I'm trying to use nix-sops to handle some secrets, but I can't make it.

To Reproduce

  1. In flake.nix
systemConfigs =
      let makeSystemConfig = inputs.system-manager.lib.makeSystemConfig;
      in {
        "minami" = makeSystemConfig {
          modules = [ ./system/minami inputs.sops-nix.nixosModules.sops ];
          extraSpecialArgs = { inherit inputs; };
        };
      };

In system/minami/default.nix

{
  imports = [ ./other-modules ];

  sops = {
    age.sshKeyPaths = [ "/etc/ssh/nix-sops" ];
    secrets = {
      secret = {
        sopsFile = ./secrets/secret.json;
        format = "json";
      };
    };
  };
  config = {
    nixpkgs.hostPlatform = "x86_64-linux";
    # other config
  };
}

nix repl --extra-experimental-features 'flakes repl-flake' flake.nix --show-trace

nix-repl> systemConfigs.minami
error:
       … while evaluating the attribute 'minami'

         at /nix/store/n2xvix786b3v8sni332pikjq3j8r3ygw-source/flake.nix:89:9:

           88|           makeSystemConfig { modules = [ ./system/marushiru.nix ]; };
           89|         "minami" = makeSystemConfig {
             |         ^
           90|           modules = [ ./system/minami inputs.sops-nix.nixosModules.sops ];

       … from call site

         at /nix/store/n2xvix786b3v8sni332pikjq3j8r3ygw-source/flake.nix:89:20:

           88|           makeSystemConfig { modules = [ ./system/marushiru.nix ]; };
           89|         "minami" = makeSystemConfig {
             |                    ^
           90|           modules = [ ./system/minami inputs.sops-nix.nixosModules.sops ];

       … while calling 'makeSystemConfig'

         at /nix/store/ncibdc9d87f9ysfvjkaiqpmwxgiayl05-source/nix/lib.nix:17:5:

           16|   makeSystemConfig =
           17|     { modules
             |     ^
           18|     , extraSpecialArgs ? { }

       … from call site

         at /nix/store/ncibdc9d87f9ysfvjkaiqpmwxgiayl05-source/nix/lib.nix:92:5:

           91|     in
           92|     returnIfNoAssertions toplevel;
             |     ^
           93|

       … while calling 'returnIfNoAssertions'

         at /nix/store/ncibdc9d87f9ysfvjkaiqpmwxgiayl05-source/nix/lib.nix:46:30:

           45|
           46|       returnIfNoAssertions = drv:
             |                              ^
           47|         let

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:242:28:

          241|           # For definitions that have an associated option
          242|           declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
             |                            ^
          243|

       … while calling 'mapAttrsRecursiveCond'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/attrsets.nix:1167:5:

         1166|     f:
         1167|     set:
             |     ^
         1168|     let

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:234:33:

          233|           ({ inherit lib options config specialArgs; } // specialArgs);
          234|         in mergeModules prefix (reverseList collected);
             |                                 ^
          235|

       … while calling 'reverseList'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/lists.nix:1068:17:

         1067|   */
         1068|   reverseList = xs:
             |                 ^
         1069|     let l = length xs; in genList (n: elemAt xs (l - n - 1)) l;

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:229:25:

          228|       merged =
          229|         let collected = collectModules
             |                         ^
          230|           class

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:445:37:

          444|
          445|     in modulesPath: initialModules: args:
             |                                     ^
          446|       filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:446:7:

          445|     in modulesPath: initialModules: args:
          446|       filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
             |       ^
          447|

       … while calling 'filterModules'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:413:36:

          412|       # modules recursively. It returns the final list of unique-by-key modules
          413|       filterModules = modulesPath: { disabled, modules }:
             |                                    ^
          414|         let

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:439:31:

          438|           disabledKeys = concatMap ({ file, disabled }: map (moduleKey file) disabled) disabled;
          439|           keyFilter = filter (attrs: ! elem attrs.key disabledKeys);
             |                               ^
          440|         in map (attrs: attrs.module) (builtins.genericClosure {

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:400:22:

          399|           let
          400|             module = checkModule (loadModule args parentFile "${parentKey}:anon-${toString n}" x);
             |                      ^
          401|             collectedImports = collectStructuredModules module._file module.key module.imports args;

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:365:11:

          364|         else
          365|           m: m;
             |           ^
          366|

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:400:35:

          399|           let
          400|             module = checkModule (loadModule args parentFile "${parentKey}:anon-${toString n}" x);
             |                                   ^
          401|             collectedImports = collectStructuredModules module._file module.key module.imports args;

       … while calling 'loadModule'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:336:53:

          335|       # Like unifyModuleSyntax, but also imports paths and calls functions if necessary
          336|       loadModule = args: fallbackFile: fallbackKey: m:
             |                                                     ^
          337|         if isFunction m then

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:354:14:

          353|           throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"
          354|         else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);
             |              ^
          355|

       … while calling 'unifyModuleSyntax'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:454:34:

          453|      of ‘options’, ‘config’ and ‘imports’ attributes. */
          454|   unifyModuleSyntax = file: key: m:
             |                                  ^
          455|     let

       error: Module `/nix/store/n2xvix786b3v8sni332pikjq3j8r3ygw-source/system/minami' has an unsupported attribute `sops'. This is caused by introducing a top-level `config' or `options' attribute. Add configuration attributes immediately on the top level instead, or move all of them (namely: sops) into the explicit `config' attribute.

Expected behavior

The configure can be built normally.

System information

latest system-manager and nix-sops

Ubuntu 22.04

Additional context

It seems that system-manager cannot use nixos modules. I'm wondering if the home-manager module can be used.

@snylonue snylonue added the bug Something isn't working label Apr 10, 2024
@r-vdp
Copy link
Member

r-vdp commented Apr 10, 2024

No you should use the NixOS module, not the HM module.

From the error, I have a suspicion that you didn't share your full config, because that error is a generic one from the module system that you get when you put attributes in the top-level module scope together with an explicit options or config attribute.

Do you by any chance have something like this?

{
  sops = { ... };

  config = { ... };
}

In that case you'd need to move the sops part inside config.
If you introduce an options attribute, you also need to put the actual config inside config.

That being said, I didn't test sops-nix with system-manager, so I'm not sure if it works.

@snylonue
Copy link
Author

No you should use the NixOS module, not the HM module.

From the error, I have a suspicion that you didn't share your full config, because that error is a generic one from the module system that you get when you put attributes in the top-level module scope together with an explicit options or config attribute.

Do you by any chance have something like this?

{
  sops = { ... };

  config = { ... };
}

In that case you'd need to move the sops part inside config. If you introduce an options attribute, you also need to put the actual config inside config.

That being said, I didn't test sops-nix with system-manager, so I'm not sure if it works.

Yes, I didn't upload the full config. I would upload a minimum reproduction if needed.

However, there are still errors if I move sops options into config, or even I import sops nixos module only. I will upload such error messages later since they may contain some more helpful information.

@snylonue
Copy link
Author

{
  imports = [ ./../../modules/system/xray.nix ];

  config = {
    nixpkgs.hostPlatform = "x86_64-linux";

    sops = {
      age.sshKeyPaths = [ "/etc/ssh/nix-sops" ];
      secrets = {
        secret = {
          sopsFile = ./secrets/secret.json;
          format = "json";
        };
      };
    };
  # other config

  };
}

After moving sops into config, I got:

error:
       … while evaluating the attribute 'minami'

         at /nix/store/jc7jknyri77nx3giz3rzzbxdflsrl1mj-source/flake.nix:89:9:

           88|           makeSystemConfig { modules = [ ./system/marushiru.nix ]; };
           89|         "minami" = makeSystemConfig {
             |         ^
           90|           modules = [ ./system/minami inputs.sops-nix.nixosModules.sops ];

       … from call site

         at /nix/store/jc7jknyri77nx3giz3rzzbxdflsrl1mj-source/flake.nix:89:20:

           88|           makeSystemConfig { modules = [ ./system/marushiru.nix ]; };
           89|         "minami" = makeSystemConfig {
             |                    ^
           90|           modules = [ ./system/minami inputs.sops-nix.nixosModules.sops ];

       … while calling 'makeSystemConfig'

         at /nix/store/ncibdc9d87f9ysfvjkaiqpmwxgiayl05-source/nix/lib.nix:17:5:

           16|   makeSystemConfig =
           17|     { modules
             |     ^
           18|     , extraSpecialArgs ? { }

       … from call site

         at /nix/store/ncibdc9d87f9ysfvjkaiqpmwxgiayl05-source/nix/lib.nix:92:5:

           91|     in
           92|     returnIfNoAssertions toplevel;
             |     ^
           93|

       … while calling 'returnIfNoAssertions'

         at /nix/store/ncibdc9d87f9ysfvjkaiqpmwxgiayl05-source/nix/lib.nix:46:30:

           45|
           46|       returnIfNoAssertions = drv:
             |                              ^
           47|         let

       … while evaluating the error message for definitions for `system', which is an option that does not exist

       … while evaluating a definition from `/nix/store/jslmnzssy01r4pighp0mnhp9dd5yk2w9-source/modules/sops/secrets-for-users'

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/modules.nix:272:25:

          271|                       "while evaluating a definition from `${firstDef.file}'"
          272|                       ( showDefs [ firstDef ])
             |                         ^
          273|                     );

       … while calling 'showDefs'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/options.nix:445:14:

          444|
          445|   showDefs = defs: concatMapStrings (def:
             |              ^
          446|     let

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/options.nix:445:20:

          444|
          445|   showDefs = defs: concatMapStrings (def:
             |                    ^
          446|     let

       … while calling 'concatMapStrings'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/strings.nix:60:25:

           59|   */
           60|   concatMapStrings = f: list: concatStrings (map f list);
             |                         ^
           61|

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/options.nix:445:38:

          444|
          445|   showDefs = defs: concatMapStrings (def:
             |                                      ^
          446|     let

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/options.nix:449:10:

          448|       prettyEval = builtins.tryEval
          449|         (lib.generators.toPretty { }
             |          ^
          450|           (lib.generators.withRecursion { depthLimit = 10; throwOnDepthLimit = false; } def.value));

       … while calling 'go'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:343:18:

          342|     let
          343|     go = indent: v:
             |                  ^
          344|     let     introSpace = if multiline then "\n${indent}  " else " ";

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/attrsets.nix:1062:10:

         1061|     attrs:
         1062|     map (name: f name attrs.${name}) (attrNames attrs);
             |          ^
         1063|

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/attrsets.nix:1062:16:

         1061|     attrs:
         1062|     map (name: f name attrs.${name}) (attrNames attrs);
             |                ^
         1063|

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:391:22:

          390|           + concatStringsSep introSpace (mapAttrsToList
          391|               (name: value:
             |                      ^
          392|                 "${escapeNixIdentifier name} = ${

       … while evaluating an attribute `activationScripts`

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:394:22:

          393|                   addErrorContext "while evaluating an attribute `${name}`"
          394|                     (go (indent + "  ") value)
             |                      ^
          395|                 };") v)

       … while calling 'go'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:343:18:

          342|     let
          343|     go = indent: v:
             |                  ^
          344|     let     introSpace = if multiline then "\n${indent}  " else " ";

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/attrsets.nix:1062:10:

         1061|     attrs:
         1062|     map (name: f name attrs.${name}) (attrNames attrs);
             |          ^
         1063|

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/attrsets.nix:1062:16:

         1061|     attrs:
         1062|     map (name: f name attrs.${name}) (attrNames attrs);
             |                ^
         1063|

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:391:22:

          390|           + concatStringsSep introSpace (mapAttrsToList
          391|               (name: value:
             |                      ^
          392|                 "${escapeNixIdentifier name} = ${

       … while evaluating an attribute `content`

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:394:22:

          393|                   addErrorContext "while evaluating an attribute `${name}`"
          394|                     (go (indent + "  ") value)
             |                      ^
          395|                 };") v)

       … while calling 'go'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:343:18:

          342|     let
          343|     go = indent: v:
             |                  ^
          344|     let     introSpace = if multiline then "\n${indent}  " else " ";

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/attrsets.nix:1062:10:

         1061|     attrs:
         1062|     map (name: f name attrs.${name}) (attrNames attrs);
             |          ^
         1063|

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/attrsets.nix:1062:16:

         1061|     attrs:
         1062|     map (name: f name attrs.${name}) (attrNames attrs);
             |                ^
         1063|

       … while calling anonymous lambda

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:391:22:

          390|           + concatStringsSep introSpace (mapAttrsToList
          391|               (name: value:
             |                      ^
          392|                 "${escapeNixIdentifier name} = ${

       … while evaluating an attribute `setupSecretsForUsers`

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:394:22:

          393|                   addErrorContext "while evaluating an attribute `${name}`"
          394|                     (go (indent + "  ") value)
             |                      ^
          395|                 };") v)

       … while calling 'go'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:343:18:

          342|     let
          343|     go = indent: v:
             |                  ^
          344|     let     introSpace = if multiline then "\n${indent}  " else " ";

       … while calling 'evalNext'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:318:24:

          317|           let
          318|             evalNext = x: mapAny (depth + 1) (transform (depth + 1) x);
             |                        ^
          319|           in

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:318:27:

          317|           let
          318|             evalNext = x: mapAny (depth + 1) (transform (depth + 1) x);
             |                           ^
          319|           in

       … while calling 'mapAny'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:316:25:

          315|           else id;
          316|         mapAny = depth: v:
             |                         ^
          317|           let

       … from call site

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/generators.nix:318:47:

          317|           let
          318|             evalNext = x: mapAny (depth + 1) (transform (depth + 1) x);
             |                                               ^
          319|           in

       … while calling 'id'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/trivial.nix:36:8:

           35|   */
           36|   id = x: x;
             |        ^
           37|

       … from call site

         at /nix/store/jslmnzssy01r4pighp0mnhp9dd5yk2w9-source/modules/sops/secrets-for-users/default.nix:36:11:

           35|       ${withEnvironment "${cfg.package}/bin/sops-install-secrets -ignore-passwd ${manifestForUsers}"}
           36|     '' // lib.optionalAttrs (config.system ? dryActivationScript) {
             |           ^
           37|       supportsDryActivation = true;

       … while calling 'optionalAttrs'

         at /nix/store/j10523yhkcc34478azkgcl70yzcx6j2j-source/lib/attrsets.nix:1318:5:

         1317|     cond:
         1318|     as:
             |     ^
         1319|     if cond then as else {};

       error: attribute 'system' missing

       at /nix/store/jslmnzssy01r4pighp0mnhp9dd5yk2w9-source/modules/sops/secrets-for-users/default.nix:36:30:

           35|       ${withEnvironment "${cfg.package}/bin/sops-install-secrets -ignore-passwd ${manifestForUsers}"}
           36|     '' // lib.optionalAttrs (config.system ? dryActivationScript) {
             |                              ^
           37|       supportsDryActivation = true;
       Did you mean systemd?

@r-vdp
Copy link
Member

r-vdp commented Apr 10, 2024

Right, you'd need to add system as an option in

options =
# We need to ignore a bunch of options that are used in NixOS modules but
# that don't apply to system-manager configs.
# TODO: can we print an informational message for things like kernel modules
# to inform users that they need to be enabled in the host system?
{
boot = lib.mkOption {
type = lib.types.raw;
};
};

@snylonue
Copy link
Author

  options = {
    system = lib.mkOption { type = lib.types.raw; };

    services.openssh = {
      enable = lib.mkOption {
        type = lib.types.bool;
        default = false;
      };
    };
  };

I managed to make it work after adding such options. However, the secret file couldn't be read at runtime (and there is no /run/secrets).

@snylonue
Copy link
Author

It seems that system-manager needs to handle system.activationScripts

https://github.com/Mic92/sops-nix/blob/538c114cfdf1f0458f507087b1dcf018ce1c0c4c/modules/sops/default.nix#L331-L347

@r-vdp
Copy link
Member

r-vdp commented Apr 13, 2024

It seems that system-manager needs to handle system.activationScripts

https://github.com/Mic92/sops-nix/blob/538c114cfdf1f0458f507087b1dcf018ce1c0c4c/modules/sops/default.nix#L331-L347

A better solution would be for sops to decrypt secrets through a systemd service instead of an activation script, which is the general direction in which things are going anyway, with systemd initrd and such.

@aanderse
Copy link
Contributor

relevant: Mic92/sops-nix#39

@snylonue
Copy link
Author

relevant: Mic92/sops-nix#39

But the pr has been opened for 3 years. Could we do something now?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants