Use KeyService for all encrypt and decrypt operations

This commit is contained in:
Adrian Utrilla 2017-08-17 09:36:22 -07:00
Родитель 745a0631ba
Коммит 10dd9b5441
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 6BA64E6212CDEBE9
6 изменённых файлов: 110 добавлений и 23 удалений

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

@ -4,6 +4,8 @@ package keys
type MasterKey interface {
Encrypt(dataKey []byte) error
EncryptIfNeeded(dataKey []byte) error
EncryptedDataKey() []byte
SetEncryptedDataKey([]byte)
Decrypt() ([]byte, error)
NeedsRotation() bool
ToString() string

38
keyservice/keyservice.go Normal file
Просмотреть файл

@ -0,0 +1,38 @@
package keyservice
import (
"fmt"
"go.mozilla.org/sops/keys"
"go.mozilla.org/sops/kms"
"go.mozilla.org/sops/pgp"
)
func KeyFromMasterKey(mk keys.MasterKey) Key {
switch mk := mk.(type) {
case *pgp.MasterKey:
return Key{
KeyType: &Key_GpgKey{
GpgKey: &GpgKey{
Fingerprint: mk.Fingerprint,
},
},
}
case *kms.MasterKey:
var ctx map[string]string
for k, v := range mk.EncryptionContext {
ctx[k] = *v
}
return Key{
KeyType: &Key_KmsKey{
KmsKey: &KmsKey{
Arn: mk.Arn,
Role: mk.Role,
Context: ctx,
},
},
}
default:
panic(fmt.Sprintf("Tried to convert unknown MasterKey type %T to keyservice.Key", mk))
}
}

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

@ -87,7 +87,6 @@ func (ks Server) Encrypt(ctx context.Context,
func (ks Server) Decrypt(ctx context.Context,
req *DecryptRequest) (*DecryptResponse, error) {
key := *req.Key
switch k := key.KeyType.(type) {
case *Key_GpgKey:

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

@ -31,6 +31,14 @@ type MasterKey struct {
EncryptionContext map[string]*string
}
func (key *MasterKey) EncryptedDataKey() []byte {
return []byte(key.EncryptedKey)
}
func (key *MasterKey) SetEncryptedDataKey(enc []byte) {
key.EncryptedKey = string(enc)
}
// Encrypt takes a sops data key, encrypts it with KMS and stores the result in the EncryptedKey field
func (key *MasterKey) Encrypt(dataKey []byte) error {
// isMocked is set by unit test to indicate that the KMS service

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

@ -24,6 +24,14 @@ type MasterKey struct {
CreationDate time.Time
}
func (key *MasterKey) EncryptedDataKey() []byte {
return []byte(key.EncryptedKey)
}
func (key *MasterKey) SetEncryptedDataKey(enc []byte) {
key.EncryptedKey = string(enc)
}
// Encrypt encrypts the data key with the PGP key with the same fingerprint as the MasterKey. It looks for PGP public keys in $PGPHOME/pubring.gpg.
func (key *MasterKey) Encrypt(dataKey []byte) error {
ring, err := key.pubRing()

76
sops.go
Просмотреть файл

@ -44,8 +44,10 @@ import (
"time"
"go.mozilla.org/sops/keys"
"go.mozilla.org/sops/keyservice"
"go.mozilla.org/sops/kms"
"go.mozilla.org/sops/pgp"
"golang.org/x/net/context"
)
// DefaultUnencryptedSuffix is the default suffix a TreeItem key has to end with for sops to leave its Value unencrypted
@ -348,19 +350,39 @@ func (m *Metadata) UpdateMasterKeysIfNeeded(dataKey []byte) (errs []error) {
return
}
// UpdateMasterKeys encrypts the data key with all master keys
func (m *Metadata) UpdateMasterKeys(dataKey []byte) (errs []error) {
for _, ks := range m.KeySources {
for _, k := range ks.Keys {
err := k.Encrypt(dataKey)
if err != nil {
errs = append(errs, fmt.Errorf("Failed to encrypt new data key with master key %q: %v\n", k.ToString(), err))
func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyservice.KeyServiceServer) (errs []error) {
if len(svcs) == 0 {
return []error{
fmt.Errorf("No key services provided, can not update master keys."),
}
}
for _, keysource := range m.KeySources {
for _, key := range keysource.Keys {
svcKey := keyservice.KeyFromMasterKey(key)
for _, svc := range svcs {
rsp, err := svc.Encrypt(context.Background(), &keyservice.EncryptRequest{
Key: &svcKey,
Plaintext: dataKey,
})
if err != nil {
errs = append(errs, fmt.Errorf("Failed to encrypt new data key with master key %q: %v\n", key.ToString(), err))
}
key.SetEncryptedDataKey(rsp.Ciphertext)
// Only need to encrypt the key successfully with one service
break
}
}
}
return
}
// UpdateMasterKeys encrypts the data key with all master keys
func (m *Metadata) UpdateMasterKeys(dataKey []byte) (errs []error) {
return m.UpdateMasterKeysWithKeyServices(dataKey, []keyservice.KeyServiceServer{
keyservice.Server{},
})
}
// AddPGPMasterKeys parses the input comma separated string of GPG fingerprints, generates a PGP MasterKey for each fingerprint, and adds the keys to the PGP KeySource
func (m *Metadata) AddPGPMasterKeys(pgpFps string) {
for i, ks := range m.KeySources {
@ -426,25 +448,35 @@ func (m *Metadata) ToMap() map[string]interface{} {
return out
}
// GetDataKey retrieves the data key from the first MasterKey in the Metadata's KeySources that's able to return it.
func (m Metadata) GetDataKey() ([]byte, error) {
// GetDataKeyWithKeyServices retrieves the data key, asking KeyServices to decrypt it with each
// MasterKey in the Metadata's KeySources until one of them succeeds.
func (m Metadata) GetDataKeyWithKeyServices(svcs []keyservice.KeyServiceServer) ([]byte, error) {
errMsg := "Could not decrypt the data key with any of the master keys:\n"
for _, ks := range m.KeySources {
for _, k := range ks.Keys {
key, err := k.Decrypt()
if err == nil {
return key, nil
for _, keysource := range m.KeySources {
for _, key := range keysource.Keys {
svcKey := keyservice.KeyFromMasterKey(key)
for _, svc := range svcs {
rsp, err := svc.Decrypt(
context.Background(),
&keyservice.DecryptRequest{
Ciphertext: key.EncryptedDataKey(),
Key: &svcKey,
})
if err != nil {
errMsg += fmt.Sprintf("\t%s: %s", key.ToString(), err)
continue
}
return rsp.Plaintext, nil
}
keyType := "Unknown"
if _, ok := k.(*pgp.MasterKey); ok {
keyType = "GPG"
} else if _, ok := k.(*kms.MasterKey); ok {
keyType = "KMS"
}
errMsg += fmt.Sprintf("\t[%s]: %s:\t%s\n", keyType, k.ToString(), err)
}
}
return nil, fmt.Errorf(errMsg)
return nil, fmt.Errorf("%s", errMsg)
}
// GetDataKey retrieves the data key from the first MasterKey in the Metadata's KeySources that's able to return it,
// using the local KeyService
func (m Metadata) GetDataKey() ([]byte, error) {
return m.GetDataKeyWithKeyServices([]keyservice.KeyServiceServer{keyservice.Server{}})
}
// ToBytes converts a string, int, float or bool to a byte representation.