Просмотр исходного кода

feat(openbao): add support for OpenBao Namespaces (#6527)

* OpenBao: add `namespace` and `auth.namespace` to API

Also updated outdated comment on auth struct.

And marked `auth` as optional. Until we have implemented `mTLS` in this provider probably everyone will want to configure an auth method, but technically it is not required.

Signed-off-by: Philipp Stehle <philipp.stehle@secretz.io>

* OpenBao: implement `namespace` and `auth.namespace` API

Signed-off-by: Philipp Stehle <philipp.stehle@secretz.io>

---------

Signed-off-by: Philipp Stehle <philipp.stehle@secretz.io>
Co-authored-by: Jean-Philippe Evrard <jean-philippe.evrard+rochepub@external.roche.com>
Philipp Stehle 1 день назад
Родитель
Сommit
8cfe1a44b5

+ 30 - 2
apis/externalsecrets/v1/secretstore_openbao_types.go

@@ -31,6 +31,8 @@ const (
 // +kubebuilder:validation:AtMostOneOf=caBundle;caProvider
 type OpenBaoProvider struct {
 	// Auth configures how secret-manager authenticates with the OpenBao server.
+	//
+	// +optional
 	Auth *OpenBaoAuth `json:"auth,omitempty"`
 
 	// PEM encoded CA bundle used to validate the OpenBao server certificate. If
@@ -47,6 +49,15 @@ type OpenBaoProvider struct {
 	// +optional
 	CAProvider *CAProvider `json:"caProvider,omitempty"`
 
+	// Name of the [OpenBao Namespace]. Namespaces is a set of features within
+	// OpenBao that allows OpenBao environments to support secure multi-tenancy.
+	// e.g: "ns1".
+	//
+	// +optional
+	//
+	// [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+	Namespace *string `json:"namespace,omitempty"`
+
 	// Server is the connection address for the OpenBao server, e.g: `https://openbao.example.com:8200`.
 	Server string `json:"server"`
 
@@ -68,10 +79,16 @@ type OpenBaoProvider struct {
 }
 
 // OpenBaoAuth is the configuration used to authenticate with an OpenBao server.
-// Currently only token-based authentication is supported via `tokenSecretRef`.
+// Currently the following authentication methods are supported: [AppRole],
+// [Token] and [UserPass]
+//
 // Additional authentication methods are planned for future releases.
 //
-// +kubebuilder:validation:MaxProperties=1
+// +kubebuilder:validation:ExactlyOneOf=appRole;tokenSecretRef;userPass
+//
+// [AppRole]: https://openbao.org/docs/auth/approle/
+// [Token]: https://openbao.org/docs/auth/token/
+// [UserPass]: https://openbao.org/docs/auth/userpass/
 type OpenBaoAuth struct {
 	// AppRole authenticates with OpenBao using the [App Role auth mechanism],
 	// with the role and secret stored in a Kubernetes Secret resource.
@@ -81,6 +98,17 @@ type OpenBaoAuth struct {
 	// +optional
 	AppRole *OpenBaoAppRole `json:"appRole,omitempty"`
 
+	// Name of the [OpenBao Namespace] to authenticate to. This can be different
+	// than the namespace your secret is in. Namespaces is a set of features
+	// within OpenBao that allows OpenBao environments to support secure
+	// multi-tenancy. e.g: "ns1". This will default to OpenBao.Namespace field
+	// if set, or empty otherwise
+	//
+	// +optional
+	//
+	// [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+	Namespace *string `json:"namespace,omitempty"`
+
 	// TokenSecretRef authenticates with OpenBao by presenting a token.
 	//
 	// +optional

+ 10 - 0
apis/externalsecrets/v1/zz_generated.deepcopy.go

@@ -3096,6 +3096,11 @@ func (in *OpenBaoAuth) DeepCopyInto(out *OpenBaoAuth) {
 		*out = new(OpenBaoAppRole)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.Namespace != nil {
+		in, out := &in.Namespace, &out.Namespace
+		*out = new(string)
+		**out = **in
+	}
 	if in.TokenSecretRef != nil {
 		in, out := &in.TokenSecretRef, &out.TokenSecretRef
 		*out = new(apismetav1.SecretKeySelector)
@@ -3136,6 +3141,11 @@ func (in *OpenBaoProvider) DeepCopyInto(out *OpenBaoProvider) {
 		*out = new(CAProvider)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.Namespace != nil {
+		in, out := &in.Namespace, &out.Namespace
+		*out = new(string)
+		**out = **in
+	}
 	if in.Path != nil {
 		in, out := &in.Path, &out.Path
 		*out = new(string)

+ 23 - 1
config/crds/bases/external-secrets.io_clustersecretstores.yaml

@@ -4180,7 +4180,6 @@ spec:
                       auth:
                         description: Auth configures how secret-manager authenticates
                           with the OpenBao server.
-                        maxProperties: 1
                         properties:
                           appRole:
                             description: |-
@@ -4272,6 +4271,16 @@ spec:
                                 must be set
                               rule: '[has(self.roleId),has(self.roleRef)].filter(x,x==true).size()
                                 == 1'
+                          namespace:
+                            description: |-
+                              Name of the [OpenBao Namespace] to authenticate to. This can be different
+                              than the namespace your secret is in. Namespaces is a set of features
+                              within OpenBao that allows OpenBao environments to support secure
+                              multi-tenancy. e.g: "ns1". This will default to OpenBao.Namespace field
+                              if set, or empty otherwise
+
+                              [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+                            type: string
                           tokenSecretRef:
                             description: TokenSecretRef authenticates with OpenBao
                               by presenting a token.
@@ -4354,6 +4363,11 @@ spec:
                             - username
                             type: object
                         type: object
+                        x-kubernetes-validations:
+                        - message: exactly one of the fields in [appRole tokenSecretRef
+                            userPass] must be set
+                          rule: '[has(self.appRole),has(self.tokenSecretRef),has(self.userPass)].filter(x,x==true).size()
+                            == 1'
                       caBundle:
                         description: |-
                           PEM encoded CA bundle used to validate the OpenBao server certificate. If
@@ -4400,6 +4414,14 @@ spec:
                         - name
                         - type
                         type: object
+                      namespace:
+                        description: |-
+                          Name of the [OpenBao Namespace]. Namespaces is a set of features within
+                          OpenBao that allows OpenBao environments to support secure multi-tenancy.
+                          e.g: "ns1".
+
+                          [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+                        type: string
                       path:
                         description: |-
                           Path is the mount path of the OpenBao KV backend endpoint, e.g:

+ 23 - 1
config/crds/bases/external-secrets.io_secretstores.yaml

@@ -4180,7 +4180,6 @@ spec:
                       auth:
                         description: Auth configures how secret-manager authenticates
                           with the OpenBao server.
-                        maxProperties: 1
                         properties:
                           appRole:
                             description: |-
@@ -4272,6 +4271,16 @@ spec:
                                 must be set
                               rule: '[has(self.roleId),has(self.roleRef)].filter(x,x==true).size()
                                 == 1'
+                          namespace:
+                            description: |-
+                              Name of the [OpenBao Namespace] to authenticate to. This can be different
+                              than the namespace your secret is in. Namespaces is a set of features
+                              within OpenBao that allows OpenBao environments to support secure
+                              multi-tenancy. e.g: "ns1". This will default to OpenBao.Namespace field
+                              if set, or empty otherwise
+
+                              [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+                            type: string
                           tokenSecretRef:
                             description: TokenSecretRef authenticates with OpenBao
                               by presenting a token.
@@ -4354,6 +4363,11 @@ spec:
                             - username
                             type: object
                         type: object
+                        x-kubernetes-validations:
+                        - message: exactly one of the fields in [appRole tokenSecretRef
+                            userPass] must be set
+                          rule: '[has(self.appRole),has(self.tokenSecretRef),has(self.userPass)].filter(x,x==true).size()
+                            == 1'
                       caBundle:
                         description: |-
                           PEM encoded CA bundle used to validate the OpenBao server certificate. If
@@ -4400,6 +4414,14 @@ spec:
                         - name
                         - type
                         type: object
+                      namespace:
+                        description: |-
+                          Name of the [OpenBao Namespace]. Namespaces is a set of features within
+                          OpenBao that allows OpenBao environments to support secure multi-tenancy.
+                          e.g: "ns1".
+
+                          [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+                        type: string
                       path:
                         description: |-
                           Path is the mount path of the OpenBao KV backend endpoint, e.g:

+ 42 - 2
deploy/crds/bundle.yaml

@@ -6210,7 +6210,6 @@ spec:
                       properties:
                         auth:
                           description: Auth configures how secret-manager authenticates with the OpenBao server.
-                          maxProperties: 1
                           properties:
                             appRole:
                               description: |-
@@ -6298,6 +6297,16 @@ spec:
                               x-kubernetes-validations:
                                 - message: exactly one of the fields in [roleId roleRef] must be set
                                   rule: '[has(self.roleId),has(self.roleRef)].filter(x,x==true).size() == 1'
+                            namespace:
+                              description: |-
+                                Name of the [OpenBao Namespace] to authenticate to. This can be different
+                                than the namespace your secret is in. Namespaces is a set of features
+                                within OpenBao that allows OpenBao environments to support secure
+                                multi-tenancy. e.g: "ns1". This will default to OpenBao.Namespace field
+                                if set, or empty otherwise
+
+                                [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+                              type: string
                             tokenSecretRef:
                               description: TokenSecretRef authenticates with OpenBao by presenting a token.
                               properties:
@@ -6376,6 +6385,9 @@ spec:
                                 - username
                               type: object
                           type: object
+                          x-kubernetes-validations:
+                            - message: exactly one of the fields in [appRole tokenSecretRef userPass] must be set
+                              rule: '[has(self.appRole),has(self.tokenSecretRef),has(self.userPass)].filter(x,x==true).size() == 1'
                         caBundle:
                           description: |-
                             PEM encoded CA bundle used to validate the OpenBao server certificate. If
@@ -6419,6 +6431,14 @@ spec:
                             - name
                             - type
                           type: object
+                        namespace:
+                          description: |-
+                            Name of the [OpenBao Namespace]. Namespaces is a set of features within
+                            OpenBao that allows OpenBao environments to support secure multi-tenancy.
+                            e.g: "ns1".
+
+                            [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+                          type: string
                         path:
                           description: |-
                             Path is the mount path of the OpenBao KV backend endpoint, e.g:
@@ -18925,7 +18945,6 @@ spec:
                       properties:
                         auth:
                           description: Auth configures how secret-manager authenticates with the OpenBao server.
-                          maxProperties: 1
                           properties:
                             appRole:
                               description: |-
@@ -19013,6 +19032,16 @@ spec:
                               x-kubernetes-validations:
                                 - message: exactly one of the fields in [roleId roleRef] must be set
                                   rule: '[has(self.roleId),has(self.roleRef)].filter(x,x==true).size() == 1'
+                            namespace:
+                              description: |-
+                                Name of the [OpenBao Namespace] to authenticate to. This can be different
+                                than the namespace your secret is in. Namespaces is a set of features
+                                within OpenBao that allows OpenBao environments to support secure
+                                multi-tenancy. e.g: "ns1". This will default to OpenBao.Namespace field
+                                if set, or empty otherwise
+
+                                [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+                              type: string
                             tokenSecretRef:
                               description: TokenSecretRef authenticates with OpenBao by presenting a token.
                               properties:
@@ -19091,6 +19120,9 @@ spec:
                                 - username
                               type: object
                           type: object
+                          x-kubernetes-validations:
+                            - message: exactly one of the fields in [appRole tokenSecretRef userPass] must be set
+                              rule: '[has(self.appRole),has(self.tokenSecretRef),has(self.userPass)].filter(x,x==true).size() == 1'
                         caBundle:
                           description: |-
                             PEM encoded CA bundle used to validate the OpenBao server certificate. If
@@ -19134,6 +19166,14 @@ spec:
                             - name
                             - type
                           type: object
+                        namespace:
+                          description: |-
+                            Name of the [OpenBao Namespace]. Namespaces is a set of features within
+                            OpenBao that allows OpenBao environments to support secure multi-tenancy.
+                            e.g: "ns1".
+
+                            [OpenBao Namespace]: https://openbao.org/docs/concepts/namespaces/
+                          type: string
                         path:
                           description: |-
                             Path is the mount path of the OpenBao KV backend endpoint, e.g:

+ 34 - 2
docs/api/spec.md

@@ -8555,8 +8555,9 @@ resource is used as the app role secret.</p>
 </p>
 <p>
 <p>OpenBaoAuth is the configuration used to authenticate with an OpenBao server.
-Currently only token-based authentication is supported via <code>tokenSecretRef</code>.
-Additional authentication methods are planned for future releases.</p>
+Currently the following authentication methods are supported: <a href="https://openbao.org/docs/auth/approle/">AppRole</a>,
+<a href="https://openbao.org/docs/auth/token/">Token</a> and <a href="https://openbao.org/docs/auth/userpass/">UserPass</a></p>
+<p>Additional authentication methods are planned for future releases.</p>
 </p>
 <table>
 <thead>
@@ -8583,6 +8584,22 @@ with the role and secret stored in a Kubernetes Secret resource.</p>
 </tr>
 <tr>
 <td>
+<code>namespace</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Name of the <a href="https://openbao.org/docs/concepts/namespaces/">OpenBao Namespace</a> to authenticate to. This can be different
+than the namespace your secret is in. Namespaces is a set of features
+within OpenBao that allows OpenBao environments to support secure
+multi-tenancy. e.g: &ldquo;ns1&rdquo;. This will default to OpenBao.Namespace field
+if set, or empty otherwise</p>
+</td>
+</tr>
+<tr>
+<td>
 <code>tokenSecretRef</code></br>
 <em>
 <a href="https://pkg.go.dev/github.com/external-secrets/external-secrets/apis/meta/v1#SecretKeySelector">
@@ -8660,6 +8677,7 @@ OpenBaoAuth
 </em>
 </td>
 <td>
+<em>(Optional)</em>
 <p>Auth configures how secret-manager authenticates with the OpenBao server.</p>
 </td>
 </tr>
@@ -8695,6 +8713,20 @@ certificates are used to validate the TLS connection.</p>
 </tr>
 <tr>
 <td>
+<code>namespace</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Name of the <a href="https://openbao.org/docs/concepts/namespaces/">OpenBao Namespace</a>. Namespaces is a set of features within
+OpenBao that allows OpenBao environments to support secure multi-tenancy.
+e.g: &ldquo;ns1&rdquo;.</p>
+</td>
+</tr>
+<tr>
+<td>
 <code>server</code></br>
 <em>
 string

+ 18 - 2
providers/v1/openbao/client.go

@@ -96,6 +96,11 @@ func (c *client) setup(ctx context.Context, kube k8sClient.Client, namespace str
 	if err != nil {
 		return err
 	}
+
+	if c.store.Namespace != nil {
+		client.SetNamespace(*c.store.Namespace)
+	}
+
 	c.client = client
 
 	return c.setupAuth(ctx, kube, namespace, provider)
@@ -155,8 +160,19 @@ func (c *client) setupAuth(ctx context.Context, kube k8sClient.Client, namespace
 		return fmt.Errorf("unsupported auth method") // this should not happen, because of CRD validation (unless a case is missing above)
 	}
 
-	_, err := c.client.Auth().Login(ctx, auth)
-	return err
+	authClient := c.client
+	if c.store.Auth.Namespace != nil {
+		authClient = authClient.WithNamespace(*c.store.Auth.Namespace)
+	}
+
+	_, err := authClient.Auth().Login(ctx, auth)
+	if err != nil {
+		return err
+	}
+
+	c.client.SetToken(authClient.Token())
+
+	return nil
 }
 
 func (c *client) Close(_ context.Context) error {

+ 68 - 0
providers/v1/openbao/provider_test.go

@@ -482,6 +482,74 @@ func TestProvider_Auth_UserPass(t *testing.T) {
 	Expect(data).To(BeEquivalentTo("bazz"))
 }
 
+func TestProvider_BaoNamespaces(t *testing.T) {
+	v := esv1.OpenBaoKVStoreV2
+
+	kube, provider := setupProvider(t, &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "auth",
+			Namespace: "default",
+		},
+		Data: map[string][]byte{
+			"token":    []byte("root"),
+			"password": []byte("bob4ever"),
+		},
+	})
+
+	store := makeValidSecretStoreWithVersion(v)
+	store.Spec.Provider.OpenBao.Namespace = new("my-namespace")
+	store.Spec.Provider.OpenBao.Path = nil
+	store.Spec.Provider.OpenBao.Auth.TokenSecretRef.Name = "auth"
+
+	t.Run("WithToken", func(t *testing.T) {
+		RegisterTestingT(t)
+
+		client, err := provider.NewClient(t.Context(), store, kube, "default")
+		Expect(err).NotTo(HaveOccurred())
+		Expect(client).NotTo(BeNil())
+		t.Cleanup(func() {
+			client.Close(t.Context())
+		})
+
+		data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
+			Key:      "foo",
+			Property: "namespaced-bar",
+		})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(data).To(BeEquivalentTo("namespaced-bazz"))
+	})
+
+	store.Spec.Provider.OpenBao.Auth = &esv1.OpenBaoAuth{
+		UserPass: &esv1.OpenBaoUserPassAuth{
+			Path:     "customuserpasspath",
+			Username: "alice",
+			SecretRef: esmeta.SecretKeySelector{
+				Name: "auth",
+				Key:  "password",
+			},
+		},
+		Namespace: new(""),
+	}
+
+	t.Run("WithUserPass", func(t *testing.T) {
+		RegisterTestingT(t)
+
+		client, err := provider.NewClient(t.Context(), store, kube, "default")
+		Expect(err).NotTo(HaveOccurred())
+		Expect(client).NotTo(BeNil())
+		t.Cleanup(func() {
+			client.Close(t.Context())
+		})
+
+		data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
+			Key:      "foo",
+			Property: "namespaced-bar",
+		})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(data).To(BeEquivalentTo("namespaced-bazz"))
+	})
+}
+
 func TestProvider_Validate(t *testing.T) {
 	RegisterTestingT(t)
 

+ 179 - 0
providers/v1/openbao/testdata/http/TestProvider_BaoNamespaces.yaml

@@ -0,0 +1,179 @@
+---
+version: 2
+interactions:
+    - id: 0
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        host: localhost:8200
+        headers:
+            X-Vault-Namespace:
+                - my-namespace
+            X-Vault-Request:
+                - "true"
+            X-Vault-Token:
+                - root
+        url: http://localhost:8200/v1/kv/data/foo
+        method: GET
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 336
+        body: |-
+            {
+              "auth": null,
+              "data": {
+                "data": {
+                  "namespaced-bar": "namespaced-bazz"
+                },
+                "metadata": {
+                  "created_time": "2099-09-09T09:09:09.09Z",
+                  "custom_metadata": null,
+                  "deletion_time": "",
+                  "destroyed": false,
+                  "version": 1
+                }
+              },
+              "lease_duration": 0,
+              "lease_id": "",
+              "renewable": false,
+              "request_id": "00000000-0000-0000-0000-000000000000",
+              "warnings": null,
+              "wrap_info": null
+            }
+        headers:
+            Cache-Control:
+                - no-store
+            Content-Length:
+                - "336"
+            Content-Type:
+                - application/json
+            Strict-Transport-Security:
+                - max-age=31536000; includeSubDomains
+            X-Vault-Namespace:
+                - my-namespace
+        status: 200 OK
+        code: 200
+        duration: 0s
+    - id: 1
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 23
+        host: localhost:8200
+        body: '{"password":"bob4ever"}'
+        headers:
+            X-Vault-Request:
+                - "true"
+        url: http://localhost:8200/v1/auth/customuserpasspath/login/alice
+        method: PUT
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 511
+        body: |-
+            {
+              "auth": {
+                "accessor": "AbCdEfGHiJk123",
+                "client_token": "s.fakeTOKEN123",
+                "entity_id": "00000000-0000-0000-0000-000000000000",
+                "lease_duration": 2764800,
+                "metadata": {
+                  "username": "alice"
+                },
+                "mfa_requirement": null,
+                "num_uses": 0,
+                "orphan": true,
+                "policies": [
+                  "default",
+                  "read-kv"
+                ],
+                "renewable": true,
+                "token_policies": [
+                  "default",
+                  "read-kv"
+                ],
+                "token_type": "service"
+              },
+              "data": null,
+              "lease_duration": 0,
+              "lease_id": "",
+              "renewable": false,
+              "request_id": "00000000-0000-0000-0000-000000000000",
+              "warnings": null,
+              "wrap_info": null
+            }
+        headers:
+            Cache-Control:
+                - no-store
+            Content-Length:
+                - "511"
+            Content-Type:
+                - application/json
+            Strict-Transport-Security:
+                - max-age=31536000; includeSubDomains
+        status: 200 OK
+        code: 200
+        duration: 0s
+    - id: 2
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        host: localhost:8200
+        headers:
+            X-Vault-Namespace:
+                - my-namespace
+            X-Vault-Request:
+                - "true"
+            X-Vault-Token:
+                - s.fakeTOKEN123
+        url: http://localhost:8200/v1/kv/data/foo
+        method: GET
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 336
+        body: |-
+            {
+              "auth": null,
+              "data": {
+                "data": {
+                  "namespaced-bar": "namespaced-bazz"
+                },
+                "metadata": {
+                  "created_time": "2099-09-09T09:09:09.09Z",
+                  "custom_metadata": null,
+                  "deletion_time": "",
+                  "destroyed": false,
+                  "version": 1
+                }
+              },
+              "lease_duration": 0,
+              "lease_id": "",
+              "renewable": false,
+              "request_id": "00000000-0000-0000-0000-000000000000",
+              "warnings": null,
+              "wrap_info": null
+            }
+        headers:
+            Cache-Control:
+                - no-store
+            Content-Length:
+                - "336"
+            Content-Type:
+                - application/json
+            Strict-Transport-Security:
+                - max-age=31536000; includeSubDomains
+            X-Vault-Namespace:
+                - my-namespace
+        status: 200 OK
+        code: 200
+        duration: 0s

+ 6 - 6
providers/v1/openbao/testdata/http/TestProvider_Validate.yaml

@@ -44,7 +44,7 @@ interactions:
                   "version": "1"
                 },
                 "plugin_version": "",
-                "running_plugin_version": "v2.5.4+builtin.bao",
+                "running_plugin_version": "v2.5.5+builtin.bao",
                 "running_sha256": "",
                 "seal_wrap": false,
                 "type": "kv",
@@ -62,7 +62,7 @@ interactions:
               "plugin_version": "",
               "renewable": false,
               "request_id": "00000000-0000-0000-0000-000000000000",
-              "running_plugin_version": "v2.5.4+builtin.bao",
+              "running_plugin_version": "v2.5.5+builtin.bao",
               "running_sha256": "",
               "seal_wrap": false,
               "type": "kv",
@@ -125,7 +125,7 @@ interactions:
                   "version": "1"
                 },
                 "plugin_version": "",
-                "running_plugin_version": "v2.5.4+builtin.bao",
+                "running_plugin_version": "v2.5.5+builtin.bao",
                 "running_sha256": "",
                 "seal_wrap": false,
                 "type": "kv",
@@ -143,7 +143,7 @@ interactions:
               "plugin_version": "",
               "renewable": false,
               "request_id": "00000000-0000-0000-0000-000000000000",
-              "running_plugin_version": "v2.5.4+builtin.bao",
+              "running_plugin_version": "v2.5.5+builtin.bao",
               "running_sha256": "",
               "seal_wrap": false,
               "type": "kv",
@@ -209,7 +209,7 @@ interactions:
                 "local": false,
                 "options": null,
                 "plugin_version": "",
-                "running_plugin_version": "v2.5.4+builtin.bao",
+                "running_plugin_version": "v2.5.5+builtin.bao",
                 "running_sha256": "",
                 "seal_wrap": true,
                 "type": "system",
@@ -224,7 +224,7 @@ interactions:
               "plugin_version": "",
               "renewable": false,
               "request_id": "00000000-0000-0000-0000-000000000000",
-              "running_plugin_version": "v2.5.4+builtin.bao",
+              "running_plugin_version": "v2.5.5+builtin.bao",
               "running_sha256": "",
               "seal_wrap": true,
               "type": "system",

+ 4 - 0
providers/v1/openbao/testdata/init-bao.sh

@@ -14,3 +14,7 @@ bao kv put -mount=secret_v1 foo bar=bazz_v1 lorem=ipsum_v1
 bao policy write read-kv testdata/policy-read-kv.hcl
 bao auth enable --path=customuserpasspath userpass
 bao write auth/customuserpasspath/users/alice password=bob4ever token_policies=read-kv
+
+bao namespace create my-namespace
+bao secrets enable -version=2 --namespace=my-namespace kv
+bao kv put -mount=kv --namespace=my-namespace foo namespaced-bar=namespaced-bazz

+ 4 - 0
providers/v1/openbao/testdata/policy-read-kv.hcl

@@ -1,3 +1,7 @@
 path "secret/*" {
   capabilities = ["read"]
 }
+
+path "my-namespace/kv/*" {
+  capabilities = ["read"]
+}

+ 2 - 0
tests/__snapshot__/clustersecretstore-v1.yaml

@@ -631,6 +631,7 @@ spec:
             key: string
             name: string
             namespace: string
+        namespace: string
         tokenSecretRef:
           key: string
           name: string
@@ -648,6 +649,7 @@ spec:
         name: string
         namespace: string
         type: "Secret" # "Secret", "ConfigMap"
+      namespace: string
       path: string
       server: string
       version: "v2"

+ 2 - 0
tests/__snapshot__/secretstore-v1.yaml

@@ -631,6 +631,7 @@ spec:
             key: string
             name: string
             namespace: string
+        namespace: string
         tokenSecretRef:
           key: string
           name: string
@@ -648,6 +649,7 @@ spec:
         name: string
         namespace: string
         type: "Secret" # "Secret", "ConfigMap"
+      namespace: string
       path: string
       server: string
       version: "v2"