зеркало из https://github.com/getsops/sops.git
Fix KMS encryption context for backwards compatibility with SOPS 1.x
In SOPS 1.x, KMS encryption context was stored as a JSON object, but SOPS 2.0 stored it as a comma-separated list of key/value pairs: ``` $ jq '.sops.kms | .[].context' encrypted-python { "a": "b", "c": "d" } > jq '.sops.kms | .[].context' encrypted-go "a:b,c:d" ``` The two outputs are incompatible with each other and caused a stack trace when reading files encrypted with SOPS 1.x. This patch restores read and output compatibility with SOPS 1.x. Fixes #190.
This commit is contained in:
Родитель
176f2baba5
Коммит
89e75471cc
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -162,8 +161,8 @@ func (key MasterKey) createSession() (*session.Session, error) {
|
|||
}
|
||||
|
||||
// ToMap converts the MasterKey to a map for serialization purposes
|
||||
func (key MasterKey) ToMap() map[string]string {
|
||||
out := make(map[string]string)
|
||||
func (key MasterKey) ToMap() map[string]interface{} {
|
||||
out := make(map[string]interface{})
|
||||
out["arn"] = key.Arn
|
||||
if key.Role != "" {
|
||||
out["role"] = key.Role
|
||||
|
@ -171,28 +170,47 @@ func (key MasterKey) ToMap() map[string]string {
|
|||
out["created_at"] = key.CreationDate.UTC().Format(time.RFC3339)
|
||||
out["enc"] = key.EncryptedKey
|
||||
if key.EncryptionContext != nil {
|
||||
var outContexts []string
|
||||
outcontext := make(map[string]string)
|
||||
for k, v := range key.EncryptionContext {
|
||||
outContexts = append(outContexts, k+":"+*v)
|
||||
outcontext[k] = *v
|
||||
}
|
||||
sort.Strings(outContexts)
|
||||
out["context"] = strings.Join(outContexts, ",")
|
||||
out["context"] = outcontext
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ParseKMSContext takes a comma-separated list of KMS context key:value pairs and returns a map
|
||||
func ParseKMSContext(in string) map[string]*string {
|
||||
if in == "" {
|
||||
return nil
|
||||
}
|
||||
// ParseKMSContext takes either a KMS context map or a comma-separated list of KMS context key:value pairs and returns a map
|
||||
func ParseKMSContext(in interface{}) map[string]*string {
|
||||
out := make(map[string]*string)
|
||||
for _, kv := range strings.Split(in, ",") {
|
||||
kv := strings.Split(kv, ":")
|
||||
if len(kv) != 2 {
|
||||
|
||||
switch in := in.(type) {
|
||||
case map[string]interface{}:
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
out[kv[0]] = &kv[1]
|
||||
for k, v := range in {
|
||||
var v = v.(string)
|
||||
out[k] = &v
|
||||
}
|
||||
case map[interface{}]interface{}:
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
for k, v := range in {
|
||||
var v = v.(string)
|
||||
out[k.(string)] = &v
|
||||
}
|
||||
case string:
|
||||
if in == "" {
|
||||
return nil
|
||||
}
|
||||
for _, kv := range strings.Split(in, ",") {
|
||||
kv := strings.Split(kv, ":")
|
||||
if len(kv) != 2 {
|
||||
return nil
|
||||
}
|
||||
out[kv[0]] = &kv[1]
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
|
@ -73,6 +73,27 @@ func TestKMSKeySourceFromString(t *testing.T) {
|
|||
func TestParseEncryptionContext(t *testing.T) {
|
||||
value1 := "value1"
|
||||
value2 := "value2"
|
||||
// map from YAML
|
||||
var yamlmap = map[interface{}]interface{}{
|
||||
"key1": value1,
|
||||
"key2": value2,
|
||||
}
|
||||
assert.Equal(t, ParseKMSContext(yamlmap), map[string]*string{
|
||||
"key1": &value1,
|
||||
"key2": &value2,
|
||||
})
|
||||
assert.Nil(t, ParseKMSContext(map[interface{}]interface{}{}))
|
||||
// map from JSON
|
||||
var jsonmap = map[string]interface{}{
|
||||
"key1": value1,
|
||||
"key2": value2,
|
||||
}
|
||||
assert.Equal(t, ParseKMSContext(jsonmap), map[string]*string{
|
||||
"key1": &value1,
|
||||
"key2": &value2,
|
||||
})
|
||||
assert.Nil(t, ParseKMSContext(map[string]interface{}{}))
|
||||
// sops 2.0.x formatted encryption context as a comma-separated list of key:value pairs
|
||||
assert.Equal(t, ParseKMSContext("key1:value1,key2:value2"), map[string]*string{
|
||||
"key1": &value1,
|
||||
"key2": &value2,
|
||||
|
@ -87,7 +108,6 @@ func TestParseEncryptionContext(t *testing.T) {
|
|||
func TestKeyToMap(t *testing.T) {
|
||||
value1 := "value1"
|
||||
value2 := "value2"
|
||||
value3 := "value3"
|
||||
key := MasterKey{
|
||||
CreationDate: time.Date(2016, time.October, 31, 10, 0, 0, 0, time.UTC),
|
||||
Arn: "foo",
|
||||
|
@ -96,14 +116,16 @@ func TestKeyToMap(t *testing.T) {
|
|||
EncryptionContext: map[string]*string{
|
||||
"key1": &value1,
|
||||
"key2": &value2,
|
||||
"AAA_this_key_should_be_first": &value3,
|
||||
},
|
||||
}
|
||||
assert.Equal(t, map[string]string{
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"arn": "foo",
|
||||
"role": "bar",
|
||||
"enc": "this is encrypted",
|
||||
"created_at": "2016-10-31T10:00:00Z",
|
||||
"context": "AAA_this_key_should_be_first:value3,key1:value1,key2:value2",
|
||||
"context": map[string]string{
|
||||
"key1": value1,
|
||||
"key2": value2,
|
||||
},
|
||||
}, key.ToMap())
|
||||
}
|
||||
|
|
|
@ -201,8 +201,8 @@ func (key *MasterKey) passphrasePrompt(keys []openpgp.Key, symmetric bool) ([]by
|
|||
}
|
||||
|
||||
// ToMap converts the MasterKey into a map for serialization purposes
|
||||
func (key MasterKey) ToMap() map[string]string {
|
||||
out := make(map[string]string)
|
||||
func (key MasterKey) ToMap() map[string]interface{} {
|
||||
out := make(map[string]interface{})
|
||||
out["fp"] = key.Fingerprint
|
||||
out["created_at"] = key.CreationDate.UTC().Format(time.RFC3339)
|
||||
out["enc"] = key.EncryptedKey
|
||||
|
|
6
sops.go
6
sops.go
|
@ -303,7 +303,7 @@ type MasterKey interface {
|
|||
Decrypt() ([]byte, error)
|
||||
NeedsRotation() bool
|
||||
ToString() string
|
||||
ToMap() map[string]string
|
||||
ToMap() map[string]interface{}
|
||||
}
|
||||
|
||||
// Store provides a way to load and save the sops tree along with metadata
|
||||
|
@ -426,7 +426,7 @@ func (m *Metadata) ToMap() map[string]interface{} {
|
|||
out["mac"] = m.MessageAuthenticationCode
|
||||
out["version"] = m.Version
|
||||
for _, ks := range m.KeySources {
|
||||
var keys []map[string]string
|
||||
var keys []map[string]interface{}
|
||||
for _, k := range ks.Keys {
|
||||
keys = append(keys, k.ToMap())
|
||||
}
|
||||
|
@ -550,7 +550,7 @@ func mapKMSEntriesToKeySource(in []interface{}) (KeySource, error) {
|
|||
return keysource, fmt.Errorf("Could not parse creation date: %s", err)
|
||||
}
|
||||
if _, ok := entry["context"]; ok {
|
||||
key.EncryptionContext = kms.ParseKMSContext(entry["context"].(string))
|
||||
key.EncryptionContext = kms.ParseKMSContext(entry["context"])
|
||||
}
|
||||
key.CreationDate = creationDate
|
||||
keysource.Keys = append(keysource.Keys, key)
|
||||
|
|
Загрузка…
Ссылка в новой задаче