1
0
mirror of https://github.com/getsops/sops.git synced 2026-02-05 12:45:21 +01:00

Added SOPS_AGE_KEY_CMD option to age, fixes #1323

Signed-off-by: Danilo Bürger <danilo.buerger@helsing.ai>
This commit is contained in:
Danilo Bürger
2025-03-24 15:16:50 +01:00
parent 0057d3de82
commit eea4b7bb76
6 changed files with 51 additions and 3 deletions

View File

@@ -73,7 +73,7 @@ checkmd: $(MD_FILES)
.PHONY: test
test: vendor
gpg --import pgp/sops_functional_tests_key.asc 2>&1 1>/dev/null || exit 0
unset SOPS_AGE_KEY_FILE; LANG=en_US.UTF-8 $(GO) test $(GO_TEST_FLAGS) ./...
unset SOPS_AGE_KEY_FILE; unset SOPS_AGE_KEY_CMD; LANG=en_US.UTF-8 $(GO) test $(GO_TEST_FLAGS) ./...
.PHONY: showcoverage
showcoverage: test

View File

@@ -227,7 +227,8 @@ On macOS, this would be ``$HOME/Library/Application Support/sops/age/keys.txt``.
Windows, this would be ``%AppData%\sops\age\keys.txt``. You can specify the location
of this file manually by setting the environment variable **SOPS_AGE_KEY_FILE**.
Alternatively, you can provide the key(s) directly by setting the **SOPS_AGE_KEY**
environment variable.
environment variable. Alternatively, you can provide a command to output the age keys
by setting the **SOPS_AGE_KEY_CMD** environment variable.
The contents of this key file should be a list of age X25519 identities, one
per line. Lines beginning with ``#`` are considered comments and ignored. Each

View File

@@ -4,10 +4,10 @@ import (
"bufio"
"bytes"
"errors"
"filippo.io/age/plugin"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
@@ -15,9 +15,11 @@ import (
"filippo.io/age"
"filippo.io/age/agessh"
"filippo.io/age/armor"
"filippo.io/age/plugin"
"github.com/sirupsen/logrus"
"github.com/getsops/sops/v3/logging"
"github.com/kballard/go-shellquote"
)
const (
@@ -27,6 +29,9 @@ const (
// SopsAgeKeyFileEnv can be set as an environment variable pointing to an
// age keys file.
SopsAgeKeyFileEnv = "SOPS_AGE_KEY_FILE"
// SopsAgeKeyCmdEnv can be set as an environment variable with a command
// to execute that returns the age keys.
SopsAgeKeyCmdEnv = "SOPS_AGE_KEY_CMD"
// SopsAgeSshPrivateKeyFileEnv can be set as an environment variable pointing to
// a private SSH key file.
SopsAgeSshPrivateKeyFileEnv = "SOPS_AGE_SSH_PRIVATE_KEY_FILE"
@@ -310,6 +315,18 @@ func (key *MasterKey) loadIdentities() (ParsedIdentities, error) {
readers[SopsAgeKeyFileEnv] = f
}
if ageKeyCmd, ok := os.LookupEnv(SopsAgeKeyCmdEnv); ok {
args, err := shellquote.Split(ageKeyCmd)
if err != nil {
return nil, fmt.Errorf("failed to parse command %s: %w", ageKeyCmd, err)
}
out, err := exec.Command(args[0], args[1:]...).Output()
if err != nil {
return nil, fmt.Errorf("failed to execute command %s: %w", ageKeyCmd, err)
}
readers[SopsAgeKeyCmdEnv] = bytes.NewReader(out)
}
userConfigDir, err := getUserConfigDir()
if err != nil && len(readers) == 0 && len(identities) == 0 {
return nil, fmt.Errorf("user config directory could not be determined: %w", err)

View File

@@ -485,6 +485,33 @@ func TestMasterKey_loadIdentities(t *testing.T) {
assert.ErrorContains(t, err, fmt.Sprintf("failed to parse '%s' age identities", SopsAgeKeyEnv))
assert.Nil(t, got)
})
t.Run(SopsAgeKeyCmdEnv, func(t *testing.T) {
tmpDir := t.TempDir()
// Overwrite to ensure local config is not picked up by tests
overwriteUserConfigDir(t, tmpDir)
t.Setenv(SopsAgeKeyCmdEnv, "echo '"+mockIdentity+"'")
key := &MasterKey{}
got, err := key.loadIdentities()
assert.NoError(t, err)
assert.Len(t, got, 1)
})
t.Run("cmd error", func(t *testing.T) {
tmpDir := t.TempDir()
// Overwrite to ensure local config is not picked up by tests
overwriteUserConfigDir(t, tmpDir)
t.Setenv(SopsAgeKeyCmdEnv, "meow")
key := &MasterKey{}
got, err := key.loadIdentities()
assert.Error(t, err)
assert.ErrorContains(t, err, "failed to execute command meow")
assert.Nil(t, got)
})
}
// overwriteUserConfigDir sets the user config directory and the user home directory

1
go.mod
View File

@@ -26,6 +26,7 @@ require (
github.com/goware/prefixer v0.0.0-20160118172347-395022866408
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/vault/api v1.16.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/lib/pq v1.10.9
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/go-wordwrap v1.0.1

2
go.sum
View File

@@ -205,6 +205,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4=
github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=