comin icon indicating copy to clipboard operation
comin copied to clipboard

SSH deploy keys

Open jpds opened this issue 1 year ago • 9 comments

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.

jpds avatar May 03 '24 00:05 jpds

I would find this very useful.

Something simple like exposing the GIT_SSH_COMMAND of the service would make this possible.

slenderq avatar Nov 08 '24 05:11 slenderq

this already works if you add

    systemd = {
      services = {
        comin = {
          environment = {
            GIT_SSH_COMMAND = "${pkgs.openssh}/bin/ssh -i <path to key>";
          };
        };
      };
    };

Arbel-arad avatar Apr 27 '25 09:04 Arbel-arad

@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 avatar May 18 '25 15:05 tcurdt

@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?

Arbel-arad avatar May 18 '25 21:05 Arbel-arad

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?

tcurdt avatar May 19 '25 00:05 tcurdt

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? 🤔

tcurdt avatar May 19 '25 00:05 tcurdt

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? 🤔

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...

Arbel-arad avatar May 19 '25 00:05 Arbel-arad

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.

tcurdt avatar May 19 '25 01:05 tcurdt

I guess @nlewo needs to weigh in whether that could be an acceptable contribution.

tcurdt avatar May 19 '25 08:05 tcurdt

@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.

tcurdt avatar Jun 07 '25 08:06 tcurdt

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

Arbel-arad avatar Jun 07 '25 09:06 Arbel-arad

@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 avatar Jun 07 '25 17:06 nlewo

@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.

Arbel-arad avatar Jun 07 '25 18:06 Arbel-arad

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 avatar Jun 07 '25 20:06 tcurdt

@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

Arbel-arad avatar Jun 07 '25 21:06 Arbel-arad

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:

  1. accept to live with the bug in go-git to require the username git
  2. work with go-git and fix this
  3. drop go-git in favour of exec of openssh

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

tcurdt avatar Jun 07 '25 22:06 tcurdt

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.

nlewo avatar Jun 08 '25 09:06 nlewo