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

Add SSH support for age #1134

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

mstrangfeld
Copy link

This MR implements #692

I realize there is already a MR #898 but it implements the ssh encryption as a completely new method.
I just patched the existing age module to also support ssh recipients and identities.

The behavior is the same as the original MR:
If there is no SOPS_AGE_SSH_PRIVATE_KEY env variable given, sops will check ~/.ssh/id_ed25519 and fallbacks to ~/.ssh/id_rsa.

Would love to hear some thoughts on this.

@conorsch
Copy link

Thanks for submitting. Took it for a spin; works splendidly over here. Here's approximately what I used to test:

#!/bin/bash
# review https://github.com/mozilla/sops/pull/1134
set -euo pipefail


# Make tempdir for test
d="$(mktemp -d)"
cd "$d" || exit 1
ssh_pubkey="$(cat ~/.ssh/id_ed25519.pub)"

cat <<END > .sops.yaml
---
creation_rules:
  - age: "$ssh_pubkey"
END
echo "Created sops config:"
cat .sops.yaml

cat <<END2 > example.yaml
---
foo: bar
END2

echo "Created vars file:"
cat example.yaml

sops -e -i example.yaml
echo "Encrypted vars file via ssh pubkey:"
cat example.yaml

echo "Attempting decryption of vars file:"
sops -d example.yaml

echo "SUCCESS!"

Tried it with a 4096-bit RSA key, and that worked fine, too. Would love to see this PR land.

@mstrangfeld mstrangfeld changed the base branch from master to develop October 25, 2022 13:04
@mstrangfeld mstrangfeld changed the title WIP: Add ssh support for age Add ssh support for age Oct 25, 2022
@mstrangfeld mstrangfeld marked this pull request as ready for review October 25, 2022 13:06
@lakano
Copy link

lakano commented Feb 8, 2023

Hi!
I've found this PR, and it's what we waiting to permit us to uses SOPS. Is this PR is abandoned or we just need to wait again?

@kirek007
Copy link

kirek007 commented Feb 9, 2023

Hey, I would also be interested in using ssh key :)

@hiddeco hiddeco added this to the v3.9.0 milestone Jul 3, 2023
@hiddeco
Copy link
Member

hiddeco commented Jul 3, 2023

Thank you for your contribution! 🥑

Due to the size of this PR, I have scheduled it for next-next minor. As we do not want to unleash a flood of issues do to newly introduced functionalities on us while we have just taken over the project. I'll come back to this once v3.8.0 has been released.

In the meantime, it would be helpful if you could rebase your work and sign-off your commits. Thanks! 🙇

@neongreen neongreen mentioned this pull request Aug 5, 2023
@hiddeco hiddeco changed the title Add ssh support for age Add SSH support for age Oct 11, 2023
Copy link
Member

@hiddeco hiddeco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me some time (and I hope you are still around, @mstrangfeld!), but here is an initial round of review. Overall, it appears to be headed in the right direction, except for some minor nits and picks around details.

Thanks a lot for spending time on this, it appears to be the most requested thing at the moment. I promise my next review won't take this long. 🍇

age/keysource.go Outdated Show resolved Hide resolved
age/keysource.go Outdated Show resolved Hide resolved
// SopsAgeKeyUserConfigPath). It will load all found references, and expects
// at least one configuration to be present.
// SopsAgeSshPrivateKeyEnv, SopsAgeKeyUserConfigPath). It will load all
// found references, and expects at least one configuration to be present.
func (key *MasterKey) loadIdentities() (ParsedIdentities, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is a method, it should continue to be above the newly introduced private functions.

age/keysource.go Outdated Show resolved Hide resolved
age/keysource.go Outdated
Comment on lines 295 to 330
sshKeyFilePath, ok := os.LookupEnv(SopsAgeSshPrivateKeyEnv)
if ok {
return getAgeSshIdentityFromPrivateKeyFile(sshKeyFilePath)
}

userHomeDir, err := os.UserHomeDir()
if err != nil || userHomeDir == "" {
log.Warnf("could not determine the user home directory: %v", err)
return nil, nil
}

sshEd25519PrivateKeyPath := filepath.Join(userHomeDir, ".ssh", "id_ed25519")
if _, err := os.Stat(sshEd25519PrivateKeyPath); err == nil {
return getAgeSshIdentityFromPrivateKeyFile(sshEd25519PrivateKeyPath)
}

sshRsaPrivateKeyPath := filepath.Join(userHomeDir, ".ssh", "id_rsa")
if _, err := os.Stat(sshRsaPrivateKeyPath); err == nil {
return getAgeSshIdentityFromPrivateKeyFile(sshRsaPrivateKeyPath)
}

return nil, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, age lazily attempts to make use of the keys. Which makes me wonder if it would not be better to collect any found key which would match the behavior of loadIdentities().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so, it may be better to collect existing paths here and delegate the loading of them to loadIdentities(). Which would iterate over the returned paths, while calling getAgeSshIdentityFromPrivateKeyFile().

age/keysource.go Outdated Show resolved Hide resolved
age/keysource.go Outdated Show resolved Hide resolved
age/keysource.go Outdated Show resolved Hide resolved
@mstrangfeld
Copy link
Author

Hi @hiddeco, thanks for the review! I will rebase, sign-off the commits and try to implement your suggestions!
It might take a week or so, but I'm excited to get this feature done.

@sylvorg
Copy link

sylvorg commented Dec 1, 2023

I hate to look like I'm trying rush this, but I'm really just very excited for this feature! 😅 So if I could just bump this...?

@fiksn
Copy link

fiksn commented Dec 21, 2023

The behavior is the same as the original MR: If there is no SOPS_AGE_SSH_PRIVATE_KEY env variable given, sops will check ~/.ssh/id_ed25519 and fallbacks to ~/.ssh/id_rsa.

Would love to hear some thoughts on this.

Reasonable behavior. What was a bit confusing for me was just when I've set SOPS_AGE_SSH_PRIVATE_KEY=file.key it automatically assumed there is also a file.key.pub. I mean I did ssh-keygen -y -f file.key > file.key.pub then but this should not really be necessary (or this assumption should at least be documented).

Signed-off-by: Marvin Strangfeld <[email protected]>
@mstrangfeld
Copy link
Author

I finally had some time to do this. I am no longer actively using sops at the moment, so if anyone else wants to take over from here, please feel free to use and modify my code as you wish.

@tarasglek
Copy link

I wrote a blog post on using sops with ssh keys and github, might be relevant to someone here. https://taras.glek.net/post/github-to-sops-lighter-weight-secret-management/

@overfl0
Copy link

overfl0 commented Apr 25, 2024

Hi @hiddeco , would it be possible to take a look at this PR once again?
The PR has been created around 1.5 years ago and the original poster, after being asked to rebase it to the latest version of sops (and doing so), said that he's not actively using sops anymore.
As a result, I think that the longer it takes for this PR to be merged, the harder it will be for it to be merged in the future, with every other commit not related to this PR potentially messing something somewhere.

Maybe it would make sense to merge this now and then work on any potential refactoring in future versions, so that we already have something that's working that we can use.

@patryk4815
Copy link

patryk4815 commented May 1, 2024

@overfl0 You can convert ssh-ed25519 key using ssh-to-age program ;)
https://github.com/Mic92/ssh-to-age/

@elijah
Copy link

elijah commented May 28, 2024

This is a valuable feature - +1 - it would be great to see it merged and usable.

@felixfontein felixfontein modified the milestones: v3.9.0, 3.10.0 Jun 26, 2024
@overfl0
Copy link

overfl0 commented Oct 28, 2024

@felixfontein what would be needed for this PR to be merged? It has had milestone tags changed for a while, without any comment whether it's just waiting for someone to look at it and it's purely due to the lack of time or if some additional work is needed.
Any information would be appreciated.

I'm tagging you because hiddeco seems to have stopped contributing in February.

Copy link
Contributor

@felixfontein felixfontein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@overfl0 I guess someone needs to reboot this PR by creating a new one and resolving conflicts. I personally don't have very much time, but I can try to give this another review, but it probably makes more sense to wait for a new PR (one comment below which I noticed while glancing over it).

Right now (well, I guess since the beginning of this year) it seems that the maintainer team has very limited time, so not much happened... I tried to get 3.9.0 out in summer with all changes done until then (and some more that should really go in); everything that wasn't looking like it will get done very very soon at that point got moved to the next milestone.

@@ -24,6 +26,9 @@ const (
// SopsAgeKeyFileEnv can be set as an environment variable pointing to an
// age keys file.
SopsAgeKeyFileEnv = "SOPS_AGE_KEY_FILE"
// SopsAgeSshPrivateKeyEnv can be set as an environment variable pointing to
// a private SSH key file.
SopsAgeSshPrivateKeyEnv = "SOPS_AGE_SSH_PRIVATE_KEY"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would include File here to avoid possible confusion with the contents of the private key.

Suggested change
SopsAgeSshPrivateKeyEnv = "SOPS_AGE_SSH_PRIVATE_KEY"
SopsAgeSshPrivateKeyEnvFile = "SOPS_AGE_SSH_PRIVATE_KEY_FILE"

@overfl0
Copy link

overfl0 commented Oct 30, 2024

Thanks for your response @felixfontein !
FYI @albinvass has done just that: he rebased this PR and created his own, 3 months ago: #1496
You may want to take a look at that PR and say how it looks. There seem to be a few automatic warnings for it, but I think that the reason nothing has been done about that is that people see that this PR here has been staying in limbo for 2 years so maybe there is no reason to spend time fixing anything.

I'm sure that if you acknowledge that PR and say there that there is an actual chance of it being merged in, that people will then be willing to help and iron it out.

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

Successfully merging this pull request may close these issues.