Add KMS encryption context support

Fixes #93
This commit is contained in:
Adrian Utrilla 2016-10-31 16:51:43 +01:00
Родитель 17132124e8
Коммит 3fa7cc43f1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 6BA64E6212CDEBE9
6 изменённых файлов: 44 добавлений и 18 удалений

Просмотреть файл

@ -150,6 +150,10 @@ func main() {
Name: "config",
Usage: "path to sops' config file. If set, sops will not search for the config file recursively.",
},
cli.StringFlag{
Name: "encryption-context",
Usage: "comma separated list of KMS encryption context key:value pairs",
},
}
app.Action = func(c *cli.Context) error {
if c.NArg() < 1 {
@ -304,9 +308,9 @@ func decrypt(c *cli.Context, file string, fileBytes []byte, output io.Writer) er
func getKeysources(c *cli.Context, file string) ([]sops.KeySource, error) {
var kmsKeys []sops.MasterKey
var pgpKeys []sops.MasterKey
kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context"))
if c.String("kms") != "" {
for _, k := range kms.MasterKeysFromArnString(c.String("kms")) {
for _, k := range kms.MasterKeysFromArnString(c.String("kms"), kmsEncryptionContext) {
kmsKeys = append(kmsKeys, k)
}
}
@ -329,7 +333,7 @@ func getKeysources(c *cli.Context, file string) ([]sops.KeySource, error) {
for _, k := range pgp.MasterKeysFromFingerprintString(pgpString) {
pgpKeys = append(pgpKeys, k)
}
for _, k := range kms.MasterKeysFromArnString(kmsString) {
for _, k := range kms.MasterKeysFromArnString(kmsString, kmsEncryptionContext) {
kmsKeys = append(kmsKeys, k)
}
}
@ -387,7 +391,8 @@ func rotate(c *cli.Context, file string, fileBytes []byte, output io.Writer) err
if err != nil {
return cli.NewExitError(fmt.Sprintf("Error encrypting tree: %s", err), exitErrorEncryptingTree)
}
tree.Metadata.AddKMSMasterKeys(c.String("add-kms"))
kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context"))
tree.Metadata.AddKMSMasterKeys(c.String("add-kms"), kmsEncryptionContext)
tree.Metadata.AddPGPMasterKeys(c.String("add-pgp"))
tree.Metadata.RemoveKMSMasterKeys(c.String("rm-kms"))
tree.Metadata.RemovePGPMasterKeys(c.String("rm-pgp"))

Просмотреть файл

@ -274,6 +274,7 @@ func (store Store) kmsEntries(in []interface{}) (sops.KeySource, error) {
if err != nil {
return keysource, fmt.Errorf("Could not parse creation date: %s", err)
}
key.EncryptionContext = kms.ParseKMSContext(entry["context"].(string))
key.CreationDate = creationDate
keysource.Keys = append(keysource.Keys, key)
}

Просмотреть файл

@ -20,10 +20,11 @@ var kmsSvc kmsiface.KMSAPI
// MasterKey is a AWS KMS key used to encrypt and decrypt sops' data key.
type MasterKey struct {
Arn string
Role string
EncryptedKey string
CreationDate time.Time
Arn string
Role string
EncryptedKey string
CreationDate time.Time
EncryptionContext map[string]*string
}
// Encrypt takes a sops data key, encrypts it with KMS and stores the result in the EncryptedKey field
@ -36,7 +37,7 @@ func (key *MasterKey) Encrypt(dataKey []byte) error {
}
kmsSvc = kms.New(sess)
}
out, err := kmsSvc.Encrypt(&kms.EncryptInput{Plaintext: dataKey, KeyId: &key.Arn})
out, err := kmsSvc.Encrypt(&kms.EncryptInput{Plaintext: dataKey, KeyId: &key.Arn, EncryptionContext: key.EncryptionContext})
if err != nil {
return err
}
@ -44,7 +45,7 @@ func (key *MasterKey) Encrypt(dataKey []byte) error {
return nil
}
// EncryptIfNeeded encrypts the provided sops' data ket and encrypts it if it hasn't been encrypted yet
// EncryptIfNeeded encrypts the provided sops' data key and encrypts it if it hasn't been encrypted yet
func (key *MasterKey) EncryptIfNeeded(dataKey []byte) error {
if key.EncryptedKey == "" {
return key.Encrypt(dataKey)
@ -65,7 +66,7 @@ func (key *MasterKey) Decrypt() ([]byte, error) {
}
kmsSvc = kms.New(sess)
}
decrypted, err := kmsSvc.Decrypt(&kms.DecryptInput{CiphertextBlob: k})
decrypted, err := kmsSvc.Decrypt(&kms.DecryptInput{CiphertextBlob: k, EncryptionContext: key.EncryptionContext})
if err != nil {
return nil, fmt.Errorf("Error decrypting key: %v", err)
}
@ -83,7 +84,7 @@ func (key *MasterKey) ToString() string {
}
// NewMasterKeyFromArn takes an ARN string and returns a new MasterKey for that ARN
func NewMasterKeyFromArn(arn string) *MasterKey {
func NewMasterKeyFromArn(arn string, context map[string]*string) *MasterKey {
k := &MasterKey{}
arn = strings.Replace(arn, " ", "", -1)
roleIndex := strings.Index(arn, "+arn:aws:iam::")
@ -93,18 +94,19 @@ func NewMasterKeyFromArn(arn string) *MasterKey {
} else {
k.Arn = arn
}
k.EncryptionContext = context
k.CreationDate = time.Now().UTC()
return k
}
// MasterKeysFromArnString takes a comma separated list of AWS KMS ARNs and returns a slice of new MasterKeys for those ARNs
func MasterKeysFromArnString(arn string) []*MasterKey {
func MasterKeysFromArnString(arn string, context map[string]*string) []*MasterKey {
var keys []*MasterKey
if arn == "" {
return keys
}
for _, s := range strings.Split(arn, ",") {
keys = append(keys, NewMasterKeyFromArn(s))
keys = append(keys, NewMasterKeyFromArn(s, context))
}
return keys
}
@ -156,5 +158,22 @@ 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
for k, v := range key.EncryptionContext {
outContexts = append(outContexts, k+":"+*v)
}
out["context"] = strings.Join(outContexts, ",")
}
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 {
out := make(map[string]*string)
for _, kv := range strings.Split(in, ",") {
kv := strings.Split(kv, ":")
out[kv[0]] = &kv[1]
}
return out
}

Просмотреть файл

@ -49,7 +49,7 @@ func TestKMS(t *testing.T) {
func TestKMSKeySourceFromString(t *testing.T) {
s := "arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e+arn:aws:iam::927034868273:role/sops-dev, arn:aws:kms:ap-southeast-1:656532927350:key/9006a8aa-0fa6-4c14-930e-a2dfb916de1d"
ks := MasterKeysFromArnString(s)
ks := MasterKeysFromArnString(s, nil)
k1 := ks[0]
k2 := ks[1]
expectedArn1 := "arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e"

Просмотреть файл

@ -308,11 +308,11 @@ func (m *Metadata) AddPGPMasterKeys(pgpFps string) {
}
// AddKMSMasterKeys parses the input comma separated string of AWS KMS ARNs, generates a KMS MasterKey for each ARN, and then adds the keys to the KMS KeySource
func (m *Metadata) AddKMSMasterKeys(kmsArns string) {
func (m *Metadata) AddKMSMasterKeys(kmsArns string, context map[string]*string) {
for i, ks := range m.KeySources {
if ks.Name == "kms" {
var keys []MasterKey
for _, k := range kms.MasterKeysFromArnString(kmsArns) {
for _, k := range kms.MasterKeysFromArnString(kmsArns, context) {
keys = append(keys, k)
}
ks.Keys = append(ks.Keys, keys...)
@ -333,7 +333,7 @@ func (m *Metadata) RemovePGPMasterKeys(pgpFps string) {
// RemoveKMSMasterKeys takes a comma separated string of AWS KMS ARNs and removes the keys corresponding to those ARNs from the metadata's KeySources
func (m *Metadata) RemoveKMSMasterKeys(arns string) {
var keys []MasterKey
for _, k := range kms.MasterKeysFromArnString(arns) {
for _, k := range kms.MasterKeysFromArnString(arns, nil) {
keys = append(keys, k)
}
m.RemoveMasterKeys(keys)

Просмотреть файл

@ -200,6 +200,7 @@ func (store *Store) kmsEntries(in []interface{}) (sops.KeySource, error) {
return keysource, fmt.Errorf("Could not parse creation date: %s", err)
}
key.CreationDate = creationDate
key.EncryptionContext = kms.ParseKMSContext(entry["context"].(string))
keysource.Keys = append(keysource.Keys, key)
}
return keysource, nil