1
0
mirror of https://github.com/getsops/sops.git synced 2026-02-05 12:45:21 +01:00

Add support for Azure Key Vault

This commit is contained in:
Calle Pettersson
2018-06-17 22:50:30 +02:00
parent 3265a66cd3
commit 9fa4f0e90e
10 changed files with 582 additions and 56 deletions

View File

@@ -30,9 +30,12 @@ test:
showcoverage: test
$(GO) tool cover -html=coverage.out
generate:
generate: keyservice/keyservice.pb.go
$(GO) generate
%.pb.go: %.proto
protoc --go_out=plugins=grpc:. $<
functional-tests:
$(GO) build -o functional-tests/sops go.mozilla.org/sops/cmd/sops
cd functional-tests && cargo test

187
azkv/keysource.go Normal file
View File

@@ -0,0 +1,187 @@
/*
Package azkv contains an implementation of the go.mozilla.org/sops/keys.MasterKey interface that encrypts and decrypts the
data key using Azure Key Vault with the Azure Go SDK.
*/
package azkv //import "go.mozilla.org/sops/azkv"
import (
"context"
"encoding/base64"
"fmt"
"regexp"
"strings"
"time"
"go.mozilla.org/sops/logging"
"github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault"
"github.com/Azure/azure-sdk-for-go/services/keyvault/auth"
"github.com/sirupsen/logrus"
)
var log *logrus.Logger
func init() {
log = logging.NewLogger("AZKV")
}
// MasterKey is a Azure Key Vault key used to encrypt and decrypt sops' data key.
type MasterKey struct {
VaultURL string
Name string
Version string
EncryptedKey string
CreationDate time.Time
}
func newKeyVaultClient() (keyvault.BaseClient, error) {
var err error
c := keyvault.New()
c.Authorizer, err = auth.NewAuthorizerFromEnvironment()
if err != nil {
log.WithError(err).Error("Failed to create Azure authorizer")
return c, err
}
return c, nil
}
// NewMasterKey creates a new MasterKey from an URL, key name and version, setting the creation date to the current date
func NewMasterKey(vaultURL string, keyName string, keyVersion string) *MasterKey {
return &MasterKey{
VaultURL: vaultURL,
Name: keyName,
Version: keyVersion,
CreationDate: time.Now().UTC(),
}
}
// MasterKeysFromURLs takes a comma separated list of Azure Key Vault URLs and returns a slice of new MasterKeys for them
func MasterKeysFromURLs(urls string) []*MasterKey {
var keys []*MasterKey
if urls == "" {
return keys
}
for _, s := range strings.Split(urls, ",") {
keys = append(keys, NewMasterKeyFromURL(s))
}
return keys
}
// NewMasterKeyFromResourceID takes an Azure Key Vault key URL and returns a new MasterKey
// URL format is {vaultUrl}/keys/{key-name}/{key-version}
func NewMasterKeyFromURL(url string) *MasterKey {
k := &MasterKey{}
re := regexp.MustCompile("^(https://[^/]+)/keys/([^/]+)/([^/]+)$")
parts := re.FindStringSubmatch(url)
if parts == nil || len(parts) < 2 {
log.Error("No match!")
// !?
}
k.VaultURL = parts[1]
k.Name = parts[2]
k.Version = parts[3]
k.CreationDate = time.Now().UTC()
return k
}
// EncryptedDataKey returns the encrypted data key this master key holds
func (key *MasterKey) EncryptedDataKey() []byte {
return []byte(key.EncryptedKey)
}
// SetEncryptedDataKey sets the encrypted data key for this master key
func (key *MasterKey) SetEncryptedDataKey(enc []byte) {
key.EncryptedKey = string(enc)
}
// Encrypt takes a sops data key, encrypts it with Key Vault and stores the result in the EncryptedKey field
func (key *MasterKey) Encrypt(dataKey []byte) error {
c, err := newKeyVaultClient()
if err != nil {
return err
}
data := base64.RawURLEncoding.EncodeToString(dataKey)
p := keyvault.KeyOperationsParameters{Value: &data, Algorithm: keyvault.RSAOAEP256}
res, err := c.Encrypt(context.Background(), key.VaultURL, key.Name, key.Version, p)
if err != nil {
log.WithError(err).WithFields(logrus.Fields{
"key": key.Name,
"version": key.Version,
}).Error("Encryption failed")
return fmt.Errorf("Failed to encrypt data: %v", err)
}
key.EncryptedKey = *res.Result
log.WithFields(logrus.Fields{
"key": key.Name,
"version": key.Version,
}).Info("Encryption succeeded")
return nil
}
// 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)
}
return nil
}
// Decrypt decrypts the EncryptedKey field with Azure Key Vault and returns the result.
func (key *MasterKey) Decrypt() ([]byte, error) {
c, err := newKeyVaultClient()
if err != nil {
return nil, err
}
p := keyvault.KeyOperationsParameters{Value: &key.EncryptedKey, Algorithm: keyvault.RSAOAEP256}
res, err := c.Decrypt(context.TODO(), key.VaultURL, key.Name, key.Version, p)
if err != nil {
log.WithError(err).WithFields(logrus.Fields{
"key": key.Name,
"version": key.Version,
}).Error("Decryption failed")
return nil, fmt.Errorf("Error decrypting key: %v", err)
}
plaintext, err := base64.RawURLEncoding.DecodeString(*res.Result)
if err != nil {
log.WithError(err).WithFields(logrus.Fields{
"key": key.Name,
"version": key.Version,
}).Error("Decryption failed")
return nil, err
}
log.WithFields(logrus.Fields{
"key": key.Name,
"version": key.Version,
}).Info("Decryption succeeded")
return plaintext, nil
}
// NeedsRotation returns whether the data key needs to be rotated or not.
func (key *MasterKey) NeedsRotation() bool {
return time.Since(key.CreationDate) > (time.Hour * 24 * 30 * 6)
}
// ToString converts the key to a string representation
func (key *MasterKey) ToString() string {
return fmt.Sprintf("%s/keys/%s/%s", key.VaultURL, key.Name, key.Version)
}
// ToMap converts the MasterKey to a map for serialization purposes
func (key MasterKey) ToMap() map[string]interface{} {
out := make(map[string]interface{})
out["vaultUrl"] = key.VaultURL
out["key"] = key.Name
out["version"] = key.Version
out["created_at"] = key.CreationDate.UTC().Format(time.RFC3339)
out["enc"] = key.EncryptedKey
return out
}

102
azkv/keysource_test.go Normal file
View File

@@ -0,0 +1,102 @@
package azkv
import (
"flag"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestAzureKeySourceFromUrl(t *testing.T) {
cases := []struct {
name string
input string
expectedFoundKeys int
expectedKeys []MasterKey
}{
{
name: "Single url",
input: "https://test.vault.azure.net/keys/test-key/a2a690a4fcc04166b739da342a912c90",
expectedFoundKeys: 1,
expectedKeys: []MasterKey{
{
VaultURL: "https://test.vault.azure.net",
Name: "test-key",
Version: "a2a690a4fcc04166b739da342a912c90",
},
},
},
{
name: "Multiple url",
input: "https://test.vault.azure.net/keys/test-key/a2a690a4fcc04166b739da342a912c90,https://test2.vault.azure.net/keys/another-test-key/cf0021e8b743453bae758e7fbf71b60e",
expectedFoundKeys: 2,
expectedKeys: []MasterKey{
{
VaultURL: "https://test.vault.azure.net",
Name: "test-key",
Version: "a2a690a4fcc04166b739da342a912c90",
},
{
VaultURL: "https://test2.vault.azure.net",
Name: "another-test-key",
Version: "cf0021e8b743453bae758e7fbf71b60e",
},
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
keys := MasterKeysFromURLs(c.input)
if c.expectedFoundKeys != len(keys) {
t.Errorf("Unexpected number of keys returned, expected %d, got %d", c.expectedFoundKeys, len(keys))
}
for idx := range keys {
assert.Equal(t, c.expectedKeys[idx].VaultURL, keys[idx].VaultURL)
assert.Equal(t, c.expectedKeys[idx].Name, keys[idx].Name)
assert.Equal(t, c.expectedKeys[idx].Version, keys[idx].Version)
}
})
}
}
func TestKeyToMap(t *testing.T) {
key := MasterKey{
CreationDate: time.Date(2016, time.October, 31, 10, 0, 0, 0, time.UTC),
VaultURL: "https://test.vault.azure.net",
Name: "test-key",
Version: "1",
EncryptedKey: "this is encrypted",
}
assert.Equal(t, map[string]interface{}{
"vaultUrl": key.VaultURL,
"key": key.Name,
"version": key.Version,
"enc": "this is encrypted",
"created_at": "2016-10-31T10:00:00Z",
}, key.ToMap())
}
var azureKeyAcceptanceTestUrl = flag.String("azure-key", "", "URL to Azure Key Vault (note that this can incur real costs!)")
func TestRoundtrip(t *testing.T) {
if *azureKeyAcceptanceTestUrl == "" {
t.Skip("Azure URL not provided, skipping acceptance test")
}
input := []byte("test-string")
key := NewMasterKeyFromURL(*azureKeyAcceptanceTestUrl)
err := key.Encrypt(input)
if err != nil {
t.Fatal(err)
}
output, err := key.Decrypt()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, input, output)
}

View File

@@ -21,6 +21,7 @@ import (
"github.com/sirupsen/logrus"
"go.mozilla.org/sops/aes"
_ "go.mozilla.org/sops/audit"
"go.mozilla.org/sops/azkv"
"go.mozilla.org/sops/cmd/sops/codes"
"go.mozilla.org/sops/cmd/sops/common"
"go.mozilla.org/sops/cmd/sops/subcommand/groups"
@@ -59,7 +60,7 @@ func main() {
},
}
app.Name = "sops"
app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS and GPG support"
app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS, Azure Key Vault and GPG support"
app.ArgsUsage = "sops [options] file"
app.Version = version
app.Authors = []cli.Author{
@@ -78,6 +79,10 @@ func main() {
(you need to setup google application default credentials. See
https://developers.google.com/identity/protocols/application-default-credentials)
To encrypt or decrypt a document with Azure Key Vault, specify the
Azure Key Vault key URL in the --azure-kv flag or in the SOPS_AZURE_KEYVAULT_URL
environment variable.
To encrypt or decrypt using PGP, specify the PGP fingerprint in the
-p flag or in the SOPS_PGP_FP environment variable.
@@ -88,7 +93,7 @@ func main() {
or decrypting existing documents can be done with "sops file" or
"sops -d file" respectively. The KMS and PGP keys listed in the encrypted
documents are used then. To manage master keys in existing documents, use
the "add-{kms,pgp,gcp-kms}" and "rm-{kms,pgp,gcp-kms}" flags.
the "add-{kms,pgp,gcp-kms,azure-kv}" and "rm-{kms,pgp,gcp-kms,azure-kv}" flags.
To use a different GPG binary than the one in your PATH, set SOPS_GPG_EXEC.
@@ -160,6 +165,10 @@ func main() {
Name: "gcp-kms",
Usage: "the GCP KMS Resource ID the new group should contain. Can be specified more than once",
},
cli.StringSliceFlag{
Name: "azure-kv",
Usage: "the Azure Key Vault key URL the new group should contain. Can be specified more than once",
},
cli.BoolFlag{
Name: "in-place, i",
Usage: "write output back to the same file instead of stdout",
@@ -176,6 +185,7 @@ func main() {
Action: func(c *cli.Context) error {
pgpFps := c.StringSlice("pgp")
kmsArns := c.StringSlice("kms")
azkvs := c.StringSlice("azkv")
var group sops.KeyGroup
for _, fp := range pgpFps {
group = append(group, pgp.NewMasterKeyFromFingerprint(fp))
@@ -183,6 +193,10 @@ func main() {
for _, arn := range kmsArns {
group = append(group, kms.NewMasterKeyFromArn(arn, kms.ParseKMSContext(c.String("encryption-context"))))
}
// NOTE: Why isn't GCP here?
for _, url := range azkvs {
group = append(group, azkv.NewMasterKeyFromURL(url))
}
return groups.Add(groups.AddOpts{
InputPath: c.String("file"),
InPlace: c.Bool("in-place"),
@@ -288,6 +302,11 @@ func main() {
Usage: "comma separated list of GCP KMS resource IDs",
EnvVar: "SOPS_GCP_KMS_IDS",
},
cli.StringFlag{
Name: "azure-kv",
Usage: "comma separated list of Azure Key Vault URLs",
EnvVar: "SOPS_AZURE_KEYVAULT_URLS",
},
cli.StringFlag{
Name: "pgp, p",
Usage: "comma separated list of PGP fingerprints",
@@ -321,6 +340,14 @@ func main() {
Name: "rm-gcp-kms",
Usage: "remove the provided comma-separated list of GCP KMS key resource IDs from the list of master keys on the given file",
},
cli.StringFlag{
Name: "add-azure-kv",
Usage: "add the provided comma-separated list of Azure Key Vault key URLs to the list of master keys on the given file",
},
cli.StringFlag{
Name: "rm-azure-kv",
Usage: "remove the provided comma-separated list of Azure Key Vault key URLs from the list of master keys on the given file",
},
cli.StringFlag{
Name: "add-kms",
Usage: "add the provided comma-separated list of KMS ARNs to the list of master keys on the given file",
@@ -380,7 +407,8 @@ func main() {
}
fileName := c.Args()[0]
if _, err := os.Stat(fileName); os.IsNotExist(err) {
if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" {
if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-azure-kv") != "" ||
c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-azure-kv") != "" {
return common.NewExitError("Error: cannot add or remove keys on non-existent files, use `--kms` and `--pgp` instead.", codes.CannotChangeKeysFromNonExistentFile)
}
if c.Bool("encrypt") || c.Bool("decrypt") || c.Bool("rotate") {
@@ -468,6 +496,9 @@ func main() {
for _, k := range gcpkms.MasterKeysFromResourceIDString(c.String("add-gcp-kms")) {
addMasterKeys = append(addMasterKeys, k)
}
for _, k := range azkv.MasterKeysFromURLs(c.String("add-azure-kv")) {
addMasterKeys = append(addMasterKeys, k)
}
var rmMasterKeys []keys.MasterKey
for _, k := range kms.MasterKeysFromArnString(c.String("rm-kms"), kmsEncryptionContext) {
@@ -479,6 +510,9 @@ func main() {
for _, k := range gcpkms.MasterKeysFromResourceIDString(c.String("rm-gcp-kms")) {
rmMasterKeys = append(rmMasterKeys, k)
}
for _, k := range azkv.MasterKeysFromURLs(c.String("rm-azure-kv")) {
rmMasterKeys = append(rmMasterKeys, k)
}
output, err = rotate(rotateOpts{
OutputStore: outputStore,
InputStore: inputStore,
@@ -673,6 +707,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
var kmsKeys []keys.MasterKey
var pgpKeys []keys.MasterKey
var cloudKmsKeys []keys.MasterKey
var azkvKeys []keys.MasterKey
kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context"))
if c.String("encryption-context") != "" && kmsEncryptionContext == nil {
return nil, common.NewExitError("Invalid KMS encryption context format", codes.ErrorInvalidKMSEncryptionContextFormat)
@@ -687,12 +722,17 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
cloudKmsKeys = append(cloudKmsKeys, k)
}
}
if c.String("azure-kv") != "" {
for _, k := range azkv.MasterKeysFromURLs(c.String("azure-kv")) {
azkvKeys = append(azkvKeys, k)
}
}
if c.String("pgp") != "" {
for _, k := range pgp.MasterKeysFromFingerprintString(c.String("pgp")) {
pgpKeys = append(pgpKeys, k)
}
}
if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" {
if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && c.String("azure-kv") == "" {
conf, err := loadConfig(c, file, kmsEncryptionContext)
// config file might just not be supplied, without any error
if conf == nil {
@@ -707,6 +747,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
var group sops.KeyGroup
group = append(group, kmsKeys...)
group = append(group, cloudKmsKeys...)
group = append(group, azkvKeys...)
group = append(group, pgpKeys...)
return []sops.KeyGroup{group}, nil
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/mozilla-services/yaml"
"github.com/sirupsen/logrus"
"go.mozilla.org/sops"
"go.mozilla.org/sops/azkv"
"go.mozilla.org/sops/gcpkms"
"go.mozilla.org/sops/kms"
"go.mozilla.org/sops/logging"
@@ -63,9 +64,10 @@ type configFile struct {
}
type keyGroup struct {
KMS []kmsKey
GCPKMS []gcpKmsKey `yaml:"gcp_kms"`
PGP []string
KMS []kmsKey
GCPKMS []gcpKmsKey `yaml:"gcp_kms"`
AzureKV []azureKVKey `yaml:"azure_keyvault"`
PGP []string
}
type gcpKmsKey struct {
@@ -78,12 +80,19 @@ type kmsKey struct {
Context map[string]*string `yaml:"context"`
}
type azureKVKey struct {
VaultURL string `yaml:"vaultUrl"`
Key string `yaml:"key"`
Version string `yaml:"version"`
}
type creationRule struct {
FilenameRegex string `yaml:"filename_regex"`
PathRegex string `yaml:"path_regex"`
KMS string
PGP string
GCPKMS string `yaml:"gcp_kms"`
AzureKeyVault string `yaml:"azure_keyvault"`
KeyGroups []keyGroup `yaml:"key_groups"`
ShamirThreshold int `yaml:"shamir_threshold"`
UnencryptedSuffix string `yaml:"unencrypted_suffix"`
@@ -172,6 +181,9 @@ func loadForFileFromBytes(confBytes []byte, filePath string, kmsEncryptionContex
for _, k := range gcpkms.MasterKeysFromResourceIDString(rule.GCPKMS) {
keyGroup = append(keyGroup, k)
}
for _, k := range azkv.MasterKeysFromURLs(rule.AzureKeyVault) {
keyGroup = append(keyGroup, k)
}
groups = append(groups, keyGroup)
}
return &Config{

View File

@@ -7,6 +7,7 @@ package keyservice
import (
"fmt"
"go.mozilla.org/sops/azkv"
"go.mozilla.org/sops/gcpkms"
"go.mozilla.org/sops/keys"
"go.mozilla.org/sops/kms"
@@ -46,6 +47,16 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
},
},
}
case *azkv.MasterKey:
return Key{
KeyType: &Key_AzureKeyvaultKey{
AzureKeyvaultKey: &AzureKeyVaultKey{
VaultUrl: mk.VaultURL,
Name: mk.Name,
Version: mk.Version,
},
},
}
default:
panic(fmt.Sprintf("Tried to convert unknown MasterKey type %T to keyservice.Key", mk))
}

View File

@@ -1,17 +1,18 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: keyservice.proto
// source: keyservice/keyservice.proto
/*
Package keyservice is a generated protocol buffer package.
It is generated from these files:
keyservice.proto
keyservice/keyservice.proto
It has these top-level messages:
Key
PgpKey
KmsKey
GcpKmsKey
AzureKeyVaultKey
EncryptRequest
EncryptResponse
DecryptRequest
@@ -44,6 +45,7 @@ type Key struct {
// *Key_KmsKey
// *Key_PgpKey
// *Key_GcpKmsKey
// *Key_AzureKeyvaultKey
KeyType isKey_KeyType `protobuf_oneof:"key_type"`
}
@@ -65,10 +67,14 @@ type Key_PgpKey struct {
type Key_GcpKmsKey struct {
GcpKmsKey *GcpKmsKey `protobuf:"bytes,3,opt,name=gcp_kms_key,json=gcpKmsKey,oneof"`
}
type Key_AzureKeyvaultKey struct {
AzureKeyvaultKey *AzureKeyVaultKey `protobuf:"bytes,4,opt,name=azure_keyvault_key,json=azureKeyvaultKey,oneof"`
}
func (*Key_KmsKey) isKey_KeyType() {}
func (*Key_PgpKey) isKey_KeyType() {}
func (*Key_GcpKmsKey) isKey_KeyType() {}
func (*Key_KmsKey) isKey_KeyType() {}
func (*Key_PgpKey) isKey_KeyType() {}
func (*Key_GcpKmsKey) isKey_KeyType() {}
func (*Key_AzureKeyvaultKey) isKey_KeyType() {}
func (m *Key) GetKeyType() isKey_KeyType {
if m != nil {
@@ -98,12 +104,20 @@ func (m *Key) GetGcpKmsKey() *GcpKmsKey {
return nil
}
func (m *Key) GetAzureKeyvaultKey() *AzureKeyVaultKey {
if x, ok := m.GetKeyType().(*Key_AzureKeyvaultKey); ok {
return x.AzureKeyvaultKey
}
return nil
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*Key) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _Key_OneofMarshaler, _Key_OneofUnmarshaler, _Key_OneofSizer, []interface{}{
(*Key_KmsKey)(nil),
(*Key_PgpKey)(nil),
(*Key_GcpKmsKey)(nil),
(*Key_AzureKeyvaultKey)(nil),
}
}
@@ -126,6 +140,11 @@ func _Key_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
if err := b.EncodeMessage(x.GcpKmsKey); err != nil {
return err
}
case *Key_AzureKeyvaultKey:
b.EncodeVarint(4<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.AzureKeyvaultKey); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("Key.KeyType has unexpected type %T", x)
@@ -160,6 +179,14 @@ func _Key_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (b
err := b.DecodeMessage(msg)
m.KeyType = &Key_GcpKmsKey{msg}
return true, err
case 4: // key_type.azure_keyvault_key
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(AzureKeyVaultKey)
err := b.DecodeMessage(msg)
m.KeyType = &Key_AzureKeyvaultKey{msg}
return true, err
default:
return false, nil
}
@@ -184,6 +211,11 @@ func _Key_OneofSizer(msg proto.Message) (n int) {
n += proto.SizeVarint(3<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *Key_AzureKeyvaultKey:
s := proto.Size(x.AzureKeyvaultKey)
n += proto.SizeVarint(4<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
@@ -255,6 +287,38 @@ func (m *GcpKmsKey) GetResourceId() string {
return ""
}
type AzureKeyVaultKey struct {
VaultUrl string `protobuf:"bytes,1,opt,name=vault_url,json=vaultUrl" json:"vault_url,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
Version string `protobuf:"bytes,3,opt,name=version" json:"version,omitempty"`
}
func (m *AzureKeyVaultKey) Reset() { *m = AzureKeyVaultKey{} }
func (m *AzureKeyVaultKey) String() string { return proto.CompactTextString(m) }
func (*AzureKeyVaultKey) ProtoMessage() {}
func (*AzureKeyVaultKey) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *AzureKeyVaultKey) GetVaultUrl() string {
if m != nil {
return m.VaultUrl
}
return ""
}
func (m *AzureKeyVaultKey) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *AzureKeyVaultKey) GetVersion() string {
if m != nil {
return m.Version
}
return ""
}
type EncryptRequest struct {
Key *Key `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"`
Plaintext []byte `protobuf:"bytes,2,opt,name=plaintext,proto3" json:"plaintext,omitempty"`
@@ -263,7 +327,7 @@ type EncryptRequest struct {
func (m *EncryptRequest) Reset() { *m = EncryptRequest{} }
func (m *EncryptRequest) String() string { return proto.CompactTextString(m) }
func (*EncryptRequest) ProtoMessage() {}
func (*EncryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (*EncryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *EncryptRequest) GetKey() *Key {
if m != nil {
@@ -286,7 +350,7 @@ type EncryptResponse struct {
func (m *EncryptResponse) Reset() { *m = EncryptResponse{} }
func (m *EncryptResponse) String() string { return proto.CompactTextString(m) }
func (*EncryptResponse) ProtoMessage() {}
func (*EncryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (*EncryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *EncryptResponse) GetCiphertext() []byte {
if m != nil {
@@ -303,7 +367,7 @@ type DecryptRequest struct {
func (m *DecryptRequest) Reset() { *m = DecryptRequest{} }
func (m *DecryptRequest) String() string { return proto.CompactTextString(m) }
func (*DecryptRequest) ProtoMessage() {}
func (*DecryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (*DecryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
func (m *DecryptRequest) GetKey() *Key {
if m != nil {
@@ -326,7 +390,7 @@ type DecryptResponse struct {
func (m *DecryptResponse) Reset() { *m = DecryptResponse{} }
func (m *DecryptResponse) String() string { return proto.CompactTextString(m) }
func (*DecryptResponse) ProtoMessage() {}
func (*DecryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
func (*DecryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *DecryptResponse) GetPlaintext() []byte {
if m != nil {
@@ -340,6 +404,7 @@ func init() {
proto.RegisterType((*PgpKey)(nil), "PgpKey")
proto.RegisterType((*KmsKey)(nil), "KmsKey")
proto.RegisterType((*GcpKmsKey)(nil), "GcpKmsKey")
proto.RegisterType((*AzureKeyVaultKey)(nil), "AzureKeyVaultKey")
proto.RegisterType((*EncryptRequest)(nil), "EncryptRequest")
proto.RegisterType((*EncryptResponse)(nil), "EncryptResponse")
proto.RegisterType((*DecryptRequest)(nil), "DecryptRequest")
@@ -448,37 +513,42 @@ var _KeyService_serviceDesc = grpc.ServiceDesc{
},
},
Streams: []grpc.StreamDesc{},
Metadata: "keyservice.proto",
Metadata: "keyservice/keyservice.proto",
}
func init() { proto.RegisterFile("keyservice.proto", fileDescriptor0) }
func init() { proto.RegisterFile("keyservice/keyservice.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 405 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xcd, 0xae, 0x93, 0x40,
0x14, 0x2e, 0xe5, 0x4a, 0xe5, 0x70, 0x73, 0x21, 0x93, 0x1b, 0x73, 0xd3, 0x18, 0x6d, 0x66, 0xd5,
0x98, 0x66, 0x8c, 0xb8, 0x31, 0x5d, 0xaa, 0xd5, 0x1a, 0x36, 0x06, 0x1f, 0x80, 0x54, 0x7a, 0x44,
0x02, 0x85, 0x71, 0x98, 0x36, 0xce, 0x13, 0xf8, 0x0e, 0x3e, 0xad, 0x61, 0x18, 0x68, 0xa9, 0x9b,
0xbb, 0x3b, 0xf3, 0xf1, 0xcd, 0xf7, 0x33, 0x1c, 0x08, 0x0a, 0x54, 0x0d, 0x8a, 0x53, 0x9e, 0x22,
0xe3, 0xa2, 0x96, 0x35, 0xfd, 0x63, 0x81, 0x1d, 0xa1, 0x22, 0x14, 0x66, 0xc5, 0xa1, 0x49, 0x0a,
0x54, 0x0f, 0xd6, 0xc2, 0x5a, 0x7a, 0xe1, 0x8c, 0x45, 0x87, 0x26, 0x42, 0xb5, 0x9d, 0xc4, 0x4e,
0xa1, 0xa7, 0x96, 0xc3, 0x33, 0xae, 0x39, 0x53, 0xc3, 0xf9, 0x9a, 0x71, 0xc3, 0xe1, 0x7a, 0x22,
0x2b, 0xf0, 0xb2, 0x94, 0x27, 0xbd, 0x96, 0xad, 0x79, 0xc0, 0x3e, 0xa7, 0x7c, 0x90, 0x73, 0xb3,
0xfe, 0xf0, 0x1e, 0xe0, 0x69, 0x81, 0x2a, 0x91, 0x8a, 0x23, 0x7d, 0x05, 0x4e, 0xa7, 0x46, 0x16,
0xe0, 0xfd, 0xc8, 0xab, 0x0c, 0x05, 0x17, 0x79, 0x25, 0x75, 0x1e, 0x37, 0xbe, 0x84, 0xe8, 0x5f,
0x0b, 0x9c, 0x4e, 0x82, 0x04, 0x60, 0xef, 0x44, 0x65, 0x48, 0xed, 0x48, 0x08, 0xdc, 0x88, 0xba,
0x44, 0x9d, 0xd1, 0x8d, 0xf5, 0x4c, 0x18, 0xcc, 0xd2, 0xba, 0x92, 0xf8, 0x5b, 0x3e, 0xd8, 0x0b,
0x7b, 0xe9, 0x85, 0xf7, 0xa6, 0x1e, 0xfb, 0xd0, 0xc1, 0x9b, 0x4a, 0x0a, 0x15, 0xf7, 0xa4, 0xf9,
0x1a, 0x6e, 0x2f, 0x3f, 0xb4, 0x2e, 0xfd, 0xd3, 0xb8, 0x71, 0x3b, 0x92, 0x7b, 0x78, 0x72, 0xda,
0x95, 0xc7, 0xde, 0xa6, 0x3b, 0xac, 0xa7, 0xef, 0x2c, 0xba, 0x02, 0x77, 0xa8, 0x4b, 0x5e, 0x82,
0x27, 0xb0, 0xa9, 0x8f, 0x22, 0xc5, 0x24, 0xdf, 0x1b, 0x01, 0xe8, 0xa1, 0x2f, 0x7b, 0xfa, 0x09,
0xee, 0x36, 0x55, 0x2a, 0x14, 0x97, 0x31, 0xfe, 0x3a, 0x62, 0x23, 0xc9, 0xb3, 0xb3, 0x97, 0x17,
0xde, 0xb0, 0x08, 0x55, 0xe7, 0xf8, 0x1c, 0x5c, 0x5e, 0xee, 0xf2, 0xae, 0x45, 0xeb, 0x7a, 0x1b,
0x9f, 0x01, 0xfa, 0x06, 0xfc, 0x41, 0xa7, 0xe1, 0x75, 0xd5, 0x20, 0x79, 0x01, 0x90, 0xe6, 0xfc,
0x27, 0x0a, 0x7d, 0xc3, 0xd2, 0x37, 0x2e, 0x10, 0xba, 0x85, 0xbb, 0x8f, 0xf8, 0x28, 0xeb, 0xb1,
0xd2, 0xf4, 0x3f, 0xa5, 0xd7, 0xe0, 0x0f, 0x4a, 0xc6, 0x7c, 0x94, 0xd6, 0xba, 0x4a, 0x1b, 0x96,
0x00, 0x11, 0xaa, 0x6f, 0xdd, 0x2a, 0xb6, 0x7f, 0xc7, 0x64, 0x27, 0x3e, 0x1b, 0xbf, 0xc6, 0x3c,
0x60, 0x57, 0xb5, 0xe8, 0xa4, 0xe5, 0x1b, 0x3b, 0xe2, 0xb3, 0x71, 0x85, 0x79, 0xc0, 0xae, 0x92,
0xd0, 0xc9, 0x77, 0x47, 0xef, 0xfa, 0xdb, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa7, 0xb0, 0x93,
0xf5, 0xff, 0x02, 0x00, 0x00,
// 485 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x4d, 0x6f, 0xd4, 0x30,
0x10, 0x6d, 0x36, 0xcb, 0x6e, 0x33, 0xa9, 0xba, 0xc1, 0xaa, 0xd0, 0x6a, 0x8b, 0x60, 0xe5, 0x53,
0x85, 0x2a, 0x57, 0x2c, 0x17, 0xd4, 0x5b, 0x81, 0x42, 0x51, 0x2e, 0x28, 0x08, 0x6e, 0x68, 0x15,
0xd2, 0x21, 0x44, 0xc9, 0x26, 0xc6, 0x71, 0x22, 0xcc, 0x4f, 0xe1, 0x27, 0xf1, 0xab, 0x90, 0x1d,
0x27, 0xfb, 0xc1, 0x85, 0xdb, 0xf8, 0xf9, 0xcd, 0x9b, 0x79, 0xcf, 0x32, 0x9c, 0xe7, 0xa8, 0x6a,
0x14, 0x6d, 0x96, 0xe0, 0xd5, 0xb6, 0x64, 0x5c, 0x54, 0xb2, 0xa2, 0x7f, 0x1c, 0x70, 0x43, 0x54,
0x84, 0xc2, 0x34, 0xdf, 0xd4, 0xeb, 0x1c, 0xd5, 0xdc, 0x59, 0x3a, 0x17, 0xfe, 0x6a, 0xca, 0xc2,
0x4d, 0x1d, 0xa2, 0xba, 0x3b, 0x8a, 0x26, 0xb9, 0xa9, 0x34, 0x87, 0xa7, 0xdc, 0x70, 0x46, 0x96,
0xf3, 0x21, 0xe5, 0x96, 0xc3, 0x4d, 0x45, 0x2e, 0xc1, 0x4f, 0x13, 0xbe, 0xee, 0xb5, 0x5c, 0xc3,
0x03, 0xf6, 0x2e, 0xe1, 0x83, 0x9c, 0x97, 0xf6, 0x07, 0x72, 0x03, 0x24, 0xfe, 0xd5, 0x08, 0xd4,
0xdc, 0x36, 0x6e, 0x0a, 0x69, 0x9a, 0xc6, 0xa6, 0xe9, 0x21, 0xbb, 0xd1, 0x57, 0x21, 0xaa, 0xcf,
0xfa, 0xa6, 0xeb, 0x0d, 0x62, 0x8b, 0xb5, 0x16, 0x7b, 0x05, 0x70, 0x9c, 0xa3, 0x5a, 0x4b, 0xc5,
0x91, 0x3e, 0x83, 0x49, 0xb7, 0x10, 0x59, 0x82, 0xff, 0x2d, 0x2b, 0x53, 0x14, 0x5c, 0x64, 0xa5,
0x34, 0x96, 0xbc, 0x68, 0x17, 0xa2, 0xbf, 0x1d, 0x98, 0xd8, 0x2d, 0x02, 0x70, 0x63, 0x51, 0x5a,
0x92, 0x2e, 0x09, 0x81, 0xb1, 0xa8, 0x0a, 0x34, 0x36, 0xbd, 0xc8, 0xd4, 0x84, 0xc1, 0x34, 0xa9,
0x4a, 0x89, 0x3f, 0xe5, 0xdc, 0x5d, 0xba, 0x17, 0xfe, 0xea, 0xcc, 0x26, 0xc4, 0x5e, 0x77, 0xf0,
0x6d, 0x29, 0x85, 0x8a, 0x7a, 0xd2, 0xe2, 0x1a, 0x4e, 0x76, 0x2f, 0xf4, 0x94, 0x3e, 0x5d, 0x2f,
0xd2, 0x25, 0x39, 0x83, 0x07, 0x6d, 0x5c, 0x34, 0xfd, 0x98, 0xee, 0x70, 0x3d, 0x7a, 0xe9, 0xd0,
0x4b, 0xf0, 0x86, 0xc4, 0xc8, 0x53, 0xf0, 0x05, 0xd6, 0x55, 0x23, 0x12, 0x5c, 0x67, 0xf7, 0x56,
0x00, 0x7a, 0xe8, 0xfd, 0x3d, 0xfd, 0x02, 0xc1, 0x61, 0x54, 0xe4, 0x1c, 0xbc, 0x2e, 0xd0, 0x46,
0x14, 0xb6, 0xe5, 0xd8, 0x00, 0x9f, 0x44, 0xa1, 0xed, 0x95, 0xf1, 0x66, 0xb0, 0xa7, 0x6b, 0x32,
0x87, 0x69, 0x8b, 0xa2, 0xce, 0xaa, 0xd2, 0x3c, 0x9a, 0x17, 0xf5, 0x47, 0xfa, 0x16, 0x4e, 0x6f,
0xcb, 0x44, 0x28, 0x2e, 0x23, 0xfc, 0xd1, 0x60, 0x2d, 0xc9, 0xa3, 0xad, 0x15, 0x7f, 0x35, 0x66,
0x21, 0xaa, 0xce, 0xd0, 0x63, 0xf0, 0x78, 0x11, 0x67, 0x5d, 0x48, 0x5a, 0xfc, 0x24, 0xda, 0x02,
0xf4, 0x39, 0xcc, 0x06, 0x9d, 0x9a, 0x57, 0x65, 0x8d, 0xe4, 0x09, 0x40, 0x92, 0xf1, 0xef, 0x28,
0x4c, 0x87, 0x63, 0x3a, 0x76, 0x10, 0x7a, 0x07, 0xa7, 0x6f, 0xf0, 0xbf, 0x46, 0xef, 0x2b, 0x8d,
0xfe, 0x51, 0xba, 0x82, 0xd9, 0xa0, 0x64, 0x87, 0xef, 0x6d, 0xeb, 0x1c, 0x6c, 0xbb, 0x2a, 0x00,
0x42, 0x54, 0x1f, 0xbb, 0xcf, 0xa2, 0x1f, 0xdf, 0xee, 0x4e, 0x66, 0x6c, 0x3f, 0x8d, 0x45, 0xc0,
0x0e, 0x6c, 0xd1, 0x23, 0xcd, 0xb7, 0xe3, 0xc8, 0x8c, 0xed, 0x5b, 0x58, 0x04, 0xec, 0x60, 0x13,
0x7a, 0xf4, 0x75, 0x62, 0x7e, 0xe3, 0x8b, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xeb, 0x29, 0x21,
0x4e, 0xac, 0x03, 0x00, 0x00,
}

View File

@@ -5,6 +5,7 @@ message Key {
KmsKey kms_key = 1;
PgpKey pgp_key = 2;
GcpKmsKey gcp_kms_key = 3;
AzureKeyVaultKey azure_keyvault_key = 4;
}
}
@@ -22,6 +23,12 @@ message GcpKmsKey {
string resource_id = 1;
}
message AzureKeyVaultKey {
string vault_url = 1;
string name = 2;
string version = 3;
}
message EncryptRequest {
Key key = 1;
bytes plaintext = 2;

View File

@@ -3,6 +3,7 @@ package keyservice
import (
"fmt"
"go.mozilla.org/sops/azkv"
"go.mozilla.org/sops/gcpkms"
"go.mozilla.org/sops/kms"
"go.mozilla.org/sops/pgp"
@@ -55,6 +56,19 @@ func (ks *Server) encryptWithGcpKms(key *GcpKmsKey, plaintext []byte) ([]byte, e
return []byte(gcpKmsKey.EncryptedKey), nil
}
func (ks *Server) encryptWithAzureKeyVault(key *AzureKeyVaultKey, plaintext []byte) ([]byte, error) {
azkvKey := azkv.MasterKey{
VaultURL: key.VaultUrl,
Name: key.Name,
Version: key.Version,
}
err := azkvKey.Encrypt(plaintext)
if err != nil {
return nil, err
}
return []byte(azkvKey.EncryptedKey), nil
}
func (ks *Server) decryptWithPgp(key *PgpKey, ciphertext []byte) ([]byte, error) {
pgpKey := pgp.NewMasterKeyFromFingerprint(key.Fingerprint)
pgpKey.EncryptedKey = string(ciphertext)
@@ -86,6 +100,17 @@ func (ks *Server) decryptWithGcpKms(key *GcpKmsKey, ciphertext []byte) ([]byte,
return []byte(plaintext), err
}
func (ks *Server) decryptWithAzureKeyVault(key *AzureKeyVaultKey, ciphertext []byte) ([]byte, error) {
azkvKey := azkv.MasterKey{
VaultURL: key.VaultUrl,
Name: key.Name,
Version: key.Version,
}
azkvKey.EncryptedKey = string(ciphertext)
plaintext, err := azkvKey.Decrypt()
return []byte(plaintext), err
}
// Encrypt takes an encrypt request and encrypts the provided plaintext with the provided key, returning the encrypted
// result
func (ks Server) Encrypt(ctx context.Context,
@@ -117,6 +142,14 @@ func (ks Server) Encrypt(ctx context.Context,
response = &EncryptResponse{
Ciphertext: ciphertext,
}
case *Key_AzureKeyvaultKey:
ciphertext, err := ks.encryptWithAzureKeyVault(k.AzureKeyvaultKey, req.Plaintext)
if err != nil {
return nil, err
}
response = &EncryptResponse{
Ciphertext: ciphertext,
}
case nil:
return nil, status.Errorf(codes.NotFound, "Must provide a key")
default:
@@ -139,6 +172,8 @@ func keyToString(key Key) string {
return fmt.Sprintf("AWS KMS key with ARN %s", k.KmsKey.Arn)
case *Key_GcpKmsKey:
return fmt.Sprintf("GCP KMS key with resource ID %s", k.GcpKmsKey.ResourceId)
case *Key_AzureKeyvaultKey:
return fmt.Sprintf("Azure Key Vault key with URL %s/keys/%s/%s", k.AzureKeyvaultKey.VaultUrl, k.AzureKeyvaultKey.Name, k.AzureKeyvaultKey.Version)
default:
return fmt.Sprintf("Unknown key type")
}
@@ -191,6 +226,14 @@ func (ks Server) Decrypt(ctx context.Context,
response = &DecryptResponse{
Plaintext: plaintext,
}
case *Key_AzureKeyvaultKey:
plaintext, err := ks.decryptWithAzureKeyVault(k.AzureKeyvaultKey, req.Ciphertext)
if err != nil {
return nil, err
}
response = &DecryptResponse{
Plaintext: plaintext,
}
case nil:
return nil, grpc.Errorf(codes.NotFound, "Must provide a key")
default:

View File

@@ -15,6 +15,7 @@ import (
"fmt"
"go.mozilla.org/sops"
"go.mozilla.org/sops/azkv"
"go.mozilla.org/sops/gcpkms"
"go.mozilla.org/sops/kms"
"go.mozilla.org/sops/pgp"
@@ -38,6 +39,7 @@ type Metadata struct {
KeyGroups []keygroup `yaml:"key_groups,omitempty" json:"key_groups,omitempty"`
KMSKeys []kmskey `yaml:"kms" json:"kms"`
GCPKMSKeys []gcpkmskey `yaml:"gcp_kms" json:"gcp_kms"`
AzureKeyVaultKeys []azkvkey `yaml:"azure_kv" json:"azure_kv"`
LastModified string `yaml:"lastmodified" json:"lastmodified"`
MessageAuthenticationCode string `yaml:"mac" json:"mac"`
PGPKeys []pgpkey `yaml:"pgp" json:"pgp"`
@@ -47,9 +49,10 @@ type Metadata struct {
}
type keygroup struct {
PGPKeys []pgpkey `yaml:"pgp,omitempty" json:"pgp,omitempty"`
KMSKeys []kmskey `yaml:"kms,omitempty" json:"kms,omitempty"`
GCPKMSKeys []gcpkmskey `yaml:"gcp_kms,omitempty" json:"gcp_kms,omitempty"`
PGPKeys []pgpkey `yaml:"pgp,omitempty" json:"pgp,omitempty"`
KMSKeys []kmskey `yaml:"kms,omitempty" json:"kms,omitempty"`
GCPKMSKeys []gcpkmskey `yaml:"gcp_kms,omitempty" json:"gcp_kms,omitempty"`
AzureKeyVaultKeys []azkvkey `yaml:"azure_kv,omitempty" json:"azure_kv,omitempty"`
}
type pgpkey struct {
@@ -72,6 +75,14 @@ type gcpkmskey struct {
EncryptedDataKey string `yaml:"enc" json:"enc"`
}
type azkvkey struct {
VaultURL string `yaml:"vault_url" json:"vault_url"`
Name string `yaml:"name" json:"name"`
Version string `yaml:"version" json:"version"`
CreatedAt string `yaml:"created_at" json:"created_at"`
EncryptedDataKey string `yaml:"enc" json:"enc"`
}
// MetadataFromInternal converts an internal SOPS metadata representation to a representation appropriate for storage
func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata {
var m Metadata
@@ -86,12 +97,14 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata {
m.PGPKeys = pgpKeysFromGroup(group)
m.KMSKeys = kmsKeysFromGroup(group)
m.GCPKMSKeys = gcpkmsKeysFromGroup(group)
m.AzureKeyVaultKeys = azkvKeysFromGroup(group)
} else {
for _, group := range sopsMetadata.KeyGroups {
m.KeyGroups = append(m.KeyGroups, keygroup{
KMSKeys: kmsKeysFromGroup(group),
PGPKeys: pgpKeysFromGroup(group),
GCPKMSKeys: gcpkmsKeysFromGroup(group),
KMSKeys: kmsKeysFromGroup(group),
PGPKeys: pgpKeysFromGroup(group),
GCPKMSKeys: gcpkmsKeysFromGroup(group),
AzureKeyVaultKeys: azkvKeysFromGroup(group),
})
}
}
@@ -142,6 +155,22 @@ func gcpkmsKeysFromGroup(group sops.KeyGroup) (keys []gcpkmskey) {
return
}
func azkvKeysFromGroup(group sops.KeyGroup) (keys []azkvkey) {
for _, key := range group {
switch key := key.(type) {
case *azkv.MasterKey:
keys = append(keys, azkvkey{
VaultURL: key.VaultURL,
Name: key.Name,
Version: key.Version,
CreatedAt: key.CreationDate.Format(time.RFC3339),
EncryptedDataKey: key.EncryptedKey,
})
}
}
return
}
// ToInternal converts a storage-appropriate Metadata struct to a SOPS internal representation
func (m *Metadata) ToInternal() (sops.Metadata, error) {
lastModified, err := time.Parse(time.RFC3339, m.LastModified)
@@ -169,7 +198,7 @@ func (m *Metadata) ToInternal() (sops.Metadata, error) {
}, nil
}
func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmskey) (sops.KeyGroup, error) {
func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmskey, azkvKeys []azkvkey) (sops.KeyGroup, error) {
var internalGroup sops.KeyGroup
for _, kmsKey := range kmsKeys {
k, err := kmsKey.toInternal()
@@ -185,6 +214,13 @@ func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmske
}
internalGroup = append(internalGroup, k)
}
for _, azkvKey := range azkvKeys {
k, err := azkvKey.toInternal()
if err != nil {
return nil, err
}
internalGroup = append(internalGroup, k)
}
for _, pgpKey := range pgpKeys {
k, err := pgpKey.toInternal()
if err != nil {
@@ -197,8 +233,8 @@ func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmske
func (m *Metadata) internalKeygroups() ([]sops.KeyGroup, error) {
var internalGroups []sops.KeyGroup
if len(m.PGPKeys) > 0 || len(m.KMSKeys) > 0 || len(m.GCPKMSKeys) > 0 {
internalGroup, err := internalGroupFrom(m.KMSKeys, m.PGPKeys, m.GCPKMSKeys)
if len(m.PGPKeys) > 0 || len(m.KMSKeys) > 0 || len(m.GCPKMSKeys) > 0 || len(m.AzureKeyVaultKeys) > 0 {
internalGroup, err := internalGroupFrom(m.KMSKeys, m.PGPKeys, m.GCPKMSKeys, m.AzureKeyVaultKeys)
if err != nil {
return nil, err
}
@@ -206,7 +242,7 @@ func (m *Metadata) internalKeygroups() ([]sops.KeyGroup, error) {
return internalGroups, nil
} else if len(m.KeyGroups) > 0 {
for _, group := range m.KeyGroups {
internalGroup, err := internalGroupFrom(group.KMSKeys, group.PGPKeys, group.GCPKMSKeys)
internalGroup, err := internalGroupFrom(group.KMSKeys, group.PGPKeys, group.GCPKMSKeys, group.AzureKeyVaultKeys)
if err != nil {
return nil, err
}
@@ -244,6 +280,20 @@ func (gcpKmsKey *gcpkmskey) toInternal() (*gcpkms.MasterKey, error) {
}, nil
}
func (azkvKey *azkvkey) toInternal() (*azkv.MasterKey, error) {
creationDate, err := time.Parse(time.RFC3339, azkvKey.CreatedAt)
if err != nil {
return nil, err
}
return &azkv.MasterKey{
VaultURL: azkvKey.VaultURL,
Name: azkvKey.Name,
Version: azkvKey.Version,
EncryptedKey: azkvKey.EncryptedDataKey,
CreationDate: creationDate,
}, nil
}
func (pgpKey *pgpkey) toInternal() (*pgp.MasterKey, error) {
creationDate, err := time.Parse(time.RFC3339, pgpKey.CreatedAt)
if err != nil {