Browse Source

Fix the leak in GCPSM when the secret operator cannot find the secret. (#722)

* fix(gcp): Fix the leak in GCPSM when the secret operator cannot find the secret.

The IAM client has an internal gRPC connection,
but if the secret fetch fails, the goroutine created by the gRPC connection will leak.

Therefore, close the IAM client when the creation of the GCPSM client fails.

* test: fix build error on fakeIAMClient
castaneai 4 years ago
parent
commit
3fd3cc0186

+ 15 - 0
pkg/provider/gcp/secretmanager/secretsmanager.go

@@ -63,6 +63,7 @@ type GoogleSecretManagerClient interface {
 type ProviderGCP struct {
 	projectID           string
 	SecretManagerClient GoogleSecretManagerClient
+	gClient             *gClient
 }
 
 type gClient struct {
@@ -86,6 +87,10 @@ func (c *gClient) getTokenSource(ctx context.Context, store esv1alpha1.GenericSt
 	return google.DefaultTokenSource(ctx, CloudPlatformRole)
 }
 
+func (c *gClient) Close() error {
+	return c.workloadIdentity.Close()
+}
+
 func serviceAccountTokenSource(ctx context.Context, store esv1alpha1.GenericStore, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
 	spec := store.GetSpec()
 	if spec == nil || spec.Provider.GCPSM == nil {
@@ -146,6 +151,13 @@ func (sm *ProviderGCP) NewClient(ctx context.Context, store esv1alpha1.GenericSt
 		storeKind:        store.GetObjectKind().GroupVersionKind().Kind,
 		workloadIdentity: wi,
 	}
+	sm.gClient = &cliStore
+	defer func() {
+		// closes IAMClient to prevent gRPC connection leak in case of an error.
+		if sm.SecretManagerClient == nil {
+			_ = sm.gClient.Close()
+		}
+	}()
 
 	sm.projectID = cliStore.store.ProjectID
 
@@ -239,6 +251,9 @@ func (sm *ProviderGCP) GetSecretMap(ctx context.Context, ref esv1alpha1.External
 
 func (sm *ProviderGCP) Close(ctx context.Context) error {
 	err := sm.SecretManagerClient.Close()
+	if sm.gClient != nil {
+		err = sm.gClient.Close()
+	}
 	if err != nil {
 		return fmt.Errorf(errClientClose, err)
 	}

+ 5 - 0
pkg/provider/gcp/secretmanager/secretsmanager_workload_identity.go

@@ -62,6 +62,7 @@ type workloadIdentity struct {
 // interface to GCP IAM API.
 type IamClient interface {
 	GenerateAccessToken(ctx context.Context, req *credentialspb.GenerateAccessTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateAccessTokenResponse, error)
+	Close() error
 }
 
 // interface to securetoken/identitybindingtoken API.
@@ -154,6 +155,10 @@ func (w *workloadIdentity) TokenSource(ctx context.Context, store esv1alpha1.Gen
 	}), nil
 }
 
+func (w *workloadIdentity) Close() error {
+	return w.iamClient.Close()
+}
+
 func newIAMClient(ctx context.Context) (IamClient, error) {
 	iamOpts := []option.ClientOption{
 		option.WithUserAgent("external-secrets-operator"),

+ 4 - 0
pkg/provider/gcp/secretmanager/secretsmanager_workload_identity_test.go

@@ -357,6 +357,10 @@ func (f *fakeIAMClient) GenerateAccessToken(ctx context.Context, req *credential
 	return f.generateAccessTokenFunc(ctx, req, opts...)
 }
 
+func (f *fakeIAMClient) Close() error {
+	return nil
+}
+
 // fake SA Token Generator.
 type fakeSATokenGen struct {
 	GenerateFunc func(context.Context, string, string, string) (*authv1.TokenRequest, error)