mirror of
https://github.com/getsops/sops.git
synced 2026-02-05 12:45:21 +01:00
Merge pull request #1811 from danilobuerger/SOPS_AGE_KEY_CMD
Added SOPS_AGE_KEY_CMD option to age, fixes #1323
This commit is contained in:
2
Makefile
2
Makefile
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/google/shlex"
|
||||
)
|
||||
|
||||
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 := shlex.Split(ageKeyCmd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse command %s from %s: %w", ageKeyCmd, SopsAgeKeyCmdEnv, err)
|
||||
}
|
||||
out, err := exec.Command(args[0], args[1:]...).Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute command %s from %s: %w", ageKeyCmd, SopsAgeKeyCmdEnv, 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user