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

setting owner and group seems not to work for ids #514

Open
mrVanDalo opened this issue Mar 16, 2024 · 10 comments
Open

setting owner and group seems not to work for ids #514

mrVanDalo opened this issue Mar 16, 2024 · 10 comments

Comments

@mrVanDalo
Copy link

It seems I can't use predefined uids and gids. Here is my example.

  systemd.services."container@matrix-ingolf-wagner".unitConfig.ConditionPathExists = config.sops.secrets.matrix_shared_secret.path;
  sops.secrets.matrix_shared_secret.owner = toString config.ids.uids.matrix-synapse;
  sops.secrets.matrix_shared_secret.group = toString config.ids.gids.matrix-synapse;

Doing this I get the following error:

setting up /etc...
/nix/store/wizswcp7lwr4hpdrbw8jnamqa0k643wn-sops-install-secrets-0.0.1/bin/sops-install-secrets: Manifest is not valid: Failed to lookup user '224': user: unknown user 224
Activation script snippet 'setupSecrets' failed (1)
reloading user units for root...
setting up tmpfiles
warning: error(s) occurred while switching to the new configuration
@mrVanDalo
Copy link
Author

My current workaround is:

  systemd.services."container@matrix-ingolf-wagner".unitConfig.ConditionPathExists = config.sops.secrets.matrix_shared_secret.path;
  sops.secrets.matrix_shared_secret.owner = "matrix-synapse";

  users.users.matrix-synapse = {
    isSystemUser = true;
    uid = config.ids.uids.matrix-synapse;
    group = "matrix-synapse";
  };
  users.groups.matrix-synapse.gid = config.ids.gids.matrix-synapse;

But it's a bit strange that I have to create the users, because sops is not capable of handling ids (the documentation says it does)

@Mic92
Copy link
Owner

Mic92 commented Mar 16, 2024

Yeah, looks like this works for usernames only: https://pkg.go.dev/os/user#Lookup

@clamydo
Copy link

clamydo commented Mar 31, 2024

I've stumbled over this with a different use case: I have a systemd-nspawn container via containers module and bind-mount a secret into it. In order to get the access right, I have to use the uid of the user inside the container. Something like that:

  sops.secrets."my/secret" = {
    #### THIS DOES NOT WORK
    owner = config.containers.testvm1.config.users.users.turnserver.uid;
  };

  containers.testvm1 = let mysecret = config.sops.secrets."my/secret".path;
  in {
    autoStart = true;
    bindMounts.${mysecret}.isReadOnly = true;

    config = {
      system.stateVersion = "23.11";

      services.coturn = {
        enable = true;
        realm = "example.com";

        static-auth-secret-file = mysecret;
        use-auth-secret = true;
      };
    };

  };

I am unsure how to proceed, without the ability to set a uid.


Update: For better or worse I have found a workaround by copying secrets into the container and setting permissions there:

  sops.secrets."my/secret" = { };

  containers.testvm1 = let mysecret = config.sops.secrets."my/secret".path;
  in {
    autoStart = true;

    config = {
      system.stateVersion = "23.11";

      environment.etc."secret_coturn" = {
        source = mysecret;
        mode = "0400";
        user = config.users.users.turnserver.name;
      };

      services.coturn = {
        enable = true;
        realm = "example.com";

        static-auth-secret-file = "/etc/secret_coturn";
        use-auth-secret = true;
      };
    };

  };

@Mic92
Copy link
Owner

Mic92 commented Apr 1, 2024

For systemd-nspawn it might be also interesting to use the --set-credential flag to first load secrets into the container and than have the container load them from the system credential directory: https://systemd.io/CREDENTIALS/

@Mic92
Copy link
Owner

Mic92 commented Apr 1, 2024

When LoadCredential is used for a service than the service can read the secret always from /run/credentials/${serviceName}.service/${name}. Maybe this could be some sort of module for systemd-nspawn to make it a bit more convenient. This way you also don't have to deal with UIDs at all.

@clamydo
Copy link

clamydo commented Apr 4, 2024

Are you suggesting to pass the encrypted secret via --set-credential? If yes, then I would probably need to bind-mount the private host-sshd-key (or whatever else was used) and setup sops-nix inside the container in order to decrypt it? Not sure how I feel about passing the private key down to the container, but could work.

If you suggesting to pass the unencrypted secret string this way, I think this is a bad idea. First, it might end up in the nix store as part of the derivation. Second, from the systemd.exec(5) manpage:

Do not use this option for data that is supposed to be secret, as it is accessible to unprivileged processes via IPC. It's only safe to use this for user IDs, public key material and similar non-sensitive data. For everything else use LoadCredential=.

So, rather --load-credential should probably used in any case.

So I gather, something like this could work? Haven't tested it completely, though. At least I am relatively sure, this way no secrets end up in the nix store. I am however not sure, how the permissions work and how well the secret for one service is kept hidden from other services or processes in the container.

  containers.test = {
    autoStart = true;

    extraFlags = [
      "--load-credential=examplekey:${config.sops.secrets.example_key.path}"
    ];

    config = {
      system.stateVersion = "23.11";
      systemd.services.foobar = {
        enable = true;
        script = ''
          cat $CREDENTIALS_DIRECTORY/examplekeypropageted
        '';
        serviceConfig = {
          LoadCredential =
            "examplekeypropageted:examplekey";
        };
        wantedBy = [ "multi-user.target" ];
      };
    };
  };

@clamydo
Copy link

clamydo commented Apr 4, 2024

I've checked, it works this way and the secret is also protected inside the container. Thanks for the suggestion @Mic92

Here is MWE https://gist.github.com/clamydo/9691c48552efcd6d338407d58c900a4a

@dkowis
Copy link

dkowis commented Apr 22, 2024

I'm using arion, to translate a docker compose into a nice pretty nix config, and bind mounting in the secrets seems like the best way to do the things.

I needed to specify the gid/uid of the secret for the one that's inside the container as well, and there's no way that I could find to set it to be actually a gid.

If I could just tell it to be a specific GID/UID this would go away, and might even be valid if you're doing weird NFS things.

Could there perhaps be a way to use a different setting that would explicitly set the uid/gid to a number?

@TheCataliasTNT2k
Copy link

Yeah, looks like this works for usernames only: https://pkg.go.dev/os/user#Lookup

What about doing the following:

  • If "name" is given, lookup the name
  • If "id" is given lookup the id
    • If "require_existing" is false (defaults to true), accept non-existing ids

This would allow all scenarios...

@Mic92
Copy link
Owner

Mic92 commented Jul 14, 2024

Sounds good. PRs are welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants