Skip to content

Commit eea4b7b

Browse files
committed
Added SOPS_AGE_KEY_CMD option to age, fixes #1323
Signed-off-by: Danilo Bürger <danilo.buerger@helsing.ai>
1 parent 0057d3d commit eea4b7b

File tree

6 files changed

+51
-3
lines changed

6 files changed

+51
-3
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ checkmd: $(MD_FILES)
7373
.PHONY: test
7474
test: vendor
7575
gpg --import pgp/sops_functional_tests_key.asc 2>&1 1>/dev/null || exit 0
76-
unset SOPS_AGE_KEY_FILE; LANG=en_US.UTF-8 $(GO) test $(GO_TEST_FLAGS) ./...
76+
unset SOPS_AGE_KEY_FILE; unset SOPS_AGE_KEY_CMD; LANG=en_US.UTF-8 $(GO) test $(GO_TEST_FLAGS) ./...
7777

7878
.PHONY: showcoverage
7979
showcoverage: test

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,8 @@ On macOS, this would be ``$HOME/Library/Application Support/sops/age/keys.txt``.
227227
Windows, this would be ``%AppData%\sops\age\keys.txt``. You can specify the location
228228
of this file manually by setting the environment variable **SOPS_AGE_KEY_FILE**.
229229
Alternatively, you can provide the key(s) directly by setting the **SOPS_AGE_KEY**
230-
environment variable.
230+
environment variable. Alternatively, you can provide a command to output the age keys
231+
by setting the **SOPS_AGE_KEY_CMD** environment variable.
231232

232233
The contents of this key file should be a list of age X25519 identities, one
233234
per line. Lines beginning with ``#`` are considered comments and ignored. Each

age/keysource.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,22 @@ import (
44
"bufio"
55
"bytes"
66
"errors"
7-
"filippo.io/age/plugin"
87
"fmt"
98
"io"
109
"os"
10+
"os/exec"
1111
"path/filepath"
1212
"runtime"
1313
"strings"
1414

1515
"filippo.io/age"
1616
"filippo.io/age/agessh"
1717
"filippo.io/age/armor"
18+
"filippo.io/age/plugin"
1819
"github.com/sirupsen/logrus"
1920

2021
"github.com/getsops/sops/v3/logging"
22+
"github.com/kballard/go-shellquote"
2123
)
2224

2325
const (
@@ -27,6 +29,9 @@ const (
2729
// SopsAgeKeyFileEnv can be set as an environment variable pointing to an
2830
// age keys file.
2931
SopsAgeKeyFileEnv = "SOPS_AGE_KEY_FILE"
32+
// SopsAgeKeyCmdEnv can be set as an environment variable with a command
33+
// to execute that returns the age keys.
34+
SopsAgeKeyCmdEnv = "SOPS_AGE_KEY_CMD"
3035
// SopsAgeSshPrivateKeyFileEnv can be set as an environment variable pointing to
3136
// a private SSH key file.
3237
SopsAgeSshPrivateKeyFileEnv = "SOPS_AGE_SSH_PRIVATE_KEY_FILE"
@@ -310,6 +315,18 @@ func (key *MasterKey) loadIdentities() (ParsedIdentities, error) {
310315
readers[SopsAgeKeyFileEnv] = f
311316
}
312317

318+
if ageKeyCmd, ok := os.LookupEnv(SopsAgeKeyCmdEnv); ok {
319+
args, err := shellquote.Split(ageKeyCmd)
320+
if err != nil {
321+
return nil, fmt.Errorf("failed to parse command %s: %w", ageKeyCmd, err)
322+
}
323+
out, err := exec.Command(args[0], args[1:]...).Output()
324+
if err != nil {
325+
return nil, fmt.Errorf("failed to execute command %s: %w", ageKeyCmd, err)
326+
}
327+
readers[SopsAgeKeyCmdEnv] = bytes.NewReader(out)
328+
}
329+
313330
userConfigDir, err := getUserConfigDir()
314331
if err != nil && len(readers) == 0 && len(identities) == 0 {
315332
return nil, fmt.Errorf("user config directory could not be determined: %w", err)

age/keysource_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,33 @@ func TestMasterKey_loadIdentities(t *testing.T) {
485485
assert.ErrorContains(t, err, fmt.Sprintf("failed to parse '%s' age identities", SopsAgeKeyEnv))
486486
assert.Nil(t, got)
487487
})
488+
489+
t.Run(SopsAgeKeyCmdEnv, func(t *testing.T) {
490+
tmpDir := t.TempDir()
491+
// Overwrite to ensure local config is not picked up by tests
492+
overwriteUserConfigDir(t, tmpDir)
493+
494+
t.Setenv(SopsAgeKeyCmdEnv, "echo '"+mockIdentity+"'")
495+
496+
key := &MasterKey{}
497+
got, err := key.loadIdentities()
498+
assert.NoError(t, err)
499+
assert.Len(t, got, 1)
500+
})
501+
502+
t.Run("cmd error", func(t *testing.T) {
503+
tmpDir := t.TempDir()
504+
// Overwrite to ensure local config is not picked up by tests
505+
overwriteUserConfigDir(t, tmpDir)
506+
507+
t.Setenv(SopsAgeKeyCmdEnv, "meow")
508+
509+
key := &MasterKey{}
510+
got, err := key.loadIdentities()
511+
assert.Error(t, err)
512+
assert.ErrorContains(t, err, "failed to execute command meow")
513+
assert.Nil(t, got)
514+
})
488515
}
489516

490517
// overwriteUserConfigDir sets the user config directory and the user home directory

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ require (
2626
github.com/goware/prefixer v0.0.0-20160118172347-395022866408
2727
github.com/hashicorp/go-cleanhttp v0.5.2
2828
github.com/hashicorp/vault/api v1.16.0
29+
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
2930
github.com/lib/pq v1.10.9
3031
github.com/mitchellh/go-homedir v1.1.0
3132
github.com/mitchellh/go-wordwrap v1.0.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
205205
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
206206
github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4=
207207
github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA=
208+
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
209+
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
208210
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
209211
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
210212
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=

0 commit comments

Comments
 (0)