Browse Source

Gc/fix/gcp pushsecret location replication (#4751)

* fix: push secret replication location now set as metadata

Signed-off-by: Gustavo Carvalho <gustavo@externalsecrets.com>

* fix: docs link

Signed-off-by: Gustavo Carvalho <gustavo@externalsecrets.com>

---------

Signed-off-by: Gustavo Carvalho <gustavo@externalsecrets.com>
Co-authored-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
Gustavo Fernandes de Carvalho 11 months ago
parent
commit
224d56617d

+ 28 - 52
docs/provider/google-secrets-manager.md

@@ -182,7 +182,7 @@ In the case of a `ClusterSecretStore`, you additionally have to define the servi
 
 #### Authorizing the Core Controller Pod
 
-Instead of managing authentication at the `SecretStore` and `ClusterSecretStore` level, you can give the [Core Controller](/api/components/) Pod's service account access to Secret Manager secrets using one of the two WIF approaches described in the previous sections.
+Instead of managing authentication at the `SecretStore` and `ClusterSecretStore` level, you can give the [Core Controller](../api/components/) Pod's service account access to Secret Manager secrets using one of the two WIF approaches described in the previous sections.
 
 To demonstrate this approach, we'll assume you installed ESO using Helm into the `external-secrets` namespace, with `external-secrets` as the release name:
 
@@ -291,18 +291,25 @@ spec:
 
 ### Location and Replication
 
-By default, secrets are automatically replicated across multiple regions. You can specify a single location for your secrets by setting the `location` field:
+By default, secrets are automatically replicated across multiple regions. You can specify a single location for your secrets by setting the `replicationLocation` field:
 
 ```yaml
-apiVersion: external-secrets.io/v1beta1
-kind: SecretStore
+apiVersion: external-secrets.io/v1alpha1
+kind: PushSecret
 metadata:
-  name: gcp-secret-store
+  name: pushsecret-example
 spec:
-  provider:
-    gcpsm:
-      projectID: my-project
-      location: us-east1  # Specify a single location
+  # ... other fields ...
+  data:
+    - match:
+        secretKey: mykey
+        remoteRef:
+          remoteKey: my-secret
+      metadata:
+        apiVersion: kubernetes.external-secrets.io/v1alpha1
+        kind: PushSecretMetadata`
+        spec:
+          replicationLocation: "us-east1"
 ```
 
 ### Customer-Managed Encryption Keys (CMEK)
@@ -346,50 +353,19 @@ spec:
       location: us-east1  # Required when using CMEK
 ```
 
-## Migration Guide: PushSecret Metadata Format (v0.11.x to v0.12.0)
-
-In version 0.12.0, the metadata format for PushSecrets has been standardized to use a structured format. If you're upgrading from v0.11.x, you'll need to update your PushSecret specifications.
+## Regional Secrets
+GCP Secret Manager Regional Secrets are available to be used with both ExternalSecrets and PushSecrets.
 
-### Old Format (v0.11.x)
-```yaml
-apiVersion: external-secrets.io/v1alpha1
-kind: PushSecret
-spec:
-  data:
-    - match:
-        secretKey: mykey
-        remoteRef:
-          remoteKey: my-secret
-      metadata:
-        annotations:
-          key1: "value1"
-        labels:
-          key2: "value2"
-        topics:
-          - "topic1"
-          - "topic2"
-```
+In order to achieve so, add a `location` to your SecretStore definition:
 
-### New Format (v0.12.0+)
 ```yaml
-apiVersion: external-secrets.io/v1alpha1
-kind: PushSecret
+apiVersion: external-secrets.io/v1beta1
+kind: SecretStore
+metadata:
+  name: gcp-secret-store
 spec:
-  data:
-    - match:
-        secretKey: mykey
-        remoteRef:
-          remoteKey: my-secret
-      metadata:
-        apiVersion: kubernetes.external-secrets.io/v1alpha1
-        kind: PushSecretMetadata
-        spec:
-          annotations:
-            key1: "value1"
-          labels:
-            key2: "value2"
-          topics:
-            - "topic1"
-            - "topic2"
-          cmekKeyName: "projects/my-project/locations/us-east1/keyRings/my-keyring/cryptoKeys/my-key"  # Optional: for CMEK
-```
+  provider:
+    gcpsm:
+      projectID: my-project
+      location: us-east1 # uses regional secrets on us-east1
+```

+ 12 - 15
pkg/provider/gcp/secretmanager/client.go

@@ -189,24 +189,21 @@ func (c *Client) PushSecret(ctx context.Context, secret *corev1.Secret, pushSecr
 			},
 		}
 
-		if c.store.Location != "" {
-			replica := &secretmanagerpb.Replication_UserManaged_Replica{
-				Location: c.store.Location,
+		if pushSecretData.GetMetadata() != nil {
+			replica := &secretmanagerpb.Replication_UserManaged_Replica{}
+			var err error
+			meta, err := metadata.ParseMetadataParameters[PushSecretMetadataSpec](pushSecretData.GetMetadata())
+			if err != nil {
+				return fmt.Errorf("failed to parse PushSecret metadata: %w", err)
 			}
-
-			if pushSecretData.GetMetadata() != nil {
-				var err error
-				meta, err := metadata.ParseMetadataParameters[PushSecretMetadataSpec](pushSecretData.GetMetadata())
-				if err != nil {
-					return fmt.Errorf("failed to parse PushSecret metadata: %w", err)
-				}
-				if meta != nil && meta.Spec.CMEKKeyName != "" {
-					replica.CustomerManagedEncryption = &secretmanagerpb.CustomerManagedEncryption{
-						KmsKeyName: meta.Spec.CMEKKeyName,
-					}
+			if meta != nil && meta.Spec.ReplicationLocation != "" {
+				replica.Location = meta.Spec.ReplicationLocation
+			}
+			if meta != nil && meta.Spec.CMEKKeyName != "" {
+				replica.CustomerManagedEncryption = &secretmanagerpb.CustomerManagedEncryption{
+					KmsKeyName: meta.Spec.CMEKKeyName,
 				}
 			}
-
 			replication = &secretmanagerpb.Replication{
 				Replication: &secretmanagerpb.Replication_UserManaged_{
 					UserManaged: &secretmanagerpb.Replication_UserManaged{

+ 11 - 2
pkg/provider/gcp/secretmanager/client_test.go

@@ -679,8 +679,17 @@ func TestPushSecret(t *testing.T) {
 		{
 			desc: "successfully pushes a secret with defined region",
 			args: args{
-				store:               &esv1.GCPSMProvider{ProjectID: smtc.projectID, Location: usEast1},
-				mock:                smtc.mockClient,
+				store: &esv1.GCPSMProvider{ProjectID: smtc.projectID},
+				mock:  smtc.mockClient,
+				Metadata: &apiextensionsv1.JSON{
+					Raw: []byte(`{
+						"apiVersion": "kubernetes.external-secrets.io/v1alpha1",
+						"kind": "PushSecretMetadata",
+						"spec": {
+							"replicationLocation": "us-east1"
+						}
+					}`),
+				},
 				GetSecretMockReturn: fakesm.SecretMockReturn{Secret: nil, Err: notFoundError},
 				CreateSecretMockReturn: fakesm.SecretMockReturn{Secret: &secretmanagerpb.Secret{
 					Name: "projects/default/secrets/baz",

+ 6 - 5
pkg/provider/gcp/secretmanager/push_secret.go

@@ -35,11 +35,12 @@ const (
 )
 
 type PushSecretMetadataSpec struct {
-	Annotations map[string]string             `json:"annotations,omitempty"`
-	Labels      map[string]string             `json:"labels,omitempty"`
-	Topics      []string                      `json:"topics,omitempty"`
-	MergePolicy PushSecretMetadataMergePolicy `json:"mergePolicy,omitempty"`
-	CMEKKeyName string                        `json:"cmekKeyName,omitempty"`
+	Annotations         map[string]string             `json:"annotations,omitempty"`
+	Labels              map[string]string             `json:"labels,omitempty"`
+	Topics              []string                      `json:"topics,omitempty"`
+	MergePolicy         PushSecretMetadataMergePolicy `json:"mergePolicy,omitempty"`
+	CMEKKeyName         string                        `json:"cmekKeyName,omitempty"`
+	ReplicationLocation string                        `json:"replicationLocation,omitempty"`
 }
 
 func newPushSecretBuilder(payload []byte, data esv1.PushSecretData) (pushSecretBuilder, error) {