فهرست منبع

Implemented key option for SetSecret method

Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>
Gustavo Carvalho 4 سال پیش
والد
کامیت
7ad3874b2d

+ 7 - 7
pkg/provider/azure/keyvault/fake/fake.go

@@ -26,7 +26,7 @@ type AzureMockClient struct {
 	getCertificate     func(ctx context.Context, vaultBaseURL string, certificateName string, certificateVersion string) (result keyvault.CertificateBundle, err error)
 	setSecret          func(ctx context.Context, vaultBaseURL string, secretName string, parameters keyvault.SecretSetParameters) (result keyvault.SecretBundle, err error)
 	importCertificate  func(ctx context.Context, vaultBaseURL string, certificateName string, parameters keyvault.CertificateImportParameters) (result keyvault.CertificateBundle, err error)
-	createKey          func(ctx context.Context, vaultBaseURL string, keyName string, parameters keyvault.KeyCreateParameters) (result keyvault.KeyBundle, err error)
+	importKey          func(ctx context.Context, vaultBaseURL string, keyName string, parameters keyvault.KeyImportParameters) (result keyvault.KeyBundle, err error)
 }
 
 func (mc *AzureMockClient) GetSecret(ctx context.Context, vaultBaseURL, secretName, secretVersion string) (result keyvault.SecretBundle, err error) {
@@ -53,8 +53,8 @@ func (mc *AzureMockClient) ImportCertificate(ctx context.Context, vaultBaseURL s
 	return mc.importCertificate(ctx, vaultBaseURL, certificateName, parameters)
 }
 
-func (mc *AzureMockClient) CreateKey(ctx context.Context, vaultBaseURL string, keyName string, parameters keyvault.KeyCreateParameters) (result keyvault.KeyBundle, err error) {
-	return mc.createKey(ctx, vaultBaseURL, keyName, parameters)
+func (mc *AzureMockClient) ImportKey(ctx context.Context, vaultBaseURL string, keyName string, parameters keyvault.KeyImportParameters) (result keyvault.KeyBundle, err error) {
+	return mc.importKey(ctx, vaultBaseURL, keyName, parameters)
 }
 
 func (mc *AzureMockClient) WithValue(serviceURL, secretName, secretVersion string, apiOutput keyvault.SecretBundle, err error) {
@@ -89,9 +89,9 @@ func (mc *AzureMockClient) WithImportCertificate(apiOutput keyvault.CertificateB
 	}
 }
 
-func (mc *AzureMockClient) WithCreateKey(output keyvault.KeyBundle, err error) {
+func (mc *AzureMockClient) WithImportKey(output keyvault.KeyBundle, err error) {
 	if mc != nil {
-		mc.createKey = func(ctx context.Context, vaultBaseURL string, keyName string, parameters keyvault.KeyCreateParameters) (result keyvault.KeyBundle, err error) {
+		mc.importKey = func(ctx context.Context, vaultBaseURL string, keyName string, parameters keyvault.KeyImportParameters) (keyvault.KeyBundle, error) {
 			return output, err
 		}
 	}
@@ -99,7 +99,7 @@ func (mc *AzureMockClient) WithCreateKey(output keyvault.KeyBundle, err error) {
 
 func (mc *AzureMockClient) WithSetSecret(output keyvault.SecretBundle, err error) {
 	if mc != nil {
-		mc.setSecret = func(ctx context.Context, vaultBaseURL string, secretName string, parameters keyvault.SecretSetParameters) (result keyvault.SecretBundle, err error) {
+		mc.setSecret = func(ctx context.Context, vaultBaseURL string, secretName string, parameters keyvault.SecretSetParameters) (keyvault.SecretBundle, error) {
 			return output, err
 		}
 	}
@@ -107,7 +107,7 @@ func (mc *AzureMockClient) WithSetSecret(output keyvault.SecretBundle, err error
 
 func (mc *AzureMockClient) WithList(serviceURL string, apiOutput keyvault.SecretListResultIterator, err error) {
 	if mc != nil {
-		mc.getSecretsComplete = func(ctx context.Context, vaultBaseURL string, maxresults *int32) (result keyvault.SecretListResultIterator, err error) {
+		mc.getSecretsComplete = func(ctx context.Context, vaultBaseURL string, maxresults *int32) (keyvault.SecretListResultIterator, error) {
 			return apiOutput, err
 		}
 	}

+ 71 - 8
pkg/provider/azure/keyvault/keyvault.go

@@ -33,6 +33,7 @@ import (
 	"github.com/Azure/go-autorest/autorest/adal"
 	kvauth "github.com/Azure/go-autorest/autorest/azure/auth"
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
+	"github.com/lestrrat-go/jwx/jwk"
 	"github.com/tidwall/gjson"
 	authv1 "k8s.io/api/authentication/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -40,6 +41,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/client-go/kubernetes"
 	kcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
+	"k8s.io/utils/pointer"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
 	"software.sslmate.com/src/go-pkcs12"
@@ -96,7 +98,7 @@ type SecretClient interface {
 	GetSecretsComplete(ctx context.Context, vaultBaseURL string, maxresults *int32) (result keyvault.SecretListResultIterator, err error)
 	GetCertificate(ctx context.Context, vaultBaseURL string, certificateName string, certificateVersion string) (result keyvault.CertificateBundle, err error)
 	SetSecret(ctx context.Context, vaultBaseURL string, secretName string, parameters keyvault.SecretSetParameters) (result keyvault.SecretBundle, err error)
-	CreateKey(ctx context.Context, vaultBaseURL string, keyName string, parameters keyvault.KeyCreateParameters) (result keyvault.KeyBundle, err error)
+	ImportKey(ctx context.Context, vaultBaseURL string, keyName string, parameters keyvault.KeyImportParameters) (result keyvault.KeyBundle, err error)
 	ImportCertificate(ctx context.Context, vaultBaseURL string, certificateName string, parameters keyvault.CertificateImportParameters) (result keyvault.CertificateBundle, err error)
 }
 
@@ -221,6 +223,16 @@ func getCertificateFromValue(value []byte) (*x509.Certificate, error) {
 	return localCert, err
 }
 
+func getKeyFromValue(value []byte) (interface{}, error) {
+	var val []byte
+	val = value
+	pemBlock, _ := pem.Decode(value)
+	if pemBlock != nil {
+		val = pemBlock.Bytes
+	}
+	return x509.ParsePKCS8PrivateKey(val)
+}
+
 // Not Implemented SetSecret.
 func (a *Azure) SetSecret(ctx context.Context, value []byte, ref esv1beta1.PushRemoteRef) error {
 	objectType, secretName := getObjType(esv1beta1.ExternalSecretDataRemoteRef{Key: ref.GetRemoteKey()})
@@ -229,8 +241,25 @@ func (a *Azure) SetSecret(ctx context.Context, value []byte, ref esv1beta1.PushR
 	manager := "external-secrets"
 	switch objectType {
 	case defaultObjType:
-		// returns a SecretBundle with the secret value
-		// https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault#SecretBundle
+		secret, err := a.baseClient.GetSecret(ctx, *a.provider.VaultURL, secretName, "")
+		aerr := &autorest.DetailedError{}
+		conv := errors.As(err, aerr)
+		if err != nil && !conv {
+			return fmt.Errorf("could not get secret %v: could not parse error: %v", secretName, err)
+		}
+		if conv && aerr.StatusCode != 404 {
+			return fmt.Errorf("could not get secret %v: %v", secretName, err)
+		}
+		if err == nil {
+			manager, ok := secret.Tags["managed-by"]
+			if !ok || manager == nil || *manager != "external-secrets" {
+				return fmt.Errorf("secret %v is not managed by external-secrets", secretName)
+			}
+			val := secret.Value
+			if val != nil && *val == string(value) {
+				return nil
+			}
+		}
 		secretParams := keyvault.SecretSetParameters{
 			Value: &val,
 			Tags: map[string]*string{
@@ -240,7 +269,7 @@ func (a *Azure) SetSecret(ctx context.Context, value []byte, ref esv1beta1.PushR
 				Enabled: &enabled,
 			},
 		}
-		_, err := a.baseClient.SetSecret(ctx, *a.provider.VaultURL, secretName, secretParams)
+		_, err = a.baseClient.SetSecret(ctx, *a.provider.VaultURL, secretName, secretParams)
 		if err != nil {
 			return fmt.Errorf("could not set secret %v: %v", ref.GetRemoteKey(), err)
 		}
@@ -280,11 +309,45 @@ func (a *Azure) SetSecret(ctx context.Context, value []byte, ref esv1beta1.PushR
 			return fmt.Errorf("could not import certificate %v: %v", secretName, err)
 		}
 	case objectTypeKey:
-		// returns a KeyBundle that contains a jwk
-		// azure kv returns only public keys
-		// see: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault#KeyBundle
+		key, err := getKeyFromValue(value)
+		if err != nil {
+			return fmt.Errorf("could not load private key %v: format not compatible with PCKS8", secretName)
+		}
+		jwKey, err := jwk.New(key)
+		if err != nil {
+			return fmt.Errorf("failed to generate a JWK from secret %v content: %v", secretName, err)
+		}
+		buf, err := json.Marshal(jwKey)
+		if err != nil {
+			return fmt.Errorf("error parsing key: %v", err)
+		}
+		azkey := keyvault.JSONWebKey{}
+		err = json.Unmarshal(buf, &azkey)
+		if err != nil {
+			return fmt.Errorf("error unmarshalling key: %v", err)
+		}
+		keyFromVault, err := a.baseClient.GetKey(ctx, *a.provider.VaultURL, secretName, "")
+		if err != nil && err.(autorest.DetailedError).StatusCode != 404 {
+			return fmt.Errorf("could not get key %v: %v", secretName, err)
+		}
+		if err == nil {
+			t, ok := keyFromVault.Tags["managed-by"]
+			if !ok || *t != "external-secrets" {
+				return fmt.Errorf("key not managed by external-secrets")
+			}
+		}
+		params := keyvault.KeyImportParameters{
+			Key:           &azkey,
+			KeyAttributes: &keyvault.KeyAttributes{},
+			Tags: map[string]*string{
+				"managed-by": pointer.StringPtr("external-secrets"),
+			},
+		}
+		_, err = a.baseClient.ImportKey(ctx, *a.provider.VaultURL, secretName, params)
+		if err != nil {
+			return fmt.Errorf("could not import key %v: %v", secretName, err)
+		}
 	}
-
 	return nil
 
 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
pkg/provider/azure/keyvault/keyvault_test.go


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است