SSH deploy keys
Would be great to have SSH deploy key support:
- https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys#deploy-keys
GitLab and Forgejo support this too.
I would find this very useful.
Something simple like exposing the GIT_SSH_COMMAND of the service would make this possible.
this already works if you add
systemd = {
services = {
comin = {
environment = {
GIT_SSH_COMMAND = "${pkgs.openssh}/bin/ssh -i <path to key>";
};
};
};
};
@Arbel-arad I just tried this ... but I am getting
level=error msg="Pull from remote 'origin' failed: authentication required"
systemctl show -p Environment comin
Environment="GIT_SSH_COMMAND=/nix/store/i0nlz4mcyxzxd96x5dv0zcy23z6xkvzy-openssh-10.0p2/bin/ssh -i /run/secrets/comin"
ls -la /run/secrets/comin
-r-------- 1 root root 399 May 18 15:50 /run/secrets/comin
If this works for you - what is different for you?
@tcurdt most likely the systemd service is not seeing keys in /run
i am using host keys that are normal files and they work.
Environment="GIT_SSH_COMMAND=/nix/store/0xh3cvypx00csnmz1b0xzy0vhsgapw3k-openssh-10.0p2/bin/ssh -i /etc/ssh/ssh_host_ed25519_key"
maybe try adding the secret path as a BindReadOnlyPaths directive in the service?
I had to walk away from the computer to realize: you better use the git url - not the https one 🙄
But unfortunately it's still not working for me:
May 18 13:51:22 utm-arm comin[113128]: time="2025-05-18T13:51:22Z" level=error msg="Pull from remote 'origin' failed: error creating SSH agent: \"SSH agent requested but SSH_AUTH_SOCK not-specified\""
Even after specifying it like this
systemd = {
services = {
comin = {
environment = {
GIT_SSH_COMMAND = "${pkgs.openssh}/bin/ssh -i /run/secrets/comin -o IdentitiesOnly=yes -o ForwardAgent=no";
};
};
};
};
services.comin = {
enable = true;
flakeSubdirectory = "nix";
debug = true;
remotes = [
{
name = "origin";
url = "[email protected]:foo/bar.git";
poller.period = 10;
}
];
};
When I run this manually it works:
GIT_SSH_COMMAND="ssh -i /run/secrets/comin -o IdentitiesOnly=yes -o ForwardAgent=no" git clone [email protected]:foo/bar.git
I tested with both, the secrets mount and a key in /etc/ssh. So that does not seem to make a difference.
I somehow have the feeling that the GIT_SSH_COMMAND is not being passed on for me - for some reason.
Which version are you using, @Arbel-arad ? Also 0.6.0?
Seems like comin uses a go git implementation.
And it seems like that one is not aware of GIT_SSH_COMMAND
https://github.com/search?q=repo%3Ago-git%2Fgo-git%20GIT_SSH_COMMAND&type=code https://github.com/go-git/go-git/discussions/1207#discussioncomment-10973201
So I am confused how this is working for you? 🤔
Seems like
cominuses a go git implementation. And it seems like that one is not aware ofGIT_SSH_COMMANDhttps://github.com/search?q=repo%3Ago-git%2Fgo-git%20GIT_SSH_COMMAND&type=code https://github.com/go-git/go-git/discussions/1207#discussioncomment-10973201
So I am confused how this is working for you? 🤔
i see the issue now... what i did was only using SSH for specific flake inputs that are secret, which works since that pulls through nix, but the cloning comin does ignores the SSH command
good catch but i'm not sure how to fix this...
good catch but i'm not sure how to fix this...
It seems go-git does support ssh keys.
I suspect the easiest would be implement native comin support for it.
https://github.com/go-git/go-git/blob/main/_examples/clone/auth/ssh/private_key/main.go
Along the lines of:
remotes = [
{
name = "origin";
url = "[email protected]:foo/bar.git";
auth.ssh_private_key_path = config.sops.secrets.comin.path;
poller.period = 10;
}
];
At least on the first glance that doesn't look too hard to add.
I guess @nlewo needs to weigh in whether that could be an acceptable contribution.
@nlewo did you test this? because I was trying this
https://github.com/nlewo/comin/issues/37#issuecomment-2889288954
...and it did not work for me becausego-git does not support GIT_SSH_COMMAND.
I'm not entirely sure how go-git handles SSH at all, their example:
r, err := git.PlainClone(directory, false, &git.CloneOptions{
Auth: publicKeys,
URL: url,
Progress: os.Stdout,
})
only passes the public keys but no path to private? maybe i'm getting this wrong... from issues on their repo looks like using ssh-agent is more stable in any case https://github.com/go-git/go-git/issues/218
@nlewo did you test this
No, i didn't test it. I will revert the commit. Thank you for your tests and sorry to have missed your comment 😢
@nlewo It only works on flake inputs, but not the flake itself. i missed that part where different fetchers are used between them...
looks like the best way to fix this would be adding an option for ssh-agent-auth that would tell go-git to use the agent instead of tokens, and keep the GIT_SSH_COMMAND too for inputs.
looks like the best way to fix this would be adding an option for ssh-agent-auth that would tell go-git to use the agent instead of tokens, and keep the GIT_SSH_COMMAND too for inputs.
TBH I am not sure a ssh-agent makes sense in a non-interactive scenario.
The go-git example I have linked has all the bits required to add a auth.ssh_private_key_path to comin.
Which should not be a big deal to add this if we decide to go for it.
Given that the github oci registry does not not support anything but classic pat tokens 😞 going for ssh keys became a little important for me. So less pressure to get this working. But I still think it should be added eventually.
@tcurdt the go-git issue i mentioned earlier is why i thought ssh-agent may be a better solution.
the fix on their side hasn't been merged yet (issue has been open for almost 5 years)
looks like the agent is just more stable when using go-git.
otherwise we could also use the git command directly which will just work with GIT_SSH_COMMAND
An agent might be OK for interactive sessions, I don't see it as an alternative for a non-interactive sessions TBH.
I see the following options:
- accept to live with the bug in
go-gitto require the usernamegit - work with
go-gitand fix this - drop
go-gitin favour of exec ofopenssh
IMO 1. then 2. sounds like an acceptable approach. For 3. I am not sure how much work it entails or whether that's even acceptable for @nlewo
I think we would need to introduce two options for the SSH authentication, because one is specific to each remote and the other one is common to all remote since it concerns the Nix evaluation.
For the SSH authentication for comin git pull
I would be surprised the SSH transport doesn't work with go-git because it uses the SSH standard golang library. Here is an exemple: https://pkg.go.dev/golang.org/x/crypto/ssh#example-PublicKeys
I don't think it's an issue to hardcode the username git and that's actually already the case for the token auth.
As proposed by @tcurdt, we could add the option services.comin.remotes.<name>.auth.ssh_private_key_path.
For the flake inputs
We could add another comin option to set the SSH_GIT_COMMAND env variable for the Nix evaluation such as services.comin.evaluation_ssh_private_key.