mirror of
https://github.com/getsops/sops.git
synced 2026-02-05 12:45:21 +01:00
Added .sops.go config file support
This commit is contained in:
@@ -235,20 +235,35 @@ func encrypt(c *cli.Context, file string, fileBytes []byte, output io.Writer) er
|
||||
metadata.UnencryptedSuffix = c.String("unencrypted-suffix")
|
||||
metadata.Version = "2.0.0"
|
||||
var kmsKeys []sops.MasterKey
|
||||
var pgpKeys []sops.MasterKey
|
||||
|
||||
if c.String("kms") != "" {
|
||||
for _, k := range kms.MasterKeysFromArnString(c.String("kms")) {
|
||||
kmsKeys = append(kmsKeys, &k)
|
||||
}
|
||||
}
|
||||
metadata.KeySources = append(metadata.KeySources, sops.KeySource{Name: "kms", Keys: kmsKeys})
|
||||
|
||||
var pgpKeys []sops.MasterKey
|
||||
if c.String("pgp") != "" {
|
||||
for _, k := range pgp.MasterKeysFromFingerprintString(c.String("pgp")) {
|
||||
pgpKeys = append(pgpKeys, &k)
|
||||
}
|
||||
}
|
||||
metadata.KeySources = append(metadata.KeySources, sops.KeySource{Name: "pgp", Keys: pgpKeys})
|
||||
|
||||
if c.String("kms") == "" && c.String("pgp") == "" {
|
||||
kmsString, pgpString, err := yaml.MasterKeyStringsForFile(file, nil)
|
||||
if err == nil {
|
||||
for _, k := range pgp.MasterKeysFromFingerprintString(pgpString) {
|
||||
pgpKeys = append(pgpKeys, &k)
|
||||
}
|
||||
for _, k := range kms.MasterKeysFromArnString(kmsString) {
|
||||
kmsKeys = append(kmsKeys, &k)
|
||||
}
|
||||
}
|
||||
}
|
||||
kmsKs := sops.KeySource{Name: "kms", Keys: kmsKeys}
|
||||
pgpKs := sops.KeySource{Name: "pgp", Keys: pgpKeys}
|
||||
metadata.KeySources = append(metadata.KeySources, kmsKs)
|
||||
metadata.KeySources = append(metadata.KeySources, pgpKs)
|
||||
|
||||
key := make([]byte, 32)
|
||||
_, err = rand.Read(key)
|
||||
if err != nil {
|
||||
|
||||
87
yaml/config.go
Normal file
87
yaml/config.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/autrilla/yaml"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type fileSystem interface {
|
||||
Stat(name string) (os.FileInfo, error)
|
||||
}
|
||||
|
||||
type osFS struct {
|
||||
stat func(string) (os.FileInfo, error)
|
||||
}
|
||||
|
||||
func (fs osFS) Stat(name string) (os.FileInfo, error) {
|
||||
return fs.stat(name)
|
||||
}
|
||||
|
||||
var fs fileSystem = osFS{stat: os.Stat}
|
||||
|
||||
const (
|
||||
maxDepth = 100
|
||||
configFileName = ".sops.yaml"
|
||||
)
|
||||
|
||||
// FindConfigFile looks for a sops config file in the current working directory and on parent directories, up to the limit defined by the maxDepth constant.
|
||||
func FindConfigFile(start string) (string, error) {
|
||||
filepath := path.Dir(start)
|
||||
for i := 0; i < maxDepth; i++ {
|
||||
_, err := fs.Stat(path.Join(filepath, configFileName))
|
||||
if err != nil {
|
||||
filepath = path.Join(filepath, "..")
|
||||
} else {
|
||||
return path.Join(filepath, configFileName), nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("Config file not found")
|
||||
}
|
||||
|
||||
type configFile struct {
|
||||
CreationRules []creationRule `yaml:"creation_rules"`
|
||||
}
|
||||
|
||||
type creationRule struct {
|
||||
FilenameRegex string `yaml:"filename_regex"`
|
||||
KMS string
|
||||
PGP string
|
||||
}
|
||||
|
||||
// Load loads a sops config file into a temporary struct
|
||||
func (f *configFile) load(bytes []byte) error {
|
||||
err := yaml.Unmarshal(bytes, f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not unmarshal config file: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MasterKeyStringsForFile returns a comma separated string of KMS ARNs and a comma separated list of PGP fingerprints. If the config bytes are left empty, the function will look for the config file by itself.
|
||||
func MasterKeyStringsForFile(filepath string, confBytes []byte) (kms, pgp string, err error) {
|
||||
if confBytes == nil {
|
||||
confPath, err := FindConfigFile(filepath)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
confBytes, err = ioutil.ReadFile(confPath)
|
||||
}
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Could not read config file: %s", err)
|
||||
}
|
||||
conf := configFile{}
|
||||
err = conf.load(confBytes)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Error loading config: %s", err)
|
||||
}
|
||||
for _, rule := range conf.CreationRules {
|
||||
if match, _ := regexp.MatchString(rule.FilenameRegex, filepath); match {
|
||||
return rule.KMS, rule.PGP, nil
|
||||
}
|
||||
}
|
||||
return "", "", nil
|
||||
}
|
||||
85
yaml/config_test.go
Normal file
85
yaml/config_test.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type mockFS struct {
|
||||
stat func(string) (os.FileInfo, error)
|
||||
}
|
||||
|
||||
func (fs mockFS) Stat(name string) (os.FileInfo, error) {
|
||||
return fs.stat(name)
|
||||
}
|
||||
|
||||
func TestFindConfigFileRecursive(t *testing.T) {
|
||||
expectedPath := path.Clean("./../../.sops.yaml")
|
||||
fs = mockFS{stat: func(name string) (os.FileInfo, error) {
|
||||
if name == expectedPath {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, &os.PathError{}
|
||||
}}
|
||||
filepath, err := FindConfigFile(".")
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, expectedPath, filepath)
|
||||
}
|
||||
|
||||
func TestFindConfigFileCurrentDir(t *testing.T) {
|
||||
expectedPath := path.Clean(".sops.yaml")
|
||||
fs = mockFS{stat: func(name string) (os.FileInfo, error) {
|
||||
if name == expectedPath {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, &os.PathError{}
|
||||
}}
|
||||
filepath, err := FindConfigFile(".")
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, expectedPath, filepath)
|
||||
}
|
||||
|
||||
var sampleConfig = []byte(`
|
||||
creation_rules:
|
||||
- filename_regex: foobar*
|
||||
kms: "1"
|
||||
pgp: "2"
|
||||
- filename_regex: ""
|
||||
kms: foo
|
||||
pgp: bar
|
||||
`)
|
||||
|
||||
func TestLoadConfigFile(t *testing.T) {
|
||||
expected := configFile{
|
||||
CreationRules: []creationRule{
|
||||
creationRule{
|
||||
FilenameRegex: "foobar*",
|
||||
KMS: "1",
|
||||
PGP: "2",
|
||||
},
|
||||
creationRule{
|
||||
FilenameRegex: "",
|
||||
KMS: "foo",
|
||||
PGP: "bar",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
conf := configFile{}
|
||||
err := conf.load(sampleConfig)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, expected, conf)
|
||||
}
|
||||
|
||||
func TestMasterKeyStringsForFile(t *testing.T) {
|
||||
kms, pgp, err := MasterKeyStringsForFile("foobar2000", sampleConfig)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, "1", kms)
|
||||
assert.Equal(t, "2", pgp)
|
||||
kms, pgp, err = MasterKeyStringsForFile("whatever", sampleConfig)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, "foo", kms)
|
||||
assert.Equal(t, "bar", pgp)
|
||||
}
|
||||
Reference in New Issue
Block a user