Skip to content

Commit

Permalink
Merge pull request #1092 from hiddeco/azkv-update-sdk
Browse files Browse the repository at this point in the history
azkv: update Azure SDK to v0.10.0
  • Loading branch information
hiddeco committed Jul 4, 2023
2 parents 8960e72 + 2625e56 commit 4eaecad
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 84 deletions.
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ You can create a Service Principal using the CLI like this:
"appId": "<some-uuid>",
"displayName": "my-keyvault-sp",
"name": "http://my-keyvault-sp",
"password": "<some-uuid>",
"tenant": "<tenant-id>"
"password": "<random-string>",
"tenant": "<tenant-uuid>"
}
The `appId` is the client ID, and the `password` is the client secret.
Expand Down
50 changes: 31 additions & 19 deletions azkv/keysource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Package azkv contains an implementation of the go.mozilla.org/sops/v3/keys.Maste
interface that encrypts and decrypts the data key using Azure Key Vault with the
Azure Key Vault Keys client module for Go.
*/
package azkv //import "go.mozilla.org/sops/v3/azkv"
package azkv // import "go.mozilla.org/sops/v3/azkv"

import (
"context"
Expand All @@ -14,9 +14,11 @@ import (
"time"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys/crypto"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys"
"github.com/sirupsen/logrus"

"go.mozilla.org/sops/v3/logging"
)

Expand Down Expand Up @@ -115,21 +117,26 @@ func (t TokenCredential) ApplyToMasterKey(key *MasterKey) {
func (key *MasterKey) Encrypt(dataKey []byte) error {
token, err := key.getTokenCredential()
if err != nil {
log.WithError(err).WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Encryption failed")
log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Encryption failed")
return fmt.Errorf("failed to get Azure token credential to encrypt data: %w", err)
}
c, err := crypto.NewClient(key.ToString(), token, nil)

c, err := azkeys.NewClient(key.VaultURL, token, nil)
if err != nil {
log.WithError(err).WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Encryption failed")
return fmt.Errorf("failed to construct Azure Key Vault crypto client to encrypt data: %w", err)
log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Encryption failed")
return fmt.Errorf("failed to construct Azure Key Vault client to encrypt data: %w", err)
}

resp, err := c.Encrypt(context.Background(), crypto.EncryptionAlgRSAOAEP256, dataKey, nil)
resp, err := c.Encrypt(context.Background(), key.Name, key.Version, azkeys.KeyOperationsParameters{
Algorithm: to.Ptr(azkeys.JSONWebKeyEncryptionAlgorithmRSAOAEP256),
Value: dataKey,
}, nil)
if err != nil {
log.WithError(err).WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Encryption failed")
log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Encryption failed")
return fmt.Errorf("failed to encrypt sops data key with Azure Key Vault key '%s': %w", key.ToString(), err)
}
encodedEncryptedKey := base64.RawURLEncoding.EncodeToString(resp.Ciphertext)

encodedEncryptedKey := base64.RawURLEncoding.EncodeToString(resp.KeyOperationResult.Result)
key.SetEncryptedDataKey([]byte(encodedEncryptedKey))
log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Encryption succeeded")
return nil
Expand Down Expand Up @@ -159,27 +166,32 @@ func (key *MasterKey) EncryptIfNeeded(dataKey []byte) error {
func (key *MasterKey) Decrypt() ([]byte, error) {
token, err := key.getTokenCredential()
if err != nil {
log.WithError(err).WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed")
log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed")
return nil, fmt.Errorf("failed to get Azure token credential to decrypt: %w", err)
}
c, err := crypto.NewClient(key.ToString(), token, nil)
if err != nil {
log.WithError(err).WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed")
return nil, fmt.Errorf("failed to construct Azure Key Vault crypto client to decrypt data: %w", err)
}

rawEncryptedKey, err := base64.RawURLEncoding.DecodeString(key.EncryptedKey)
if err != nil {
log.WithError(err).WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed")
log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed")
return nil, fmt.Errorf("failed to base64 decode Azure Key Vault encrypted key: %w", err)
}
resp, err := c.Decrypt(context.Background(), crypto.EncryptionAlgRSAOAEP256, rawEncryptedKey, nil)

c, err := azkeys.NewClient(key.VaultURL, token, nil)
if err != nil {
log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed")
return nil, fmt.Errorf("failed to construct Azure Key Vault client to decrypt data: %w", err)
}

resp, err := c.Decrypt(context.Background(), key.Name, key.Version, azkeys.KeyOperationsParameters{
Algorithm: to.Ptr(azkeys.JSONWebKeyEncryptionAlgorithmRSAOAEP256),
Value: rawEncryptedKey,
}, nil)
if err != nil {
log.WithError(err).WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed")
log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Error("Decryption failed")
return nil, fmt.Errorf("failed to decrypt sops data key with Azure Key Vault key '%s': %w", key.ToString(), err)
}
log.WithFields(logrus.Fields{"key": key.Name, "version": key.Version}).Info("Decryption succeeded")
return resp.Plaintext, nil
return resp.KeyOperationResult.Result, nil
}

// NeedsRotation returns whether the data key needs to be rotated or not.
Expand Down
48 changes: 26 additions & 22 deletions azkv/keysource_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys/crypto"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -47,12 +46,16 @@ func TestMasterKey_Decrypt(t *testing.T) {
assert.NoError(t, err)

data := []byte("this is super secret data")
c, err := crypto.NewClient(key.ToString(), key.tokenCredential, nil)

c, err := azkeys.NewClient(key.VaultURL, key.tokenCredential, nil)
assert.NoError(t, err)

resp, err := c.Encrypt(context.Background(), crypto.EncryptionAlgRSAOAEP256, data, nil)
resp, err := c.Encrypt(context.Background(), key.Name, key.Version, azkeys.KeyOperationsParameters{
Algorithm: to.Ptr(azkeys.JSONWebKeyEncryptionAlgorithmRSAOAEP256),
Value: data,
}, nil)
assert.NoError(t, err)
key.EncryptedKey = base64.RawURLEncoding.EncodeToString(resp.Ciphertext)
key.EncryptedKey = base64.RawURLEncoding.EncodeToString(resp.KeyOperationResult.Result)

got, err := key.Decrypt()
assert.NoError(t, err)
Expand Down Expand Up @@ -85,28 +88,29 @@ func createTestKMSKeyIfNotExists() (*MasterKey, error) {
}
NewTokenCredential(token).ApplyToMasterKey(key)

c, err := azkeys.NewClient(key.VaultURL, token, nil)
if err != nil {
return nil, err
}

getResp, err := c.GetKey(context.TODO(), key.Name, &azkeys.GetKeyOptions{Version: key.Version})
if err == nil {
key.Version = *getResp.Properties.Version
}
if err != nil {
createResp, err := c.CreateKey(context.TODO(), key.Name, azkeys.KeyTypeRSA, &azkeys.CreateKeyOptions{
Operations: []*azkeys.Operation{
to.Ptr(azkeys.OperationEncrypt),
to.Ptr(azkeys.OperationDecrypt),
},
Properties: &azkeys.Properties{Version: to.Ptr(key.Version)},
})
// If we have been given a version, assume it exists.
if key.Version == "" {
c, err := azkeys.NewClient(key.VaultURL, token, nil)
if err != nil {
return nil, err
}
key.Version = *createResp.Properties.Version

getResp, err := c.GetKey(context.TODO(), key.Name, key.Version, nil)
if err == nil {
key.Version = getResp.KeyBundle.Key.KID.Version()
}
if err != nil {
createResp, err := c.CreateKey(context.TODO(), key.Name, azkeys.CreateKeyParameters{
Kty: to.Ptr(azkeys.JSONWebKeyTypeRSA),
KeyOps: to.SliceOfPtrs(azkeys.JSONWebKeyOperationEncrypt, azkeys.JSONWebKeyOperationDecrypt),
}, nil)
if err != nil {
return nil, err
}
key.Version = createResp.Key.KID.Version()
}
}

return key, nil
}

Expand Down
24 changes: 12 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ require (
cloud.google.com/go/kms v1.4.0
cloud.google.com/go/storage v1.23.0
filippo.io/age v1.0.0
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.5.1
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0
github.com/ProtonMail/go-crypto v0.0.0-20220711121315-1fde58898e96
github.com/aws/aws-sdk-go-v2 v1.16.7
github.com/aws/aws-sdk-go-v2/config v1.15.14
Expand All @@ -33,10 +33,10 @@ require (
github.com/stretchr/testify v1.7.2
github.com/urfave/cli v1.22.7
go.mozilla.org/gopgagent v0.0.0-20170926210634-4d7ea76ff71a
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
golang.org/x/net v0.0.0-20220708220712-1185a9018129
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467
golang.org/x/crypto v0.7.0
golang.org/x/net v0.8.0
golang.org/x/sys v0.6.0
golang.org/x/term v0.6.0
google.golang.org/api v0.87.0
google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d
google.golang.org/grpc v1.48.0
Expand All @@ -49,10 +49,10 @@ require (
cloud.google.com/go v0.103.0 // indirect
cloud.google.com/go/compute v1.7.0 // indirect
cloud.google.com/go/iam v0.3.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.5.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.2 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/armon/go-metrics v0.4.0 // indirect
Expand All @@ -76,7 +76,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.3.0 // indirect
Expand Down Expand Up @@ -124,7 +124,7 @@ require (
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/appengine v1.6.7 // indirect
Expand Down
Loading

0 comments on commit 4eaecad

Please sign in to comment.