зеркало из https://github.com/getsops/sops.git
added the --encrypted-suffix option
This commit is contained in:
Родитель
e57c8f2c85
Коммит
efd8521436
|
@ -36,6 +36,7 @@ type editOpts struct {
|
|||
type editExampleOpts struct {
|
||||
editOpts
|
||||
UnencryptedSuffix string
|
||||
EncryptedSuffix string
|
||||
KeyGroups []sops.KeyGroup
|
||||
GroupThreshold int
|
||||
}
|
||||
|
@ -96,6 +97,7 @@ func editExample(opts editExampleOpts) ([]byte, error) {
|
|||
tree.Metadata = sops.Metadata{
|
||||
KeyGroups: opts.KeyGroups,
|
||||
UnencryptedSuffix: opts.UnencryptedSuffix,
|
||||
EncryptedSuffix: opts.EncryptedSuffix,
|
||||
Version: version,
|
||||
ShamirThreshold: opts.GroupThreshold,
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ type encryptOpts struct {
|
|||
InputPath string
|
||||
KeyServices []keyservice.KeyServiceClient
|
||||
UnencryptedSuffix string
|
||||
EncryptedSuffix string
|
||||
KeyGroups []sops.KeyGroup
|
||||
GroupThreshold int
|
||||
}
|
||||
|
@ -37,6 +38,7 @@ func encrypt(opts encryptOpts) (encryptedFile []byte, err error) {
|
|||
tree.Metadata = sops.Metadata{
|
||||
KeyGroups: opts.KeyGroups,
|
||||
UnencryptedSuffix: opts.UnencryptedSuffix,
|
||||
EncryptedSuffix: opts.EncryptedSuffix,
|
||||
Version: version,
|
||||
ShamirThreshold: opts.GroupThreshold,
|
||||
}
|
||||
|
|
|
@ -328,6 +328,10 @@ func main() {
|
|||
Usage: "override the unencrypted key suffix.",
|
||||
Value: sops.DefaultUnencryptedSuffix,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "encrypted-suffix",
|
||||
Usage: "override the encrypted key suffix. When empty, all keys will be encrypted, unless otherwise marked with unencrypted-suffix.",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "config",
|
||||
Usage: "path to sops' config file. If set, sops will not search for the config file recursively.",
|
||||
|
@ -392,6 +396,7 @@ func main() {
|
|||
InputPath: fileName,
|
||||
Cipher: aes.NewCipher(),
|
||||
UnencryptedSuffix: c.String("unencrypted-suffix"),
|
||||
EncryptedSuffix: c.String("encrypted-suffix"),
|
||||
KeyServices: svcs,
|
||||
KeyGroups: groups,
|
||||
GroupThreshold: threshold,
|
||||
|
@ -498,6 +503,7 @@ func main() {
|
|||
output, err = editExample(editExampleOpts{
|
||||
editOpts: opts,
|
||||
UnencryptedSuffix: c.String("unencrypted-suffix"),
|
||||
EncryptedSuffix: c.String("encrypted-suffix"),
|
||||
KeyGroups: groups,
|
||||
GroupThreshold: threshold,
|
||||
})
|
||||
|
|
59
sops.go
59
sops.go
|
@ -107,7 +107,7 @@ func valueFromPathAndLeaf(path []interface{}, leaf interface{}) interface{} {
|
|||
leaf,
|
||||
}
|
||||
} else {
|
||||
return []interface{} {
|
||||
return []interface{}{
|
||||
valueFromPathAndLeaf(path[1:], leaf),
|
||||
}
|
||||
}
|
||||
|
@ -115,14 +115,14 @@ func valueFromPathAndLeaf(path []interface{}, leaf interface{}) interface{} {
|
|||
if len(path) == 1 {
|
||||
return TreeBranch{
|
||||
TreeItem{
|
||||
Key: component,
|
||||
Key: component,
|
||||
Value: leaf,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
return TreeBranch{
|
||||
TreeItem{
|
||||
Key: component,
|
||||
Key: component,
|
||||
Value: valueFromPathAndLeaf(path[1:], leaf),
|
||||
},
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ func set(branch interface{}, path []interface{}, value interface{}) interface{}
|
|||
}
|
||||
}
|
||||
|
||||
func (branch TreeBranch) Set(path []interface{}, value interface{}) (TreeBranch) {
|
||||
func (branch TreeBranch) Set(path []interface{}, value interface{}) TreeBranch {
|
||||
return set(branch, path, value).(TreeBranch)
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,8 @@ func (branch TreeBranch) walkBranch(in TreeBranch, path []string, onLeaves func(
|
|||
return in, nil
|
||||
}
|
||||
|
||||
// Encrypt walks over the tree and encrypts all values with the provided cipher, except those whose key ends with the UnencryptedSuffix specified on the Metadata struct. If encryption is successful, it returns the MAC for the encrypted tree.
|
||||
// Encrypt walks over the tree and encrypts all values with the provided cipher, except those whose key ends with the UnencryptedSuffix specified on the Metadata struct, or those not ending with EncryptedSuffix, if EncryptedSuffix is provided (by default it is not).
|
||||
// If encryption is successful, it returns the MAC for the encrypted tree.
|
||||
func (tree Tree) Encrypt(key []byte, cipher Cipher) (string, error) {
|
||||
hash := sha512.New()
|
||||
_, err := tree.Branch.walkBranch(tree.Branch, make([]string, 0), func(in interface{}, path []string) (interface{}, error) {
|
||||
|
@ -294,11 +295,27 @@ func (tree Tree) Encrypt(key []byte, cipher Cipher) (string, error) {
|
|||
hash.Write(bytes)
|
||||
}
|
||||
encrypted := true
|
||||
for _, v := range path {
|
||||
if strings.HasSuffix(v, tree.Metadata.UnencryptedSuffix) {
|
||||
encrypted = false
|
||||
if tree.Metadata.UnencryptedSuffix != "" {
|
||||
for _, v := range path {
|
||||
if strings.HasSuffix(v, tree.Metadata.UnencryptedSuffix) {
|
||||
encrypted = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if tree.Metadata.EncryptedSuffix != "" {
|
||||
encryptedSuffixFound := false
|
||||
for _, v := range path {
|
||||
if strings.HasSuffix(v, tree.Metadata.EncryptedSuffix) {
|
||||
encryptedSuffixFound = true
|
||||
if !encrypted {
|
||||
return nil, fmt.Errorf("Cannot use both encrypted_suffix and unencrypted_suffix in the same file")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
encrypted = encryptedSuffixFound
|
||||
}
|
||||
if encrypted {
|
||||
var err error
|
||||
pathString := strings.Join(path, ":") + ":"
|
||||
|
@ -315,17 +332,34 @@ func (tree Tree) Encrypt(key []byte, cipher Cipher) (string, error) {
|
|||
return fmt.Sprintf("%X", hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// Decrypt walks over the tree and decrypts all values with the provided cipher, except those whose key ends with the UnencryptedSuffix specified on the Metadata struct. If decryption is successful, it returns the MAC for the decrypted tree.
|
||||
// Decrypt walks over the tree and decrypts all values with the provided cipher, except those whose key ends with the UnencryptedSuffix specified on the Metadata struct or those not ending with EncryptedSuffix, if EncryptedSuffix is provided (by default it is not).
|
||||
// If decryption is successful, it returns the MAC for the decrypted tree.
|
||||
func (tree Tree) Decrypt(key []byte, cipher Cipher) (string, error) {
|
||||
log.Debug("Decrypting tree")
|
||||
hash := sha512.New()
|
||||
_, err := tree.Branch.walkBranch(tree.Branch, make([]string, 0), func(in interface{}, path []string) (interface{}, error) {
|
||||
encrypted := true
|
||||
for _, p := range path {
|
||||
if strings.HasSuffix(p, tree.Metadata.UnencryptedSuffix) {
|
||||
encrypted = false
|
||||
if tree.Metadata.UnencryptedSuffix != "" {
|
||||
for _, p := range path {
|
||||
if strings.HasSuffix(p, tree.Metadata.UnencryptedSuffix) {
|
||||
encrypted = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if tree.Metadata.EncryptedSuffix != "" {
|
||||
encryptedSuffixFound := false
|
||||
for _, p := range path {
|
||||
if strings.HasSuffix(p, tree.Metadata.EncryptedSuffix) {
|
||||
encryptedSuffixFound = true
|
||||
if !encrypted {
|
||||
return nil, fmt.Errorf("Cannot use both encrypted_suffix and unencrypted_suffix in the same file")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
encrypted = encryptedSuffixFound
|
||||
}
|
||||
var v interface{}
|
||||
if encrypted {
|
||||
var err error
|
||||
|
@ -390,6 +424,7 @@ func (tree *Tree) GenerateDataKeyWithKeyServices(svcs []keyservice.KeyServiceCli
|
|||
type Metadata struct {
|
||||
LastModified time.Time
|
||||
UnencryptedSuffix string
|
||||
EncryptedSuffix string
|
||||
MessageAuthenticationCode string
|
||||
Version string
|
||||
KeyGroups []KeyGroup
|
||||
|
|
63
sops_test.go
63
sops_test.go
|
@ -83,6 +83,56 @@ func TestUnencryptedSuffix(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncryptedSuffix(t *testing.T) {
|
||||
branch := TreeBranch{
|
||||
TreeItem{
|
||||
Key: "foo_encrypted",
|
||||
Value: "bar",
|
||||
},
|
||||
TreeItem{
|
||||
Key: "bar",
|
||||
Value: TreeBranch{
|
||||
TreeItem{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
tree := Tree{Branch: branch, Metadata: Metadata{EncryptedSuffix: "_encrypted"}}
|
||||
expected := TreeBranch{
|
||||
TreeItem{
|
||||
Key: "foo_encrypted",
|
||||
Value: "rab",
|
||||
},
|
||||
TreeItem{
|
||||
Key: "bar",
|
||||
Value: TreeBranch{
|
||||
TreeItem{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cipher := reverseCipher{}
|
||||
_, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher)
|
||||
if err != nil {
|
||||
t.Errorf("Encrypting the tree failed: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(tree.Branch, expected) {
|
||||
t.Errorf("Trees don't match: \ngot \t\t%+v,\n expected \t\t%+v", tree.Branch, expected)
|
||||
}
|
||||
_, err = tree.Decrypt(bytes.Repeat([]byte("f"), 32), cipher)
|
||||
if err != nil {
|
||||
t.Errorf("Decrypting the tree failed: %s", err)
|
||||
}
|
||||
expected[0].Value = "bar"
|
||||
if !reflect.DeepEqual(tree.Branch, expected) {
|
||||
t.Errorf("Trees don't match: \ngot\t\t\t%+v,\nexpected\t\t%+v", tree.Branch, expected)
|
||||
}
|
||||
}
|
||||
|
||||
type MockCipher struct{}
|
||||
|
||||
func (m MockCipher) Encrypt(value interface{}, key []byte, path string) (string, error) {
|
||||
|
@ -248,7 +298,6 @@ func TestTruncateTree(t *testing.T) {
|
|||
assert.Equal(t, expected, result)
|
||||
}
|
||||
|
||||
|
||||
func TestEncryptComments(t *testing.T) {
|
||||
tree := Tree{
|
||||
Branch: TreeBranch{
|
||||
|
@ -327,7 +376,7 @@ func TestSetNewKey(t *testing.T) {
|
|||
Key: "bar",
|
||||
Value: TreeBranch{
|
||||
TreeItem{
|
||||
Key: "baz",
|
||||
Key: "baz",
|
||||
Value: "foobar",
|
||||
},
|
||||
},
|
||||
|
@ -356,7 +405,7 @@ func TestSetArrayDeepNew(t *testing.T) {
|
|||
func TestSetNewKeyDeep(t *testing.T) {
|
||||
branch := TreeBranch{
|
||||
TreeItem{
|
||||
Key: "foo",
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
},
|
||||
}
|
||||
|
@ -364,7 +413,6 @@ func TestSetNewKeyDeep(t *testing.T) {
|
|||
assert.Equal(t, "hello", set[0].Value.(TreeBranch)[0].Value.(TreeBranch)[0].Value)
|
||||
}
|
||||
|
||||
|
||||
func TestSetNewKeyOnEmptyBranch(t *testing.T) {
|
||||
branch := TreeBranch{}
|
||||
set := branch.Set([]interface{}{"foo", "bar", "baz"}, "hello")
|
||||
|
@ -386,7 +434,6 @@ func TestSetArray(t *testing.T) {
|
|||
assert.Equal(t, "uno", set[0].Value.([]interface{})[0])
|
||||
}
|
||||
|
||||
|
||||
func TestSetArrayNew(t *testing.T) {
|
||||
branch := TreeBranch{}
|
||||
set := branch.Set([]interface{}{"foo", 0, 0}, "uno")
|
||||
|
@ -396,7 +443,7 @@ func TestSetArrayNew(t *testing.T) {
|
|||
func TestSetExisting(t *testing.T) {
|
||||
branch := TreeBranch{
|
||||
TreeItem{
|
||||
Key: "foo",
|
||||
Key: "foo",
|
||||
Value: "foobar",
|
||||
},
|
||||
}
|
||||
|
@ -407,7 +454,7 @@ func TestSetExisting(t *testing.T) {
|
|||
func TestSetArrayLeafNewItem(t *testing.T) {
|
||||
branch := TreeBranch{
|
||||
TreeItem{
|
||||
Key: "array",
|
||||
Key: "array",
|
||||
Value: []interface{}{},
|
||||
},
|
||||
}
|
||||
|
@ -438,7 +485,7 @@ func TestSetArrayNonLeaf(t *testing.T) {
|
|||
Value: []interface{}{
|
||||
TreeBranch{
|
||||
TreeItem{
|
||||
Key: "hello",
|
||||
Key: "hello",
|
||||
Value: "hello",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -42,6 +42,7 @@ type Metadata struct {
|
|||
MessageAuthenticationCode string `yaml:"mac" json:"mac"`
|
||||
PGPKeys []pgpkey `yaml:"pgp" json:"pgp"`
|
||||
UnencryptedSuffix string `yaml:"unencrypted_suffix" json:"unencrypted_suffix"`
|
||||
EncryptedSuffix string `yaml:"encrypted_suffix,omitempty" json:"encrypted_suffix,omitempty"`
|
||||
Version string `yaml:"version" json:"version"`
|
||||
}
|
||||
|
||||
|
@ -76,6 +77,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata {
|
|||
var m Metadata
|
||||
m.LastModified = sopsMetadata.LastModified.Format(time.RFC3339)
|
||||
m.UnencryptedSuffix = sopsMetadata.UnencryptedSuffix
|
||||
m.EncryptedSuffix = sopsMetadata.EncryptedSuffix
|
||||
m.MessageAuthenticationCode = sopsMetadata.MessageAuthenticationCode
|
||||
m.Version = sopsMetadata.Version
|
||||
m.ShamirThreshold = sopsMetadata.ShamirThreshold
|
||||
|
@ -159,6 +161,7 @@ func (m *Metadata) ToInternal() (sops.Metadata, error) {
|
|||
Version: m.Version,
|
||||
MessageAuthenticationCode: m.MessageAuthenticationCode,
|
||||
UnencryptedSuffix: m.UnencryptedSuffix,
|
||||
EncryptedSuffix: m.EncryptedSuffix,
|
||||
LastModified: lastModified,
|
||||
}, nil
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче