Open mrVanDalo opened 7 months ago
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)
Yeah, looks like this works for usernames only: https://pkg.go.dev/os/user#Lookup
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;
};
};
};
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/
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.
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" ];
};
};
};
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
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?
Yeah, looks like this works for usernames only: https://pkg.go.dev/os/user#Lookup
What about doing the following:
This would allow all scenarios...
Sounds good. PRs are welcome.
It seems I can't use predefined uids and gids. Here is my example.
Doing this I get the following error: