Browse Source

leverage IBM provider's latest API to get the secret by name (#2750)

Shanti G 2 years ago
parent
commit
583b919cb7

+ 7 - 1
docs/provider/ibm-secrets-manager.md

@@ -197,12 +197,18 @@ Below example creates a kubernetes secret based on ID of the secret in Secrets M
 {% include 'ibm-external-secret.yaml' %}
 ```
 
-Alternatively, secret name can be specified instead of secret ID. However, note that ESO makes an additional call to fetch the relevant secret ID for the specified secret name.
+Alternatively, the secret name along with its secret group name can be specified instead of secret ID to fetch the secret.
 
 ```yaml
 {% include 'ibm-external-secret-by-name.yaml' %}
 ```
 
+Please note that the below mechanism to get the secret by name is deprecated and not supported.
+
+```yaml
+{% include 'ibm-external-secret-by-name-deprecated.yaml' %}
+```
+
 ### Getting the Kubernetes secret
 The operator will fetch the IBM Secret Manager secret and inject it as a `Kind=Secret`
 ```

+ 22 - 0
docs/snippets/ibm-external-secret-by-name-deprecated.yaml

@@ -0,0 +1,22 @@
+# NOTE: Below way of fetching the secret by name is deprecated and not supported.
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: database-credentials
+spec:
+  refreshInterval: 60m
+  secretStoreRef:
+    name: ibm-store
+    kind: SecretStore
+  target:
+    name: database-credentials
+    creationPolicy: Owner
+  data:
+  - secretKey: username
+    remoteRef:
+      key: username_password/<SECRET_NAME>
+      property: username
+  - secretKey: password
+    remoteRef:
+      key: username_password/<SECRET_NAME>
+      property: password

+ 2 - 2
docs/snippets/ibm-external-secret-by-name.yaml

@@ -13,9 +13,9 @@ spec:
   data:
   - secretKey: username
     remoteRef:
-      key: username_password/<SECRET_NAME>
+      key: <SECRET_GROUP_NAME>/username_password/<SECRET_NAME>
       property: username
   - secretKey: password
     remoteRef:
-      key: username_password/<SECRET_NAME>
+      key: <SECRET_GROUP_NAME>/username_password/<SECRET_NAME>
       property: password

+ 4 - 3
pkg/constants/constants.go

@@ -69,9 +69,10 @@ const (
 	CallKubernetesUpdateSecret                 = "UpdateSecret"
 	CallKubernetesCreateSelfSubjectRulesReview = "CreateSelfSubjectRulesReview"
 
-	ProviderIBMSM        = "IBM/SecretsManager"
-	CallIBMSMGetSecret   = "GetSecret"
-	CallIBMSMListSecrets = "ListSecrets"
+	ProviderIBMSM                = "IBM/SecretsManager"
+	CallIBMSMGetSecret           = "GetSecret"
+	CallIBMSMListSecrets         = "ListSecrets"
+	CallIBMSMGetSecretByNameType = "GetSecretByNameType"
 
 	ProviderWebhook    = "Webhook"
 	CallWebhookHTTPReq = "HTTPRequest"

+ 24 - 8
pkg/provider/ibm/fake/fake.go

@@ -24,17 +24,21 @@ import (
 )
 
 type IBMMockClient struct {
-	getSecretWithContext   func(ctx context.Context, getSecretOptions *sm.GetSecretOptions) (result sm.SecretIntf, response *core.DetailedResponse, err error)
-	listSecretsWithContext func(ctx context.Context, listSecretsOptions *sm.ListSecretsOptions) (result *sm.SecretMetadataPaginatedCollection, response *core.DetailedResponse, err error)
+	getSecretWithContext           func(ctx context.Context, getSecretOptions *sm.GetSecretOptions) (result sm.SecretIntf, response *core.DetailedResponse, err error)
+	listSecretsWithContext         func(ctx context.Context, listSecretsOptions *sm.ListSecretsOptions) (result *sm.SecretMetadataPaginatedCollection, response *core.DetailedResponse, err error)
+	getSecretByNameTypeWithContext func(ctx context.Context, getSecretByNameTypeOptions *sm.GetSecretByNameTypeOptions) (result sm.SecretIntf, response *core.DetailedResponse, err error)
 }
 
 type IBMMockClientParams struct {
-	GetSecretOptions   *sm.GetSecretOptions
-	GetSecretOutput    sm.SecretIntf
-	GetSecretErr       error
-	ListSecretsOptions *sm.ListSecretsOptions
-	ListSecretsOutput  *sm.SecretMetadataPaginatedCollection
-	ListSecretsErr     error
+	GetSecretOptions       *sm.GetSecretOptions
+	GetSecretOutput        sm.SecretIntf
+	GetSecretErr           error
+	ListSecretsOptions     *sm.ListSecretsOptions
+	ListSecretsOutput      *sm.SecretMetadataPaginatedCollection
+	ListSecretsErr         error
+	GetSecretByNameOptions *sm.GetSecretByNameTypeOptions
+	GetSecretByNameOutput  sm.SecretIntf
+	GetSecretByNameErr     error
 }
 
 func (mc *IBMMockClient) GetSecretWithContext(ctx context.Context, getSecretOptions *sm.GetSecretOptions) (result sm.SecretIntf, response *core.DetailedResponse, err error) {
@@ -45,6 +49,10 @@ func (mc *IBMMockClient) ListSecretsWithContext(ctx context.Context, listSecrets
 	return mc.listSecretsWithContext(ctx, listSecretsOptions)
 }
 
+func (mc *IBMMockClient) GetSecretByNameTypeWithContext(ctx context.Context, getSecretByNameTypeOptions *sm.GetSecretByNameTypeOptions) (result sm.SecretIntf, response *core.DetailedResponse, err error) {
+	return mc.getSecretByNameTypeWithContext(ctx, getSecretByNameTypeOptions)
+}
+
 func (mc *IBMMockClient) WithValue(params IBMMockClientParams) {
 	if mc != nil {
 		mc.getSecretWithContext = func(ctx context.Context, paramReq *sm.GetSecretOptions) (sm.SecretIntf, *core.DetailedResponse, error) {
@@ -63,5 +71,13 @@ func (mc *IBMMockClient) WithValue(params IBMMockClientParams) {
 			}
 			return params.ListSecretsOutput, nil, params.ListSecretsErr
 		}
+		mc.getSecretByNameTypeWithContext = func(ctx context.Context, paramReq *sm.GetSecretByNameTypeOptions) (sm.SecretIntf, *core.DetailedResponse, error) {
+			// type secretmanagerpb.AccessSecretVersionRequest contains unexported fields
+			// use cmpopts.IgnoreUnexported to ignore all the unexported fields in the cmp.
+			if !cmp.Equal(paramReq, params.GetSecretByNameOptions, cmpopts.IgnoreUnexported(sm.Secret{})) {
+				return nil, nil, fmt.Errorf("unexpected test argument for GetSecretByNameType: %s, %s", *paramReq.Name, *params.GetSecretByNameOptions.Name)
+			}
+			return params.GetSecretByNameOutput, nil, params.GetSecretByNameErr
+		}
 	}
 }

+ 66 - 35
pkg/provider/ibm/provider.go

@@ -77,6 +77,7 @@ var (
 type SecretManagerClient interface {
 	GetSecretWithContext(ctx context.Context, getSecretOptions *sm.GetSecretOptions) (result sm.SecretIntf, response *core.DetailedResponse, err error)
 	ListSecretsWithContext(ctx context.Context, listSecretsOptions *sm.ListSecretsOptions) (result *sm.SecretMetadataPaginatedCollection, response *core.DetailedResponse, err error)
+	GetSecretByNameTypeWithContext(ctx context.Context, getSecretByNameTypeOptions *sm.GetSecretByNameTypeOptions) (result sm.SecretIntf, response *core.DetailedResponse, err error)
 }
 
 type providerIBM struct {
@@ -143,29 +144,35 @@ func (ibm *providerIBM) GetSecret(_ context.Context, ref esv1beta1.ExternalSecre
 		return nil, fmt.Errorf(errUninitalizedIBMProvider)
 	}
 
+	var secretGroupName string
 	secretType := sm.Secret_SecretType_Arbitrary
 	secretName := ref.Key
 	nameSplitted := strings.Split(secretName, "/")
 
-	if len(nameSplitted) > 1 {
+	switch len(nameSplitted) {
+	case 2:
 		secretType = nameSplitted[0]
 		secretName = nameSplitted[1]
+	case 3:
+		secretGroupName = nameSplitted[0]
+		secretType = nameSplitted[1]
+		secretName = nameSplitted[2]
 	}
 
 	switch secretType {
 	case sm.Secret_SecretType_Arbitrary:
-		return getArbitrarySecret(ibm, &secretName)
+		return getArbitrarySecret(ibm, &secretName, secretGroupName)
 
 	case sm.Secret_SecretType_UsernamePassword:
 
 		if ref.Property == "" {
 			return nil, fmt.Errorf("remoteRef.property required for secret type username_password")
 		}
-		return getUsernamePasswordSecret(ibm, &secretName, ref)
+		return getUsernamePasswordSecret(ibm, &secretName, ref, secretGroupName)
 
 	case sm.Secret_SecretType_IamCredentials:
 
-		return getIamCredentialsSecret(ibm, &secretName)
+		return getIamCredentialsSecret(ibm, &secretName, secretGroupName)
 
 	case sm.Secret_SecretType_ImportedCert:
 
@@ -173,7 +180,7 @@ func (ibm *providerIBM) GetSecret(_ context.Context, ref esv1beta1.ExternalSecre
 			return nil, fmt.Errorf("remoteRef.property required for secret type imported_cert")
 		}
 
-		return getImportCertSecret(ibm, &secretName, ref)
+		return getImportCertSecret(ibm, &secretName, ref, secretGroupName)
 
 	case sm.Secret_SecretType_PublicCert:
 
@@ -181,7 +188,7 @@ func (ibm *providerIBM) GetSecret(_ context.Context, ref esv1beta1.ExternalSecre
 			return nil, fmt.Errorf("remoteRef.property required for secret type public_cert")
 		}
 
-		return getPublicCertSecret(ibm, &secretName, ref)
+		return getPublicCertSecret(ibm, &secretName, ref, secretGroupName)
 
 	case sm.Secret_SecretType_PrivateCert:
 
@@ -189,11 +196,11 @@ func (ibm *providerIBM) GetSecret(_ context.Context, ref esv1beta1.ExternalSecre
 			return nil, fmt.Errorf("remoteRef.property required for secret type private_cert")
 		}
 
-		return getPrivateCertSecret(ibm, &secretName, ref)
+		return getPrivateCertSecret(ibm, &secretName, ref, secretGroupName)
 
 	case sm.Secret_SecretType_Kv:
 
-		response, err := getSecretData(ibm, &secretName, sm.Secret_SecretType_Kv)
+		response, err := getSecretData(ibm, &secretName, sm.Secret_SecretType_Kv, secretGroupName)
 		if err != nil {
 			return nil, err
 		}
@@ -208,8 +215,8 @@ func (ibm *providerIBM) GetSecret(_ context.Context, ref esv1beta1.ExternalSecre
 	}
 }
 
-func getArbitrarySecret(ibm *providerIBM, secretName *string) ([]byte, error) {
-	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_Arbitrary)
+func getArbitrarySecret(ibm *providerIBM, secretName *string, secretGroupName string) ([]byte, error) {
+	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_Arbitrary, secretGroupName)
 	if err != nil {
 		return nil, err
 	}
@@ -223,8 +230,8 @@ func getArbitrarySecret(ibm *providerIBM, secretName *string) ([]byte, error) {
 	return nil, fmt.Errorf("key %s does not exist in secret %s", payloadConst, *secretName)
 }
 
-func getImportCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
-	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_ImportedCert)
+func getImportCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef, secretGroupName string) ([]byte, error) {
+	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_ImportedCert, secretGroupName)
 	if err != nil {
 		return nil, err
 	}
@@ -244,8 +251,8 @@ func getImportCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.Ext
 	return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
 }
 
-func getPublicCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
-	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_PublicCert)
+func getPublicCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef, secretGroupName string) ([]byte, error) {
+	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_PublicCert, secretGroupName)
 	if err != nil {
 		return nil, err
 	}
@@ -259,8 +266,8 @@ func getPublicCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.Ext
 	return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
 }
 
-func getPrivateCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
-	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_PrivateCert)
+func getPrivateCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef, secretGroupName string) ([]byte, error) {
+	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_PrivateCert, secretGroupName)
 	if err != nil {
 		return nil, err
 	}
@@ -274,8 +281,8 @@ func getPrivateCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.Ex
 	return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
 }
 
-func getIamCredentialsSecret(ibm *providerIBM, secretName *string) ([]byte, error) {
-	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_IamCredentials)
+func getIamCredentialsSecret(ibm *providerIBM, secretName *string, secretGroupName string) ([]byte, error) {
+	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_IamCredentials, secretGroupName)
 	if err != nil {
 		return nil, err
 	}
@@ -289,8 +296,8 @@ func getIamCredentialsSecret(ibm *providerIBM, secretName *string) ([]byte, erro
 	return nil, fmt.Errorf("key %s does not exist in secret %s", smAPIKeyConst, *secretName)
 }
 
-func getUsernamePasswordSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
-	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_UsernamePassword)
+func getUsernamePasswordSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef, secretGroupName string) ([]byte, error) {
+	response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_UsernamePassword, secretGroupName)
 	if err != nil {
 		return nil, err
 	}
@@ -348,26 +355,46 @@ func getKVSecret(ref esv1beta1.ExternalSecretDataRemoteRef, secret *sm.KVSecret)
 	return nil, fmt.Errorf("no property provided for secret %s", ref.Key)
 }
 
-func getSecretData(ibm *providerIBM, secretName *string, secretType string) (sm.SecretIntf, error) {
+func getSecretData(ibm *providerIBM, secretName *string, secretType, secretGroupName string) (sm.SecretIntf, error) {
 	var givenName *string
 	var cachedKey string
 
-	// parse given secretName for a uuid or a secret name
 	_, err := uuid.Parse(*secretName)
 	if err != nil {
-		givenName = secretName
-		cachedKey = fmt.Sprintf("%s/%s", secretType, *givenName)
-		isCached, cacheData := ibm.cache.GetData(cachedKey)
-		tmp := string(cacheData)
-		cachedName := &tmp
-		if isCached && *cachedName != "" {
-			secretName = cachedName
+		// secret name has been provided instead of id
+		if secretGroupName == "" {
+			// secret group name is not provided, follow the existing mechanism
+			// once this mechanism is deprecated, this flow will not be supported, and error will be thrown instead
+			givenName = secretName
+			cachedKey = fmt.Sprintf("%s/%s", secretType, *givenName)
+			isCached, cacheData := ibm.cache.GetData(cachedKey)
+			tmp := string(cacheData)
+			cachedName := &tmp
+			if isCached && *cachedName != "" {
+				secretName = cachedName
+			} else {
+				secretName, err = findSecretByName(ibm, givenName, secretType)
+				if err != nil {
+					return nil, err
+				}
+				ibm.cache.PutData(cachedKey, []byte(*secretName))
+			}
 		} else {
-			secretName, err = findSecretByName(ibm, givenName, secretType)
+			// secret group name is provided along with secret name, follow the new mechanism by calling GetSecretByNameTypeWithContext
+			ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
+			defer cancel()
+			response, _, err := ibm.IBMClient.GetSecretByNameTypeWithContext(
+				ctx,
+				&sm.GetSecretByNameTypeOptions{
+					Name:            secretName,
+					SecretGroupName: &secretGroupName,
+					SecretType:      &secretType,
+				})
+			metrics.ObserveAPICall(constants.ProviderIBMSM, constants.CallIBMSMGetSecretByNameType, err)
 			if err != nil {
 				return nil, err
 			}
-			ibm.cache.PutData(cachedKey, []byte(*secretName))
+			return response, nil
 		}
 	}
 
@@ -421,19 +448,23 @@ func (ibm *providerIBM) GetSecretMap(_ context.Context, ref esv1beta1.ExternalSe
 	if utils.IsNil(ibm.IBMClient) {
 		return nil, fmt.Errorf(errUninitalizedIBMProvider)
 	}
-
+	var secretGroupName string
 	secretType := sm.Secret_SecretType_Arbitrary
 	secretName := ref.Key
 	nameSplitted := strings.Split(secretName, "/")
-
-	if len(nameSplitted) > 1 {
+	switch len(nameSplitted) {
+	case 2:
 		secretType = nameSplitted[0]
 		secretName = nameSplitted[1]
+	case 3:
+		secretGroupName = nameSplitted[0]
+		secretType = nameSplitted[1]
+		secretName = nameSplitted[2]
 	}
 
 	secretMap := make(map[string][]byte)
 	secMapBytes := make(map[string][]byte)
-	response, err := getSecretData(ibm, &secretName, secretType)
+	response, err := getSecretData(ibm, &secretName, secretType, secretGroupName)
 	if err != nil {
 		return nil, err
 	}

+ 104 - 37
pkg/provider/ibm/provider_test.go

@@ -44,44 +44,53 @@ const (
 )
 
 type secretManagerTestCase struct {
-	name           string
-	mockClient     *fakesm.IBMMockClient
-	apiInput       *sm.GetSecretOptions
-	apiOutput      sm.SecretIntf
-	listInput      *sm.ListSecretsOptions
-	listOutput     *sm.SecretMetadataPaginatedCollection
-	listError      error
-	ref            *esv1beta1.ExternalSecretDataRemoteRef
-	serviceURL     *string
-	apiErr         error
-	expectError    string
-	expectedSecret string
+	name            string
+	mockClient      *fakesm.IBMMockClient
+	apiInput        *sm.GetSecretOptions
+	apiOutput       sm.SecretIntf
+	listInput       *sm.ListSecretsOptions
+	listOutput      *sm.SecretMetadataPaginatedCollection
+	listError       error
+	getByNameInput  *sm.GetSecretByNameTypeOptions
+	getByNameOutput sm.SecretIntf
+	getByNameError  error
+	ref             *esv1beta1.ExternalSecretDataRemoteRef
+	serviceURL      *string
+	apiErr          error
+	expectError     string
+	expectedSecret  string
 	// for testing secretmap
 	expectedData map[string][]byte
 }
 
 func makeValidSecretManagerTestCase() *secretManagerTestCase {
 	smtc := secretManagerTestCase{
-		mockClient:     &fakesm.IBMMockClient{},
-		apiInput:       makeValidAPIInput(),
-		ref:            makeValidRef(),
-		apiOutput:      makeValidAPIOutput(),
-		listInput:      makeValidListInput(),
-		listOutput:     makeValidListSecretsOutput(),
-		listError:      nil,
-		serviceURL:     nil,
-		apiErr:         nil,
-		expectError:    "",
-		expectedSecret: "",
-		expectedData:   map[string][]byte{},
+		mockClient:      &fakesm.IBMMockClient{},
+		apiInput:        makeValidAPIInput(),
+		ref:             makeValidRef(),
+		apiOutput:       makeValidAPIOutput(),
+		listInput:       makeValidListInput(),
+		listOutput:      makeValidListSecretsOutput(),
+		listError:       nil,
+		getByNameInput:  makeValidGetByNameInput(),
+		getByNameOutput: makeValidGetByNameOutput(),
+		getByNameError:  nil,
+		serviceURL:      nil,
+		apiErr:          nil,
+		expectError:     "",
+		expectedSecret:  "",
+		expectedData:    map[string][]byte{},
 	}
 	mcParams := fakesm.IBMMockClientParams{
-		GetSecretOptions:   smtc.apiInput,
-		GetSecretOutput:    smtc.apiOutput,
-		GetSecretErr:       smtc.apiErr,
-		ListSecretsOptions: smtc.listInput,
-		ListSecretsOutput:  smtc.listOutput,
-		ListSecretsErr:     smtc.listError,
+		GetSecretOptions:       smtc.apiInput,
+		GetSecretOutput:        smtc.apiOutput,
+		GetSecretErr:           smtc.apiErr,
+		ListSecretsOptions:     smtc.listInput,
+		ListSecretsOutput:      smtc.listOutput,
+		ListSecretsErr:         smtc.listError,
+		GetSecretByNameOptions: smtc.getByNameInput,
+		GetSecretByNameOutput:  smtc.getByNameOutput,
+		GetSecretByNameErr:     smtc.getByNameError,
 	}
 	smtc.mockClient.WithValue(mcParams)
 	return &smtc
@@ -110,6 +119,20 @@ func makeValidAPIOutput() sm.SecretIntf {
 	return i
 }
 
+func makeValidGetByNameInput() *sm.GetSecretByNameTypeOptions {
+	return &sm.GetSecretByNameTypeOptions{}
+}
+
+func makeValidGetByNameOutput() sm.SecretIntf {
+	secret := &sm.Secret{
+		SecretType: utilpointer.To(sm.Secret_SecretType_Arbitrary),
+		Name:       utilpointer.To("testyname"),
+		ID:         utilpointer.To(secretUUID),
+	}
+	var i sm.SecretIntf = secret
+	return i
+}
+
 func makeValidListSecretsOutput() *sm.SecretMetadataPaginatedCollection {
 	list := sm.SecretMetadataPaginatedCollection{}
 	return &list
@@ -126,12 +149,15 @@ func makeValidSecretManagerTestCaseCustom(tweaks ...func(smtc *secretManagerTest
 		fn(smtc)
 	}
 	mcParams := fakesm.IBMMockClientParams{
-		GetSecretOptions:   smtc.apiInput,
-		GetSecretOutput:    smtc.apiOutput,
-		GetSecretErr:       smtc.apiErr,
-		ListSecretsOptions: smtc.listInput,
-		ListSecretsOutput:  smtc.listOutput,
-		ListSecretsErr:     smtc.listError,
+		GetSecretOptions:       smtc.apiInput,
+		GetSecretOutput:        smtc.apiOutput,
+		GetSecretErr:           smtc.apiErr,
+		ListSecretsOptions:     smtc.listInput,
+		ListSecretsOutput:      smtc.listOutput,
+		ListSecretsErr:         smtc.listError,
+		GetSecretByNameOptions: smtc.getByNameInput,
+		GetSecretByNameOutput:  smtc.getByNameOutput,
+		GetSecretByNameErr:     smtc.apiErr,
 	}
 	smtc.mockClient.WithValue(mcParams)
 	return smtc
@@ -341,6 +367,26 @@ func TestIBMSecretManagerGetSecret(t *testing.T) {
 	setSecretIamByID := funcSetSecretIam(secretUUID, "good case: iam_credenatials type - get API Key by ID")
 	setSecretIamByName := funcSetSecretIam("testyname", "good case: iam_credenatials type - get API Key by name")
 
+	funcSetSecretIamNew := func(secretName, groupName, name string) func(*secretManagerTestCase) {
+		return func(smtc *secretManagerTestCase) {
+			secret := &sm.IAMCredentialsSecret{
+				SecretType: utilpointer.To(sm.Secret_SecretType_IamCredentials),
+				Name:       utilpointer.To("testyname"),
+				ID:         utilpointer.To(secretUUID),
+				ApiKey:     utilpointer.To(secretAPIKey),
+			}
+			smtc.getByNameInput.Name = &secretName
+			smtc.getByNameInput.SecretGroupName = &groupName
+			smtc.getByNameInput.SecretType = utilpointer.To(sm.Secret_SecretType_IamCredentials)
+
+			smtc.name = name
+			smtc.getByNameOutput = secret
+			smtc.ref.Key = groupName + "/" + iamCredentialsSecret + secretName
+			smtc.expectedSecret = secretAPIKey
+		}
+	}
+	setSecretIamByNameNew := funcSetSecretIamNew("testyname", "testGroup", "good case: iam_credenatials type - get API Key by name - new mechanism")
+
 	funcSetCertSecretTest := func(secret sm.SecretIntf, name, certType string, good bool) func(*secretManagerTestCase) {
 		return func(smtc *secretManagerTestCase) {
 			smtc.name = name
@@ -542,6 +588,7 @@ func TestIBMSecretManagerGetSecret(t *testing.T) {
 		makeValidSecretManagerTestCaseCustom(badSecretPublicCert),
 		makeValidSecretManagerTestCaseCustom(setSecretPrivateCert),
 		makeValidSecretManagerTestCaseCustom(badSecretPrivateCert),
+		makeValidSecretManagerTestCaseCustom(setSecretIamByNameNew),
 	}
 
 	sm := providerIBM{}
@@ -629,6 +676,25 @@ func TestGetSecretMap(t *testing.T) {
 		smtc.expectedData["apikey"] = []byte(secretAPIKey)
 	}
 
+	// good case: iam_credentials by name using new mechanism
+	setSecretIamByName := func(smtc *secretManagerTestCase) {
+		secret := &sm.IAMCredentialsSecret{
+			Name:       utilpointer.To("testyname"),
+			ID:         utilpointer.To(secretUUID),
+			SecretType: utilpointer.To(sm.Secret_SecretType_IamCredentials),
+			ApiKey:     utilpointer.To(secretAPIKey),
+		}
+		smtc.name = "good case: iam_credentials by name using new mechanism"
+		smtc.getByNameInput.Name = utilpointer.To("testyname")
+		smtc.getByNameInput.SecretGroupName = utilpointer.To("groupName")
+		smtc.getByNameInput.SecretType = utilpointer.To(sm.Secret_SecretType_IamCredentials)
+
+		smtc.getByNameOutput = secret
+		smtc.apiOutput = secret
+		smtc.ref.Key = "groupName/" + iamCredentialsSecret + "testyname"
+		smtc.expectedData["apikey"] = []byte(secretAPIKey)
+	}
+
 	// bad case: iam_credentials of a destroyed secret
 	badSecretIam := func(smtc *secretManagerTestCase) {
 		secret := &sm.IAMCredentialsSecret{
@@ -636,7 +702,7 @@ func TestGetSecretMap(t *testing.T) {
 			ID:         utilpointer.To(secretUUID),
 			SecretType: utilpointer.To(sm.Secret_SecretType_IamCredentials),
 		}
-		smtc.name = "good case: iam_credentials"
+		smtc.name = "bad case: iam_credentials of a destroyed secret"
 		smtc.apiInput.ID = utilpointer.To(secretUUID)
 		smtc.apiOutput = secret
 		smtc.ref.Key = iamCredentialsSecret + secretUUID
@@ -1086,6 +1152,7 @@ func TestGetSecretMap(t *testing.T) {
 		makeValidSecretManagerTestCaseCustom(setPrivateCertWithMetadata),
 		makeValidSecretManagerTestCaseCustom(setSecretKVWithMetadata),
 		makeValidSecretManagerTestCaseCustom(setSecretIamWithoutMetadata),
+		makeValidSecretManagerTestCaseCustom(setSecretIamByName),
 	}
 
 	sm := providerIBM{}