Browse Source

feat(provider): add Barbican provider support (#5398)

Co-authored-by: Gergely Brautigam <skarlso777@gmail.com>
Co-authored-by: Gustavo Fernandes de Carvalho <17139678+gusfcarvalho@users.noreply.github.com>
Rodrigo Kellermann 4 months ago
parent
commit
14d59bd4aa

+ 49 - 0
apis/externalsecrets/v1/secretstore_barbican_types.go

@@ -0,0 +1,49 @@
+/*
+Copyright © 2025 ESO Maintainer Team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1
+
+import (
+	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+)
+
+// BarbicanProviderUsernameRef defines a reference to a secret containing username for the Barbican provider.
+// +kubebuilder:validation:MinProperties=1
+// +kubebuilder:validation:MaxProperties=1
+type BarbicanProviderUsernameRef struct {
+	Value     string                    `json:"value,omitempty"`
+	SecretRef *esmeta.SecretKeySelector `json:"secretRef,omitempty"`
+}
+
+// BarbicanProviderPasswordRef defines a reference to a secret containing password for the Barbican provider.
+type BarbicanProviderPasswordRef struct {
+	SecretRef *esmeta.SecretKeySelector `json:"secretRef"`
+}
+
+// BarbicanProvider setup a store to sync secrets with barbican.
+type BarbicanProvider struct {
+	AuthURL    string              `json:"authURL,omitempty"`
+	TenantName string              `json:"tenantName,omitempty"`
+	DomainName string              `json:"domainName,omitempty"`
+	Region     string              `json:"region,omitempty"`
+	Auth       BarbicanAuth        `json:"auth"`
+}
+
+// BarbicanAuth contains the authentication information for Barbican.
+type BarbicanAuth struct {
+	Username BarbicanProviderUsernameRef `json:"username"`
+	Password BarbicanProviderPasswordRef `json:"password"`
+}

+ 5 - 0
apis/externalsecrets/v1/secretstore_types.go

@@ -215,9 +215,14 @@ type SecretStoreProvider struct {
 	// Volcengine configures this store to sync secrets using the Volcengine provider
 	// Volcengine configures this store to sync secrets using the Volcengine provider
 	// +optional
 	// +optional
 	Volcengine *VolcengineProvider `json:"volcengine,omitempty"`
 	Volcengine *VolcengineProvider `json:"volcengine,omitempty"`
+
 	// Ngrok configures this store to sync secrets using the ngrok provider.
 	// Ngrok configures this store to sync secrets using the ngrok provider.
 	// +optional
 	// +optional
 	Ngrok *NgrokProvider `json:"ngrok,omitempty"`
 	Ngrok *NgrokProvider `json:"ngrok,omitempty"`
+
+	// Barbican configures this store to sync secrets using the OpenStack Barbican provider
+	// +optional
+	Barbican *BarbicanProvider `json:"barbican,omitempty"`
 }
 }
 
 
 // CAProviderType defines the type of provider for certificate authority.
 // CAProviderType defines the type of provider for certificate authority.

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

@@ -501,6 +501,79 @@ func (in *AzureKVProvider) DeepCopy() *AzureKVProvider {
 }
 }
 
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BarbicanAuth) DeepCopyInto(out *BarbicanAuth) {
+	*out = *in
+	in.Username.DeepCopyInto(&out.Username)
+	in.Password.DeepCopyInto(&out.Password)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BarbicanAuth.
+func (in *BarbicanAuth) DeepCopy() *BarbicanAuth {
+	if in == nil {
+		return nil
+	}
+	out := new(BarbicanAuth)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BarbicanProvider) DeepCopyInto(out *BarbicanProvider) {
+	*out = *in
+	in.Auth.DeepCopyInto(&out.Auth)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BarbicanProvider.
+func (in *BarbicanProvider) DeepCopy() *BarbicanProvider {
+	if in == nil {
+		return nil
+	}
+	out := new(BarbicanProvider)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BarbicanProviderPasswordRef) DeepCopyInto(out *BarbicanProviderPasswordRef) {
+	*out = *in
+	if in.SecretRef != nil {
+		in, out := &in.SecretRef, &out.SecretRef
+		*out = new(apismetav1.SecretKeySelector)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BarbicanProviderPasswordRef.
+func (in *BarbicanProviderPasswordRef) DeepCopy() *BarbicanProviderPasswordRef {
+	if in == nil {
+		return nil
+	}
+	out := new(BarbicanProviderPasswordRef)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BarbicanProviderUsernameRef) DeepCopyInto(out *BarbicanProviderUsernameRef) {
+	*out = *in
+	if in.SecretRef != nil {
+		in, out := &in.SecretRef, &out.SecretRef
+		*out = new(apismetav1.SecretKeySelector)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BarbicanProviderUsernameRef.
+func (in *BarbicanProviderUsernameRef) DeepCopy() *BarbicanProviderUsernameRef {
+	if in == nil {
+		return nil
+	}
+	out := new(BarbicanProviderUsernameRef)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *BeyondTrustProviderSecretRef) DeepCopyInto(out *BeyondTrustProviderSecretRef) {
 func (in *BeyondTrustProviderSecretRef) DeepCopyInto(out *BeyondTrustProviderSecretRef) {
 	*out = *in
 	*out = *in
 	if in.SecretRef != nil {
 	if in.SecretRef != nil {
@@ -3416,6 +3489,11 @@ func (in *SecretStoreProvider) DeepCopyInto(out *SecretStoreProvider) {
 		*out = new(NgrokProvider)
 		*out = new(NgrokProvider)
 		(*in).DeepCopyInto(*out)
 		(*in).DeepCopyInto(*out)
 	}
 	}
+	if in.Barbican != nil {
+		in, out := &in.Barbican, &out.Barbican
+		*out = new(BarbicanProvider)
+		(*in).DeepCopyInto(*out)
+	}
 }
 }
 
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreProvider.
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreProvider.

+ 97 - 0
config/crds/bases/external-secrets.io_clustersecretstores.yaml

@@ -904,6 +904,103 @@ spec:
                     required:
                     required:
                     - vaultUrl
                     - vaultUrl
                     type: object
                     type: object
+                  barbican:
+                    description: Barbican configures this store to sync secrets using
+                      the OpenStack Barbican provider
+                    properties:
+                      auth:
+                        description: BarbicanAuth contains the authentication information
+                          for Barbican.
+                        properties:
+                          password:
+                            description: BarbicanProviderPasswordRef defines a reference
+                              to a secret containing password for the Barbican provider.
+                            properties:
+                              secretRef:
+                                description: |-
+                                  SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                                  In some instances, `key` is a required field.
+                                properties:
+                                  key:
+                                    description: |-
+                                      A key in the referenced Secret.
+                                      Some instances of this field may be defaulted, in others it may be required.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[-._a-zA-Z0-9]+$
+                                    type: string
+                                  name:
+                                    description: The name of the Secret resource being
+                                      referred to.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: |-
+                                      The namespace of the Secret resource being referred to.
+                                      Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                type: object
+                            required:
+                            - secretRef
+                            type: object
+                          username:
+                            description: BarbicanProviderUsernameRef defines a reference
+                              to a secret containing username for the Barbican provider.
+                            maxProperties: 1
+                            minProperties: 1
+                            properties:
+                              secretRef:
+                                description: |-
+                                  SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                                  In some instances, `key` is a required field.
+                                properties:
+                                  key:
+                                    description: |-
+                                      A key in the referenced Secret.
+                                      Some instances of this field may be defaulted, in others it may be required.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[-._a-zA-Z0-9]+$
+                                    type: string
+                                  name:
+                                    description: The name of the Secret resource being
+                                      referred to.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: |-
+                                      The namespace of the Secret resource being referred to.
+                                      Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                type: object
+                              value:
+                                type: string
+                            type: object
+                        required:
+                        - password
+                        - username
+                        type: object
+                      authURL:
+                        type: string
+                      domainName:
+                        type: string
+                      region:
+                        type: string
+                      tenantName:
+                        type: string
+                    required:
+                    - auth
+                    type: object
                   beyondtrust:
                   beyondtrust:
                     description: Beyondtrust configures this store to sync secrets
                     description: Beyondtrust configures this store to sync secrets
                       using Password Safe provider.
                       using Password Safe provider.

+ 97 - 0
config/crds/bases/external-secrets.io_secretstores.yaml

@@ -904,6 +904,103 @@ spec:
                     required:
                     required:
                     - vaultUrl
                     - vaultUrl
                     type: object
                     type: object
+                  barbican:
+                    description: Barbican configures this store to sync secrets using
+                      the OpenStack Barbican provider
+                    properties:
+                      auth:
+                        description: BarbicanAuth contains the authentication information
+                          for Barbican.
+                        properties:
+                          password:
+                            description: BarbicanProviderPasswordRef defines a reference
+                              to a secret containing password for the Barbican provider.
+                            properties:
+                              secretRef:
+                                description: |-
+                                  SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                                  In some instances, `key` is a required field.
+                                properties:
+                                  key:
+                                    description: |-
+                                      A key in the referenced Secret.
+                                      Some instances of this field may be defaulted, in others it may be required.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[-._a-zA-Z0-9]+$
+                                    type: string
+                                  name:
+                                    description: The name of the Secret resource being
+                                      referred to.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: |-
+                                      The namespace of the Secret resource being referred to.
+                                      Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                type: object
+                            required:
+                            - secretRef
+                            type: object
+                          username:
+                            description: BarbicanProviderUsernameRef defines a reference
+                              to a secret containing username for the Barbican provider.
+                            maxProperties: 1
+                            minProperties: 1
+                            properties:
+                              secretRef:
+                                description: |-
+                                  SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                                  In some instances, `key` is a required field.
+                                properties:
+                                  key:
+                                    description: |-
+                                      A key in the referenced Secret.
+                                      Some instances of this field may be defaulted, in others it may be required.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[-._a-zA-Z0-9]+$
+                                    type: string
+                                  name:
+                                    description: The name of the Secret resource being
+                                      referred to.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: |-
+                                      The namespace of the Secret resource being referred to.
+                                      Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                type: object
+                              value:
+                                type: string
+                            type: object
+                        required:
+                        - password
+                        - username
+                        type: object
+                      authURL:
+                        type: string
+                      domainName:
+                        type: string
+                      region:
+                        type: string
+                      tenantName:
+                        type: string
+                    required:
+                    - auth
+                    type: object
                   beyondtrust:
                   beyondtrust:
                     description: Beyondtrust configures this store to sync secrets
                     description: Beyondtrust configures this store to sync secrets
                       using Password Safe provider.
                       using Password Safe provider.

+ 182 - 0
deploy/crds/bundle.yaml

@@ -2947,6 +2947,97 @@ spec:
                       required:
                       required:
                         - vaultUrl
                         - vaultUrl
                       type: object
                       type: object
+                    barbican:
+                      description: Barbican configures this store to sync secrets using the OpenStack Barbican provider
+                      properties:
+                        auth:
+                          description: BarbicanAuth contains the authentication information for Barbican.
+                          properties:
+                            password:
+                              description: BarbicanProviderPasswordRef defines a reference to a secret containing password for the Barbican provider.
+                              properties:
+                                secretRef:
+                                  description: |-
+                                    SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                                    In some instances, `key` is a required field.
+                                  properties:
+                                    key:
+                                      description: |-
+                                        A key in the referenced Secret.
+                                        Some instances of this field may be defaulted, in others it may be required.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[-._a-zA-Z0-9]+$
+                                      type: string
+                                    name:
+                                      description: The name of the Secret resource being referred to.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: |-
+                                        The namespace of the Secret resource being referred to.
+                                        Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  type: object
+                              required:
+                                - secretRef
+                              type: object
+                            username:
+                              description: BarbicanProviderUsernameRef defines a reference to a secret containing username for the Barbican provider.
+                              maxProperties: 1
+                              minProperties: 1
+                              properties:
+                                secretRef:
+                                  description: |-
+                                    SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                                    In some instances, `key` is a required field.
+                                  properties:
+                                    key:
+                                      description: |-
+                                        A key in the referenced Secret.
+                                        Some instances of this field may be defaulted, in others it may be required.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[-._a-zA-Z0-9]+$
+                                      type: string
+                                    name:
+                                      description: The name of the Secret resource being referred to.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: |-
+                                        The namespace of the Secret resource being referred to.
+                                        Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  type: object
+                                value:
+                                  type: string
+                              type: object
+                          required:
+                            - password
+                            - username
+                          type: object
+                        authURL:
+                          type: string
+                        domainName:
+                          type: string
+                        region:
+                          type: string
+                        tenantName:
+                          type: string
+                      required:
+                        - auth
+                      type: object
                     beyondtrust:
                     beyondtrust:
                       description: Beyondtrust configures this store to sync secrets using Password Safe provider.
                       description: Beyondtrust configures this store to sync secrets using Password Safe provider.
                       properties:
                       properties:
@@ -14431,6 +14522,97 @@ spec:
                       required:
                       required:
                         - vaultUrl
                         - vaultUrl
                       type: object
                       type: object
+                    barbican:
+                      description: Barbican configures this store to sync secrets using the OpenStack Barbican provider
+                      properties:
+                        auth:
+                          description: BarbicanAuth contains the authentication information for Barbican.
+                          properties:
+                            password:
+                              description: BarbicanProviderPasswordRef defines a reference to a secret containing password for the Barbican provider.
+                              properties:
+                                secretRef:
+                                  description: |-
+                                    SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                                    In some instances, `key` is a required field.
+                                  properties:
+                                    key:
+                                      description: |-
+                                        A key in the referenced Secret.
+                                        Some instances of this field may be defaulted, in others it may be required.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[-._a-zA-Z0-9]+$
+                                      type: string
+                                    name:
+                                      description: The name of the Secret resource being referred to.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: |-
+                                        The namespace of the Secret resource being referred to.
+                                        Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  type: object
+                              required:
+                                - secretRef
+                              type: object
+                            username:
+                              description: BarbicanProviderUsernameRef defines a reference to a secret containing username for the Barbican provider.
+                              maxProperties: 1
+                              minProperties: 1
+                              properties:
+                                secretRef:
+                                  description: |-
+                                    SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                                    In some instances, `key` is a required field.
+                                  properties:
+                                    key:
+                                      description: |-
+                                        A key in the referenced Secret.
+                                        Some instances of this field may be defaulted, in others it may be required.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[-._a-zA-Z0-9]+$
+                                      type: string
+                                    name:
+                                      description: The name of the Secret resource being referred to.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: |-
+                                        The namespace of the Secret resource being referred to.
+                                        Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  type: object
+                                value:
+                                  type: string
+                              type: object
+                          required:
+                            - password
+                            - username
+                          type: object
+                        authURL:
+                          type: string
+                        domainName:
+                          type: string
+                        region:
+                          type: string
+                        tenantName:
+                          type: string
+                      required:
+                        - auth
+                      type: object
                     beyondtrust:
                     beyondtrust:
                       description: Beyondtrust configures this store to sync secrets using Password Safe provider.
                       description: Beyondtrust configures this store to sync secrets using Password Safe provider.
                       properties:
                       properties:

+ 200 - 0
docs/api/spec.md

@@ -1283,6 +1283,192 @@ configuration is not supported with the legacy go-autorest SDK.</p>
 </tr>
 </tr>
 </tbody>
 </tbody>
 </table>
 </table>
+<h3 id="external-secrets.io/v1.BarbicanAuth">BarbicanAuth
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1.BarbicanProvider">BarbicanProvider</a>)
+</p>
+<p>
+<p>BarbicanAuth contains the authentication information for Barbican.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>username</code></br>
+<em>
+<a href="#external-secrets.io/v1.BarbicanProviderUsernameRef">
+BarbicanProviderUsernameRef
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>password</code></br>
+<em>
+<a href="#external-secrets.io/v1.BarbicanProviderPasswordRef">
+BarbicanProviderPasswordRef
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+</tbody>
+</table>
+<h3 id="external-secrets.io/v1.BarbicanProvider">BarbicanProvider
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1.SecretStoreProvider">SecretStoreProvider</a>)
+</p>
+<p>
+<p>BarbicanProvider setup a store to sync secrets with barbican.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>authURL</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>tenantName</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>domainName</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>region</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>auth</code></br>
+<em>
+<a href="#external-secrets.io/v1.BarbicanAuth">
+BarbicanAuth
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+</tbody>
+</table>
+<h3 id="external-secrets.io/v1.BarbicanProviderPasswordRef">BarbicanProviderPasswordRef
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1.BarbicanAuth">BarbicanAuth</a>)
+</p>
+<p>
+<p>BarbicanProviderPasswordRef defines a reference to a secret containing password for the Barbican provider.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>secretRef</code></br>
+<em>
+<a href="https://pkg.go.dev/github.com/external-secrets/external-secrets/apis/meta/v1#SecretKeySelector">
+External Secrets meta/v1.SecretKeySelector
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+</tbody>
+</table>
+<h3 id="external-secrets.io/v1.BarbicanProviderUsernameRef">BarbicanProviderUsernameRef
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1.BarbicanAuth">BarbicanAuth</a>)
+</p>
+<p>
+<p>BarbicanProviderUsernameRef defines a reference to a secret containing username for the Barbican provider.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>value</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>secretRef</code></br>
+<em>
+<a href="https://pkg.go.dev/github.com/external-secrets/external-secrets/apis/meta/v1#SecretKeySelector">
+External Secrets meta/v1.SecretKeySelector
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+</tbody>
+</table>
 <h3 id="external-secrets.io/v1.BeyondTrustProviderSecretRef">BeyondTrustProviderSecretRef
 <h3 id="external-secrets.io/v1.BeyondTrustProviderSecretRef">BeyondTrustProviderSecretRef
 </h3>
 </h3>
 <p>
 <p>
@@ -9284,6 +9470,20 @@ NgrokProvider
 <p>Ngrok configures this store to sync secrets using the ngrok provider.</p>
 <p>Ngrok configures this store to sync secrets using the ngrok provider.</p>
 </td>
 </td>
 </tr>
 </tr>
+<tr>
+<td>
+<code>barbican</code></br>
+<em>
+<a href="#external-secrets.io/v1.BarbicanProvider">
+BarbicanProvider
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Barbican configures this store to sync secrets using the OpenStack Barbican provider</p>
+</td>
+</tr>
 </tbody>
 </tbody>
 </table>
 </table>
 <h3 id="external-secrets.io/v1.SecretStoreRef">SecretStoreRef
 <h3 id="external-secrets.io/v1.SecretStoreRef">SecretStoreRef

+ 2 - 0
docs/introduction/stability-support.md

@@ -94,6 +94,7 @@ The following table describes the stability level of each provider and who's res
 | [Cloud.ru](https://external-secrets.io/latest/provider/cloudru)                                            | alpha     | [@default23](https://github.com/default23)                                                          |
 | [Cloud.ru](https://external-secrets.io/latest/provider/cloudru)                                            | alpha     | [@default23](https://github.com/default23)                                                          |
 | [Volcengine](https://external-secrets.io/latest/provider/volcengine)                                       | alpha     | [@kevinyancn](https://github.com/kevinyancn)                                                        |
 | [Volcengine](https://external-secrets.io/latest/provider/volcengine)                                       | alpha     | [@kevinyancn](https://github.com/kevinyancn)                                                        |
 | [ngrok](https://external-secrets.io/latest/provider/ngrok)                                                 | alpha     | [@jonstacks](https://github.com/jonstacks)                                                          |
 | [ngrok](https://external-secrets.io/latest/provider/ngrok)                                                 | alpha     | [@jonstacks](https://github.com/jonstacks)                                                          |
+| [Barbican](https://external-secrets.io/latest/provider/barbican)                                           | alpha     | [@rkferreira](https://github.com/rkferreira)                                                        |
 
 
 
 
 ## Provider Feature Support
 ## Provider Feature Support
@@ -134,6 +135,7 @@ The following table show the support for features across different providers.
 | Cloud.ru                  |      x       |      x       |                      |            x            |        x         |             |              x              |
 | Cloud.ru                  |      x       |      x       |                      |            x            |        x         |             |              x              |
 | Volcengine                |              |              |                      |                         |        x         |             |                             |
 | Volcengine                |              |              |                      |                         |        x         |             |                             |
 | ngrok                     |              |              |                      |                         |        x         |      x      |                             |
 | ngrok                     |              |              |                      |                         |        x         |      x      |                             |
+| Barbican                  |      x       |              |                      |                         |        x         |             |                             |
 
 
 ## Support Policy
 ## Support Policy
 
 

+ 210 - 0
docs/provider/barbican.md

@@ -0,0 +1,210 @@
+# OpenStack Barbican
+
+External Secrets Operator integrates with [OpenStack Barbican](https://docs.openstack.org/barbican/latest/) for secret management.
+
+Barbican is OpenStack's Key Manager service that provides secure storage, provisioning and management of secret data. This includes keys, passwords, certificates, and other sensitive data. The Barbican provider for External Secrets Operator allows you to retrieve secrets stored in Barbican and synchronize them with Kubernetes secrets.
+
+## Authentication
+
+The Barbican provider uses OpenStack Keystone authentication. You need to provide:
+
+- **AuthURL**: The OpenStack Keystone authentication endpoint
+- **TenantName**: The OpenStack tenant/project name
+- **DomainName**: The OpenStack domain name (optional)
+- **Region**: The OpenStack region (optional)
+- **Username**: OpenStack username (stored in a Kubernetes secret)
+- **Password**: OpenStack password (stored in a Kubernetes secret)
+
+## Example
+
+First, create a secret containing your OpenStack credentials:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+  name: barbican-secret
+type: Opaque
+data:
+  username: bXl1c2VybmFtZQ== # base64 encoded "myusername"
+  password: bXlwYXNzd29yZA== # base64 encoded "mypassword"
+```
+
+Then create a SecretStore with the Barbican backend:
+
+```yaml
+apiVersion: external-secrets.io/v1
+kind: SecretStore
+metadata:
+  name: barbican-backend
+spec:
+  provider:
+    barbican:
+      authURL: "https://keystone.example.com:5000/v3"
+      tenantName: "my-project"
+      domainName: "default"
+      region: "RegionOne"
+      auth:
+        username:
+          secretRef:
+            name: "barbican-secret"
+            key: "username"
+        password:
+          secretRef:
+            name: "barbican-secret"
+            key: "password"
+```
+
+**NOTE:** In case of a `ClusterSecretStore`, be sure to provide `namespace` for the `secretRef` with the namespace of the secret that contains the credentials.
+
+## Creating an ExternalSecret
+
+Now you can create an ExternalSecret that uses the Barbican provider to retrieve secrets:
+
+```yaml
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+  name: barbican-secret
+spec:
+  secretStoreRef:
+    name: barbican-backend
+    kind: SecretStore
+  target:
+    name: example-secret
+    creationPolicy: Owner
+  data:
+  - secretKey: password
+    remoteRef:
+      key: "my-secret-uuid"
+```
+
+The `remoteRef.key` should be the UUID of the secret in Barbican. You can find this by listing secrets in Barbican:
+
+```bash
+openstack secret list
+```
+
+## Finding Secrets by Name
+
+You can also retrieve secrets by using the `find` feature to search by name.
+
+It doesnt really support regexp, its exact string matching, so you need to provide the exact name of the secret.
+
+```yaml
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+  name: barbican-find-secret
+spec:
+  secretStoreRef:
+    name: barbican-backend
+    kind: SecretStore
+  target:
+    name: found-secrets
+    creationPolicy: Owner
+  dataFrom:
+  - find:
+      name:
+        regexp: "database"
+```
+
+This will find all secrets in Barbican whose name exactly matches the string.
+
+## ClusterSecretStore
+
+For a ClusterSecretStore, you need to specify the namespace where the credentials secret is located:
+
+```yaml
+apiVersion: external-secrets.io/v1
+kind: ClusterSecretStore
+metadata:
+  name: barbican-cluster-backend
+spec:
+  provider:
+    barbican:
+      authURL: "https://keystone.example.com:5000/v3"
+      tenantName: "my-project"
+      domainName: "default"
+      region: "RegionOne"
+      auth:
+        username:
+          secretRef:
+            name: "barbican-secret"
+            key: "username"
+            namespace: "default"  # Required for ClusterSecretStore
+        password:
+          secretRef:
+            name: "barbican-secret"
+            key: "password"
+            namespace: "default"  # Required for ClusterSecretStore
+```
+
+## Configuration Reference
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `authURL` | string | Yes | OpenStack Keystone authentication endpoint URL |
+| `tenantName` | string | Yes | OpenStack tenant/project name |
+| `domainName` | string | No | OpenStack domain name |
+| `region` | string | No | OpenStack region |
+| `auth` | BarbicanAuth | Yes | Authentication credentials |
+
+### BarbicanAuth
+
+The `BarbicanAuth` type contains the authentication information:
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `username` | BarbicanProviderUsernameRef | Yes | OpenStack username (from secret or literal value) |
+| `password` | BarbicanProviderPasswordRef | Yes | OpenStack password (from secret only) |
+
+### BarbicanProviderUsernameRef
+
+The `BarbicanProviderUsernameRef` type allows you to specify username either as a literal or reference to a Kubernetes secret:
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `value` | string | No | Literal value (not recommended for sensitive data) |
+| `secretRef` | SecretKeySelector | No | Reference to a Kubernetes secret |
+
+### BarbicanProviderPasswordRef
+
+The `BarbicanProviderPasswordRef` type requires a reference to a Kubernetes secret:
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `secretRef` | SecretKeySelector | Yes | Reference to a Kubernetes secret |
+
+## Limitations
+
+- The Barbican provider is **read-only**. It does not support creating or updating secrets in Barbican.
+- Used credentials has to have access to the provided secret.
+- It will retrieve all secret types by default.
+
+## Troubleshooting
+
+### Authentication Issues
+
+If you encounter authentication errors, verify:
+
+1. The `authURL` is correct and accessible
+2. The credentials are valid and have appropriate permissions
+3. The `tenantName` and `domainName` (if used) are correct
+4. Network connectivity to the OpenStack endpoints
+
+### Secret Not Found
+
+If a secret cannot be found:
+
+1. Verify the secret UUID exists in Barbican: `openstack secret get -p https://barbican-url/v1/secrets/<uuid>`
+2. Check that the user has permission to access the secret
+3. Ensure the secret is in the correct project/tenant
+
+### Network Connectivity
+
+Ensure your Kubernetes cluster can reach:
+- The OpenStack Keystone endpoint (for authentication)
+- The Barbican service endpoint (for secret retrieval)
+
+Check firewall rules and network policies that might block access.

+ 41 - 0
docs/snippets/barbican-external-secrets.yaml

@@ -0,0 +1,41 @@
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+  name: barbican-external-secret
+spec:
+  secretStoreRef:
+    name: barbican-backend
+    kind: SecretStore
+
+  target:
+    name: barbican-result-secret-test
+
+  data:
+    - secretKey: test01
+      remoteRef:
+        key: 35654cca-3cb0-44ee-b773-5e3ad5e27f59
+
+    - secretKey: test02
+      remoteRef:
+        key: f12dd948-ae0d-4732-a7a4-c2abeecf7e92
+        property: key-from-payload
+---
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+  name: barbican-external-secret-from
+spec:
+  secretStoreRef:
+    name: barbican-backend
+    kind: SecretStore
+
+  target:
+    name: barbican-result-test-from
+
+  dataFrom:
+    - find:
+        name:
+          regexp: "testnow"
+
+    - extract:
+        key: f12dd948-ae0d-4732-a7a4-c2abeecf7e92

+ 21 - 0
docs/snippets/barbican-secret-store.yaml

@@ -0,0 +1,21 @@
+apiVersion: external-secrets.io/v1
+kind: SecretStore
+metadata:
+  name: barbican-backend
+  namespace: default
+spec:
+  provider:
+    barbican:
+      authURL: "https://keystone.example.com:5000/v3"
+      tenantName: "my-project"
+      domainName: "default"
+      region: "RegionOne"
+      auth:
+        username:
+          secretRef:
+            name: "barbican-secret"
+            key: "username"
+        password:
+          secretRef:
+            name: "barbican-secret"
+            key: "password"

+ 3 - 1
go.mod

@@ -23,6 +23,7 @@ replace (
 	github.com/external-secrets/external-secrets/providers/v1/alibaba => ./providers/v1/alibaba
 	github.com/external-secrets/external-secrets/providers/v1/alibaba => ./providers/v1/alibaba
 	github.com/external-secrets/external-secrets/providers/v1/aws => ./providers/v1/aws
 	github.com/external-secrets/external-secrets/providers/v1/aws => ./providers/v1/aws
 	github.com/external-secrets/external-secrets/providers/v1/azure => ./providers/v1/azure
 	github.com/external-secrets/external-secrets/providers/v1/azure => ./providers/v1/azure
+	github.com/external-secrets/external-secrets/providers/v1/barbican => ./providers/v1/barbican
 	github.com/external-secrets/external-secrets/providers/v1/beyondtrust => ./providers/v1/beyondtrust
 	github.com/external-secrets/external-secrets/providers/v1/beyondtrust => ./providers/v1/beyondtrust
 	github.com/external-secrets/external-secrets/providers/v1/bitwarden => ./providers/v1/bitwarden
 	github.com/external-secrets/external-secrets/providers/v1/bitwarden => ./providers/v1/bitwarden
 	github.com/external-secrets/external-secrets/providers/v1/chef => ./providers/v1/chef
 	github.com/external-secrets/external-secrets/providers/v1/chef => ./providers/v1/chef
@@ -135,6 +136,7 @@ require (
 	github.com/external-secrets/external-secrets/providers/v1/alibaba v0.0.0-00010101000000-000000000000
 	github.com/external-secrets/external-secrets/providers/v1/alibaba v0.0.0-00010101000000-000000000000
 	github.com/external-secrets/external-secrets/providers/v1/aws v0.0.0-20251103072335-a9b233b6936f
 	github.com/external-secrets/external-secrets/providers/v1/aws v0.0.0-20251103072335-a9b233b6936f
 	github.com/external-secrets/external-secrets/providers/v1/azure v0.0.0-20251103072335-a9b233b6936f
 	github.com/external-secrets/external-secrets/providers/v1/azure v0.0.0-20251103072335-a9b233b6936f
+	github.com/external-secrets/external-secrets/providers/v1/barbican v0.0.0-00010101000000-000000000000
 	github.com/external-secrets/external-secrets/providers/v1/beyondtrust v0.0.0-00010101000000-000000000000
 	github.com/external-secrets/external-secrets/providers/v1/beyondtrust v0.0.0-00010101000000-000000000000
 	github.com/external-secrets/external-secrets/providers/v1/bitwarden v0.0.0-00010101000000-000000000000
 	github.com/external-secrets/external-secrets/providers/v1/bitwarden v0.0.0-00010101000000-000000000000
 	github.com/external-secrets/external-secrets/providers/v1/chef v0.0.0-00010101000000-000000000000
 	github.com/external-secrets/external-secrets/providers/v1/chef v0.0.0-00010101000000-000000000000
@@ -302,6 +304,7 @@ require (
 	github.com/google/go-github/v56 v56.0.0 // indirect
 	github.com/google/go-github/v56 v56.0.0 // indirect
 	github.com/google/go-github/v75 v75.0.0 // indirect
 	github.com/google/go-github/v75 v75.0.0 // indirect
 	github.com/google/s2a-go v0.1.9 // indirect
 	github.com/google/s2a-go v0.1.9 // indirect
+	github.com/gophercloud/gophercloud/v2 v2.8.0 // indirect
 	github.com/grafana/grafana-openapi-client-go v0.0.0-20250925215610-d92957c70d5c // indirect
 	github.com/grafana/grafana-openapi-client-go v0.0.0-20250925215610-d92957c70d5c // indirect
 	github.com/hashicorp/go-secure-stdlib/awsutil v0.3.0 // indirect
 	github.com/hashicorp/go-secure-stdlib/awsutil v0.3.0 // indirect
 	github.com/hashicorp/go-uuid v1.0.3 // indirect
 	github.com/hashicorp/go-uuid v1.0.3 // indirect
@@ -405,7 +408,6 @@ require (
 	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
 	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
 	github.com/emicklei/go-restful/v3 v3.13.0 // indirect
 	github.com/emicklei/go-restful/v3 v3.13.0 // indirect
-	github.com/evanphx/json-patch v5.6.0+incompatible // indirect
 	github.com/evanphx/json-patch/v5 v5.9.11 // indirect
 	github.com/evanphx/json-patch/v5 v5.9.11 // indirect
 	github.com/fatih/color v1.18.0 // indirect
 	github.com/fatih/color v1.18.0 // indirect
 	github.com/fsnotify/fsnotify v1.9.0 // indirect
 	github.com/fsnotify/fsnotify v1.9.0 // indirect

+ 4 - 2
go.sum

@@ -422,8 +422,8 @@ github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfU
 github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
 github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
-github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
-github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
+github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
 github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
 github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
 github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
 github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
 github.com/extism/go-sdk v1.7.1 h1:lWJos6uY+tRFdlIHR+SJjwFDApY7OypS/2nMhiVQ9Sw=
 github.com/extism/go-sdk v1.7.1 h1:lWJos6uY+tRFdlIHR+SJjwFDApY7OypS/2nMhiVQ9Sw=
@@ -691,6 +691,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
 github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
 github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
 github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
+github.com/gophercloud/gophercloud/v2 v2.8.0 h1:of2+8tT6+FbEYHfYC8GBu8TXJNsXYSNm9KuvpX7Neqo=
+github.com/gophercloud/gophercloud/v2 v2.8.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=

+ 1 - 0
hack/api-docs/mkdocs.yml

@@ -121,6 +121,7 @@ nav:
       - AWS Secrets Manager: provider/aws-secrets-manager.md
       - AWS Secrets Manager: provider/aws-secrets-manager.md
       - AWS Parameter Store: provider/aws-parameter-store.md
       - AWS Parameter Store: provider/aws-parameter-store.md
       - Azure Key Vault: provider/azure-key-vault.md
       - Azure Key Vault: provider/azure-key-vault.md
+      - Barbican: provider/barbican.md
       - BeyondTrust: provider/beyondtrust.md
       - BeyondTrust: provider/beyondtrust.md
       - Bitwarden Secrets Manager: provider/bitwarden-secrets-manager.md
       - Bitwarden Secrets Manager: provider/bitwarden-secrets-manager.md
       - Chef: provider/chef.md
       - Chef: provider/chef.md

+ 30 - 0
pkg/register/barbican.go

@@ -0,0 +1,30 @@
+//go:build barbican || all_providers
+
+/*
+Copyright © 2025 ESO Maintainer Team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package register provides explicit registration of all providers and generators.
+package register
+
+import (
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	barbican "github.com/external-secrets/external-secrets/providers/v1/barbican"
+)
+
+func init() {
+	// Register barbican provider
+	esv1.Register(barbican.NewProvider(), barbican.ProviderSpec(), barbican.MaintenanceStatus())
+}

+ 184 - 0
providers/v1/barbican/client.go

@@ -0,0 +1,184 @@
+/*
+Copyright © 2025 ESO Maintainer Team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package barbican client implementation.
+package barbican
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/gophercloud/gophercloud/v2"
+	"github.com/gophercloud/gophercloud/v2/openstack/keymanager/v1/secrets"
+
+	corev1 "k8s.io/api/core/v1"
+
+	esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+const (
+	errClientGeneric      = "barbican client: %w"
+	errClientMissingField = "barbican client: missing field %w"
+	errClientListAllSecrets = "barbican client: failed to list all secrets: %w"
+	errClientExtractSecrets = "barbican client: failed to extract secrets: %w"
+	errClientGetSecretPayload = "barbican client: failed to get secret payload: %w"
+	errClientGetSecretPayloadProperty = "barbican client: failed to get secret payload property: %w"
+	errClientJSONUnmarshal = "barbican client: failed to unmarshal json: %w"
+)
+
+var _ esapi.SecretsClient = &Client{}
+
+// Client is a Barbican secrets client.
+type Client struct {
+	keyManager *gophercloud.ServiceClient
+}
+
+// GetAllSecrets retrieves all secrets matching the given name.
+func (c *Client) GetAllSecrets(ctx context.Context, ref esapi.ExternalSecretFind) (map[string][]byte, error) {
+	if ref.Name == nil || ref.Name.RegExp == "" {
+		return nil, fmt.Errorf(errClientMissingField, errors.New("name and/or regexp"))
+	}
+
+	opts := secrets.ListOpts{
+		Name: ref.Name.RegExp,
+	}
+
+	allPages, err := secrets.List(c.keyManager, opts).AllPages(ctx)
+	if err != nil {
+		return nil, fmt.Errorf(errClientListAllSecrets, err)
+	}
+
+	allSecrets, err := secrets.ExtractSecrets(allPages)
+	if err != nil {
+		return nil, fmt.Errorf(errClientExtractSecrets, err)
+	}
+
+	if len(allSecrets) == 0 {
+		return nil, fmt.Errorf(errClientGeneric, errors.New("no secrets found"))
+	}
+
+	var secretsMap = make(map[string][]byte)
+
+	// return a secret map with all found secrets.
+	for _, secret := range allSecrets {
+		secretUUID := extractUUIDFromRef(secret.SecretRef)
+		secretsMap[secretUUID], err = secrets.GetPayload(ctx, c.keyManager, secretUUID, nil).Extract()
+		if err != nil {
+			return nil, fmt.Errorf(errClientGetSecretPayload, fmt.Errorf("failed to get secret payload for secret %s: %w", secretUUID, err))
+		}
+	}
+	return secretsMap, nil
+}
+
+// GetSecret retrieves a secret from Barbican.
+func (c *Client) GetSecret(ctx context.Context, ref esapi.ExternalSecretDataRemoteRef) ([]byte, error) {
+	payload, err := secrets.GetPayload(ctx, c.keyManager, ref.Key, nil).Extract()
+	if err != nil {
+		return nil, fmt.Errorf(errClientGetSecretPayload, err)
+	}
+
+	if ref.Property == "" {
+		return payload, nil
+	}
+
+	propertyValue, err := getSecretPayloadProperty(payload, ref.Property)
+	if err != nil {
+		return nil, fmt.Errorf(errClientGetSecretPayloadProperty, fmt.Errorf("failed to get property %s from secret payload: %w", ref.Property, err))
+	}
+
+	return propertyValue, nil
+}
+
+// GetSecretMap retrieves a secret and parses it as a JSON object.
+func (c *Client) GetSecretMap(ctx context.Context, ref esapi.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
+	payload, err := c.GetSecret(ctx, ref)
+	if err != nil {
+		return nil, fmt.Errorf(errClientGeneric, err)
+	}
+
+	var rawJSON map[string]json.RawMessage
+	if err := json.Unmarshal(payload, &rawJSON); err != nil {
+		return nil, fmt.Errorf(errClientJSONUnmarshal, err)
+	}
+
+	secretMap := make(map[string][]byte, len(rawJSON))
+	for k, v := range rawJSON {
+		secretMap[k] = []byte(v)
+	}
+
+	return secretMap, nil
+}
+
+// PushSecret is not implemented right now for Barbican.
+func (c *Client) PushSecret(_ context.Context, _ *corev1.Secret, _ esapi.PushSecretData) error {
+	return fmt.Errorf("barbican provider does not support pushing secrets")
+}
+
+// SecretExists is not implemented right now for Barbican.
+func (c *Client) SecretExists(_ context.Context, _ esapi.PushSecretRemoteRef) (bool, error) {
+	return false, fmt.Errorf("barbican provider does not pushing secrets with update policy IfNotExists")
+}
+
+// DeleteSecret is not implemented right now for Barbican.
+func (c *Client) DeleteSecret(_ context.Context, _ esapi.PushSecretRemoteRef) error {
+	return fmt.Errorf("barbican provider does not support deleting secrets (delete policy Delete)")
+}
+
+// Validate checks if the client is properly configured.
+func (c *Client) Validate() (esapi.ValidationResult, error) {
+	return esapi.ValidationResultUnknown, nil
+}
+
+// Close closes the client and any underlying connections.
+func (c *Client) Close(_ context.Context) error {
+	return nil
+}
+
+// getSecretPayloadProperty extracts a property from a JSON payload.
+func getSecretPayloadProperty(payload []byte, property string) ([]byte, error) {
+	if property == "" {
+		return payload, nil
+	}
+
+	var rawJSON map[string]json.RawMessage
+	if err := json.Unmarshal(payload, &rawJSON); err != nil {
+		return nil, fmt.Errorf(errClientJSONUnmarshal, err)
+	}
+
+	value, ok := rawJSON[property]
+	if !ok {
+		return nil, fmt.Errorf(errClientGeneric, fmt.Errorf("property %s not found in secret payload", property))
+	}
+
+	return value, nil
+}
+
+// extractUUIDFromRef extracts the UUID from a Barbican secret reference URL.
+func extractUUIDFromRef(secretRef string) string {
+	// Barbican secret refs are usually of the form: https://<endpoint>/v1/secrets/<uuid>
+	// We'll just take the last part after the last '/'
+	// If there's a trailing slash, the UUID part would be empty, so return empty string
+
+	lastSlash := strings.LastIndex(secretRef, "/")
+	if lastSlash > -1 {
+		return secretRef[lastSlash+1:] // <- will not result in overflow even if it's the last `/`
+	}
+
+  return ""
+}

+ 209 - 0
providers/v1/barbican/client_test.go

@@ -0,0 +1,209 @@
+/*
+Copyright © 2025 ESO Maintainer Team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package barbican
+
+import (
+	"context"
+	"testing"
+
+	"github.com/gophercloud/gophercloud/v2"
+	"github.com/stretchr/testify/assert"
+
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+func TestExtractUUIDFromRef(t *testing.T) {
+	testCases := []struct {
+		name         string
+		secretRef    string
+		expectedUUID string
+	}{
+		{
+			name:         "valid barbican secret ref",
+			secretRef:    "https://barbican.example.com/v1/secrets/12345678-1234-1234-1234-123456789abc",
+			expectedUUID: "12345678-1234-1234-1234-123456789abc",
+		},
+		{
+			name:         "secret ref without protocol",
+			secretRef:    "barbican.example.com/v1/secrets/87654321-4321-4321-4321-cba987654321",
+			expectedUUID: "87654321-4321-4321-4321-cba987654321",
+		},
+		{
+			name:         "empty string",
+			secretRef:    "",
+			expectedUUID: "",
+		},
+		{
+			name:         "trailing slash",
+			secretRef:    "https://barbican.example.com/v1/secrets/12345678-1234-1234-1234-123456789abc/",
+			expectedUUID: "",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			uuid := extractUUIDFromRef(tc.secretRef)
+			assert.Equal(t, tc.expectedUUID, uuid)
+		})
+	}
+}
+
+func TestGetSecretPayloadProperty(t *testing.T) {
+	testPayload := []byte(`{"username":"admin","password":"secret123","nested":{"key":"value"}}`)
+
+	testCases := []struct {
+		name         string
+		payload      []byte
+		property     string
+		expectError  bool
+		errorMessage string
+		expectedData []byte
+	}{
+		{
+			name:         "empty property returns full payload",
+			payload:      testPayload,
+			property:     "",
+			expectError:  false,
+			expectedData: testPayload,
+		},
+		{
+			name:         "valid property extraction",
+			payload:      testPayload,
+			property:     "username",
+			expectError:  false,
+			expectedData: []byte(`"admin"`),
+		},
+		{
+			name:         "nested property extraction",
+			payload:      testPayload,
+			property:     "nested",
+			expectError:  false,
+			expectedData: []byte(`{"key":"value"}`),
+		},
+		{
+			name:         "property not found",
+			payload:      testPayload,
+			property:     "nonexistent",
+			expectError:  true,
+			errorMessage: "property nonexistent not found in secret payload",
+		},
+		{
+			name:         "invalid JSON",
+			payload:      []byte("invalid-json"),
+			property:     "username",
+			expectError:  true,
+			errorMessage: "barbican client",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			data, err := getSecretPayloadProperty(tc.payload, tc.property)
+
+			if tc.expectError {
+				assert.Error(t, err)
+				assert.Contains(t, err.Error(), tc.errorMessage)
+				assert.Nil(t, data)
+			} else {
+				assert.NoError(t, err)
+				assert.Equal(t, tc.expectedData, data)
+			}
+		})
+	}
+}
+
+func TestUnsupportedOperations(t *testing.T) {
+	client := &Client{
+		keyManager: &gophercloud.ServiceClient{},
+	}
+
+	// Test PushSecret
+	err := client.PushSecret(context.Background(), nil, nil)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "does not support pushing secrets")
+
+	// Test SecretExists
+	exists, err := client.SecretExists(context.Background(), nil)
+	assert.Error(t, err)
+	assert.False(t, exists)
+	assert.Contains(t, err.Error(), "barbican provider does not pushing secrets with update policy IfNotExists")
+
+	// Test DeleteSecret
+	err = client.DeleteSecret(context.Background(), nil)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "does not support deleting secrets")
+}
+
+func TestValidateAndClose(t *testing.T) {
+	client := &Client{
+		keyManager: &gophercloud.ServiceClient{},
+	}
+
+	// Test Validate
+	result, err := client.Validate()
+	assert.NoError(t, err)
+	assert.Equal(t, esv1.ValidationResultUnknown, result)
+
+	// Test Close
+	err = client.Close(context.Background())
+	assert.NoError(t, err)
+}
+
+func TestGetAllSecretsValidation(t *testing.T) {
+	client := &Client{
+		keyManager: &gophercloud.ServiceClient{},
+	}
+
+	testCases := []struct {
+		name         string
+		findRef      esv1.ExternalSecretFind
+		expectError  bool
+		errorMessage string
+	}{
+		{
+			name: "no name specified should return error",
+			findRef: esv1.ExternalSecretFind{
+				Name: nil,
+			},
+			expectError:  true,
+			errorMessage: "missing field",
+		},
+		{
+			name: "empty name regex should return error",
+			findRef: esv1.ExternalSecretFind{
+				Name: &esv1.FindName{
+					RegExp: "",
+				},
+			},
+			expectError:  true,
+			errorMessage: "missing field",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			_, err := client.GetAllSecrets(context.Background(), tc.findRef)
+
+			if tc.expectError {
+				assert.Error(t, err)
+				assert.Contains(t, err.Error(), tc.errorMessage)
+			} else if err != nil {
+					assert.Contains(t, err.Error(), "barbican client")
+			}
+		})
+	}
+}

+ 154 - 0
providers/v1/barbican/fake/mock.go

@@ -0,0 +1,154 @@
+/*
+Copyright © 2025 ESO Maintainer Team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package fake
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/gophercloud/gophercloud/v2"
+	"github.com/gophercloud/gophercloud/v2/openstack/keymanager/v1/secrets"
+	"github.com/gophercloud/gophercloud/v2/pagination"
+)
+
+// MockKeyManagerClient is a mock implementation of the Gophercloud ServiceClient
+// for testing purposes without requiring actual OpenStack services.
+type MockKeyManagerClient struct {
+	// Mock data storage
+	secrets      map[string][]byte
+	secretsInfo  map[string]secrets.Secret
+	shouldError  bool
+	errorMessage string
+}
+
+// NewMockKeyManagerClient creates a new mock client.
+func NewMockKeyManagerClient() *MockKeyManagerClient {
+	return &MockKeyManagerClient{
+		secrets:     make(map[string][]byte),
+		secretsInfo: make(map[string]secrets.Secret),
+		shouldError: false,
+	}
+}
+
+// WithSecret adds a secret to the mock client.
+func (m *MockKeyManagerClient) WithSecret(uuid, name string, payload []byte) *MockKeyManagerClient {
+	m.secrets[uuid] = payload
+	m.secretsInfo[uuid] = secrets.Secret{
+		SecretRef: fmt.Sprintf("https://barbican.example.com/v1/secrets/%s", uuid),
+		Name:      name,
+	}
+	return m
+}
+
+// WithError configures the mock to return an error.
+func (m *MockKeyManagerClient) WithError(errorMessage string) *MockKeyManagerClient {
+	m.shouldError = true
+	m.errorMessage = errorMessage
+	return m
+}
+
+// Reset clears all mock data and error states.
+func (m *MockKeyManagerClient) Reset() {
+	m.secrets = make(map[string][]byte)
+	m.secretsInfo = make(map[string]secrets.Secret)
+	m.shouldError = false
+	m.errorMessage = ""
+}
+
+// GetPayload mocks the secrets.GetPayload function.
+func (m *MockKeyManagerClient) GetPayload(_ context.Context, _ *gophercloud.ServiceClient, uuid string, _ secrets.GetPayloadOptsBuilder) ([]byte, error) {
+	if m.shouldError {
+		return nil, fmt.Errorf("%s", m.errorMessage)
+	}
+
+	payload, exists := m.secrets[uuid]
+	if !exists {
+		return nil, fmt.Errorf("secret with UUID %s not found", uuid)
+	}
+
+	return payload, nil
+}
+
+// ListSecrets mocks the secrets.List function.
+func (m *MockKeyManagerClient) ListSecrets(_ context.Context, _ *gophercloud.ServiceClient, opts secrets.ListOptsBuilder) ([]secrets.Secret, error) {
+	if m.shouldError {
+		return nil, fmt.Errorf("%s", m.errorMessage)
+	}
+
+	var result =  make([]secrets.Secret, 10)
+	for _, secret := range m.secretsInfo {
+		// Apply name filter if provided
+		if opts != nil {
+			if listOpts, ok := opts.(secrets.ListOpts); ok && listOpts.Name != "" {
+				if secret.Name != listOpts.Name {
+					continue
+				}
+			}
+		}
+		result = append(result, secret)
+	}
+
+	return result, nil
+}
+
+// MockPagination implements pagination.Page for testing.
+type MockPagination struct {
+	secrets []secrets.Secret
+}
+
+func (p MockPagination) NextPageURL() (string, error) {
+	return "", nil
+}
+
+func (p MockPagination) IsEmpty() (bool, error) {
+	return len(p.secrets) == 0, nil
+}
+
+func (p MockPagination) LastMarker() (string, error) {
+	return "", nil
+}
+
+func (p MockPagination) GetBody() interface{} {
+	return map[string]interface{}{
+		"secrets": p.secrets,
+	}
+}
+
+// MockPager implements pagination.Pager for testing.
+type MockPager struct {
+	page MockPagination
+}
+
+func (p MockPager) AllPages(_ context.Context) (pagination.Page, error) {
+	return p.page, nil
+}
+
+func (p MockPager) EachPage(_ context.Context, fn func(pagination.Page) (bool, error)) error {
+	cont, err := fn(p.page)
+	if err != nil {
+		return err
+	}
+	_ = cont
+	return nil
+}
+
+// NewMockPager creates a new mock pager with the provided secrets.
+func NewMockPager(secrets []secrets.Secret) MockPager {
+	return MockPager{
+		page: MockPagination{secrets: secrets},
+	}
+}

+ 82 - 0
providers/v1/barbican/go.mod

@@ -0,0 +1,82 @@
+module github.com/external-secrets/external-secrets/providers/v1/barbican
+
+go 1.25.1
+
+require (
+	github.com/external-secrets/external-secrets/apis v0.0.0
+	github.com/external-secrets/external-secrets/runtime v0.0.0-00010101000000-000000000000
+	github.com/gophercloud/gophercloud/v2 v2.8.0
+	github.com/stretchr/testify v1.11.1
+	k8s.io/api v0.34.1
+	k8s.io/apimachinery v0.34.1
+	sigs.k8s.io/controller-runtime v0.22.3
+)
+
+require (
+	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/cespare/xxhash/v2 v2.3.0 // indirect
+	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+	github.com/emicklei/go-restful/v3 v3.13.0 // indirect
+	github.com/evanphx/json-patch/v5 v5.9.11 // indirect
+	github.com/fsnotify/fsnotify v1.9.0 // indirect
+	github.com/fxamacker/cbor/v2 v2.9.0 // indirect
+	github.com/go-logr/logr v1.4.3 // indirect
+	github.com/go-openapi/jsonpointer v0.22.1 // indirect
+	github.com/go-openapi/jsonreference v0.21.2 // indirect
+	github.com/go-openapi/swag v0.25.1 // indirect
+	github.com/go-openapi/swag/cmdutils v0.25.1 // indirect
+	github.com/go-openapi/swag/conv v0.25.1 // indirect
+	github.com/go-openapi/swag/fileutils v0.25.1 // indirect
+	github.com/go-openapi/swag/jsonname v0.25.1 // indirect
+	github.com/go-openapi/swag/jsonutils v0.25.1 // indirect
+	github.com/go-openapi/swag/loading v0.25.1 // indirect
+	github.com/go-openapi/swag/mangling v0.25.1 // indirect
+	github.com/go-openapi/swag/netutils v0.25.1 // indirect
+	github.com/go-openapi/swag/stringutils v0.25.1 // indirect
+	github.com/go-openapi/swag/typeutils v0.25.1 // indirect
+	github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/google/btree v1.1.3 // indirect
+	github.com/google/gnostic-models v0.7.0 // indirect
+	github.com/google/go-cmp v0.7.0 // indirect
+	github.com/google/uuid v1.6.0 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
+	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+	github.com/prometheus/client_golang v1.23.2 // indirect
+	github.com/prometheus/client_model v0.6.2 // indirect
+	github.com/prometheus/common v0.67.2 // indirect
+	github.com/prometheus/procfs v0.19.2 // indirect
+	github.com/spf13/pflag v1.0.10 // indirect
+	github.com/x448/float16 v0.8.4 // indirect
+	go.yaml.in/yaml/v2 v2.4.3 // indirect
+	go.yaml.in/yaml/v3 v3.0.4 // indirect
+	golang.org/x/net v0.46.0 // indirect
+	golang.org/x/oauth2 v0.32.0 // indirect
+	golang.org/x/sync v0.17.0 // indirect
+	golang.org/x/sys v0.37.0 // indirect
+	golang.org/x/term v0.36.0 // indirect
+	golang.org/x/text v0.30.0 // indirect
+	golang.org/x/time v0.14.0 // indirect
+	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
+	google.golang.org/protobuf v1.36.10 // indirect
+	gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
+	gopkg.in/inf.v0 v0.9.1 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+	k8s.io/apiextensions-apiserver v0.34.1 // indirect
+	k8s.io/client-go v0.34.1 // indirect
+	k8s.io/klog/v2 v2.130.1 // indirect
+	k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
+	k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
+	sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
+	sigs.k8s.io/randfill v1.0.0 // indirect
+	sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
+	sigs.k8s.io/yaml v1.6.0 // indirect
+)
+
+replace (
+	github.com/external-secrets/external-secrets/apis => ../../../apis
+	github.com/external-secrets/external-secrets/runtime => ../../../runtime
+)

+ 210 - 0
providers/v1/barbican/go.sum

@@ -0,0 +1,210 @@
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
+github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
+github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
+github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
+github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
+github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
+github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
+github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
+github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
+github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
+github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
+github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
+github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk=
+github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM=
+github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU=
+github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ=
+github.com/go-openapi/swag v0.25.1 h1:6uwVsx+/OuvFVPqfQmOOPsqTcm5/GkBhNwLqIR916n8=
+github.com/go-openapi/swag v0.25.1/go.mod h1:bzONdGlT0fkStgGPd3bhZf1MnuPkf2YAys6h+jZipOo=
+github.com/go-openapi/swag/cmdutils v0.25.1 h1:nDke3nAFDArAa631aitksFGj2omusks88GF1VwdYqPY=
+github.com/go-openapi/swag/cmdutils v0.25.1/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
+github.com/go-openapi/swag/conv v0.25.1 h1:+9o8YUg6QuqqBM5X6rYL/p1dpWeZRhoIt9x7CCP+he0=
+github.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs=
+github.com/go-openapi/swag/fileutils v0.25.1 h1:rSRXapjQequt7kqalKXdcpIegIShhTPXx7yw0kek2uU=
+github.com/go-openapi/swag/fileutils v0.25.1/go.mod h1:+NXtt5xNZZqmpIpjqcujqojGFek9/w55b3ecmOdtg8M=
+github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
+github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
+github.com/go-openapi/swag/jsonutils v0.25.1 h1:AihLHaD0brrkJoMqEZOBNzTLnk81Kg9cWr+SPtxtgl8=
+github.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1 h1:DSQGcdB6G0N9c/KhtpYc71PzzGEIc/fZ1no35x4/XBY=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1/go.mod h1:kjmweouyPwRUEYMSrbAidoLMGeJ5p6zdHi9BgZiqmsg=
+github.com/go-openapi/swag/loading v0.25.1 h1:6OruqzjWoJyanZOim58iG2vj934TysYVptyaoXS24kw=
+github.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc=
+github.com/go-openapi/swag/mangling v0.25.1 h1:XzILnLzhZPZNtmxKaz/2xIGPQsBsvmCjrJOWGNz/ync=
+github.com/go-openapi/swag/mangling v0.25.1/go.mod h1:CdiMQ6pnfAgyQGSOIYnZkXvqhnnwOn997uXZMAd/7mQ=
+github.com/go-openapi/swag/netutils v0.25.1 h1:2wFLYahe40tDUHfKT1GRC4rfa5T1B4GWZ+msEFA4Fl4=
+github.com/go-openapi/swag/netutils v0.25.1/go.mod h1:CAkkvqnUJX8NV96tNhEQvKz8SQo2KF0f7LleiJwIeRE=
+github.com/go-openapi/swag/stringutils v0.25.1 h1:Xasqgjvk30eUe8VKdmyzKtjkVjeiXx1Iz0zDfMNpPbw=
+github.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg=
+github.com/go-openapi/swag/typeutils v0.25.1 h1:rD/9HsEQieewNt6/k+JBwkxuAHktFtH3I3ysiFZqukA=
+github.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8=
+github.com/go-openapi/swag/yamlutils v0.25.1 h1:mry5ez8joJwzvMbaTGLhw8pXUnhDK91oSJLDPF1bmGk=
+github.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
+github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
+github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
+github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
+github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gophercloud/gophercloud/v2 v2.8.0 h1:of2+8tT6+FbEYHfYC8GBu8TXJNsXYSNm9KuvpX7Neqo=
+github.com/gophercloud/gophercloud/v2 v2.8.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
+github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
+github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
+github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
+github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
+github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
+github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
+github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
+github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
+github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyAEN8=
+github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko=
+github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
+github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
+go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
+go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
+golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
+golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
+golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
+golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
+golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
+golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
+golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
+golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
+golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
+golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
+gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
+google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
+google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
+gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
+k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
+k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
+k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
+k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
+k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
+k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
+k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
+k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
+k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
+k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
+k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
+k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+sigs.k8s.io/controller-runtime v0.22.3 h1:I7mfqz/a/WdmDCEnXmSPm8/b/yRTy6JsKKENTijTq8Y=
+sigs.k8s.io/controller-runtime v0.22.3/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8=
+sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
+sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
+sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
+sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
+sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
+sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
+sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
+sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=

+ 138 - 0
providers/v1/barbican/provider.go

@@ -0,0 +1,138 @@
+/*
+Copyright © 2025 ESO Maintainer Team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package barbican
+
+import (
+	"context"
+	"errors"
+	"fmt"
+
+	"github.com/gophercloud/gophercloud/v2"
+	"github.com/gophercloud/gophercloud/v2/openstack"
+
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	"github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
+)
+
+const (
+	errGeneric      = "barbican provider error: %w"
+	errMissingField = "barbican provider missing required field: %w"
+	errAuthFailed   = "barbican provider authentication failed: %w"
+	errClientInit   = "barbican provider client initialization failed: %w"
+)
+
+var _ esv1.Provider = &Provider{}
+
+// Provider implements the Barbican provider.
+type Provider struct{}
+
+// Capabilities returns the capabilities of the Barbican provider.
+func (p *Provider) Capabilities() esv1.SecretStoreCapabilities {
+	return esv1.SecretStoreReadOnly
+}
+
+// ValidateStore validates the Barbican store configuration.
+func (p *Provider) ValidateStore(store esv1.GenericStore) (admission.Warnings, error) {
+	if store == nil {
+		return nil, fmt.Errorf(errGeneric, errors.New("store is nil"))
+	}
+	return nil, nil
+}
+
+// NewClient creates a new Barbican client.
+func (p *Provider) NewClient(ctx context.Context, store esv1.GenericStore, kube client.Client, namespace string) (esv1.SecretsClient, error) {
+	return newClient(ctx, store, kube, namespace)
+}
+
+// getProvider retrieves the Barbican provider configuration from the store.
+func getProvider(store esv1.GenericStore) (*esv1.BarbicanProvider, error) {
+	spec := store.GetSpec()
+	if spec.Provider == nil || spec.Provider.Barbican == nil {
+		return nil, fmt.Errorf(errMissingField, errors.New("provider barbican is nil"))
+	}
+	return spec.Provider.Barbican, nil
+}
+
+func newClient(ctx context.Context, store esv1.GenericStore, kube client.Client, namespace string) (esv1.SecretsClient, error) {
+	provider, err := getProvider(store)
+	if err != nil {
+		return nil, err
+	}
+	if provider.AuthURL == "" {
+		return nil, fmt.Errorf(errMissingField, errors.New("authURL is required"))
+	}
+
+	username := provider.Auth.Username.Value
+
+	if username == "" {
+		username, err = resolvers.SecretKeyRef(ctx, kube, store.GetKind(), namespace, provider.Auth.Username.SecretRef)
+		if err != nil {
+			return nil, fmt.Errorf(errMissingField, err)
+		}
+	}
+
+	password, err := resolvers.SecretKeyRef(ctx, kube, store.GetKind(), namespace, provider.Auth.Password.SecretRef)
+	if err != nil {
+		return nil, fmt.Errorf(errMissingField, err)
+	}
+
+	authopts := gophercloud.AuthOptions{
+		IdentityEndpoint: provider.AuthURL,
+		TenantName:       provider.TenantName,
+		DomainName:       provider.DomainName,
+		Username:         username,
+		Password:         password,
+	}
+
+	auth, err := openstack.AuthenticatedClient(ctx, authopts)
+	if err != nil {
+		return nil, fmt.Errorf(errAuthFailed, err)
+	}
+
+	barbicanClient, err := openstack.NewKeyManagerV1(auth, gophercloud.EndpointOpts{
+		Region: provider.Region,
+	})
+	if err != nil {
+		return nil, fmt.Errorf(errClientInit, err)
+	}
+
+	c := &Client{
+		keyManager: barbicanClient,
+	}
+
+	return c, nil
+}
+
+// NewProvider constructs a new Barbican provider.
+func NewProvider() esv1.Provider {
+	return &Provider{}
+}
+
+// ProviderSpec returns a sample Barbican provider spec.
+func ProviderSpec() *esv1.SecretStoreProvider {
+	return &esv1.SecretStoreProvider{
+		Barbican: &esv1.BarbicanProvider{},
+	}
+}
+
+// MaintenanceStatus returns the maintenance status of the Barbican provider.
+func MaintenanceStatus() esv1.MaintenanceStatus {
+	return esv1.MaintenanceStatusMaintained
+}

+ 303 - 0
providers/v1/barbican/provider_test.go

@@ -0,0 +1,303 @@
+/*
+Copyright © 2025 ESO Maintainer Team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package barbican
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
+
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+)
+
+const (
+	testAuthURL    = "https://keystone.example.com/v3"
+	testTenantName = "test-tenant"
+	testDomainName = "default"
+	testRegion     = "RegionOne"
+	testUsername   = "test-user"
+	testPassword   = "test-password"
+	testSecretName = "barbican-creds"
+	testNamespace  = "default"
+)
+
+type validateStoreTestCase struct {
+	name        string
+	store       esv1.GenericStore
+	expectError bool
+	errorMsg    string
+}
+
+func TestProviderCapabilities(t *testing.T) {
+	provider := &Provider{}
+	capabilities := provider.Capabilities()
+
+	assert.Equal(t, esv1.SecretStoreReadOnly, capabilities)
+}
+
+func TestValidateStore(t *testing.T) {
+	provider := &Provider{}
+
+	testCases := []validateStoreTestCase{
+		{
+			name:        "nil store should return error",
+			store:       nil,
+			expectError: true,
+			errorMsg:    "store is nil",
+		},
+		{
+			name:        "valid store should pass validation",
+			store:       makeValidSecretStore(),
+			expectError: false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			warnings, err := provider.ValidateStore(tc.store)
+
+			if tc.expectError {
+				assert.Error(t, err)
+				assert.Contains(t, err.Error(), tc.errorMsg)
+				assert.Nil(t, warnings)
+			} else {
+				assert.NoError(t, err)
+				assert.Nil(t, warnings)
+			}
+		})
+	}
+}
+
+func TestGetProvider(t *testing.T) {
+	testCases := []struct {
+		name        string
+		store       esv1.GenericStore
+		expectError bool
+		errorMsg    string
+	}{
+		{
+			name:        "valid store with barbican provider",
+			store:       makeValidSecretStore(),
+			expectError: false,
+		},
+		{
+			name:        "nil provider should return error",
+			store:       makeSecretStoreWithNilProvider(),
+			expectError: true,
+			errorMsg:    "provider barbican is nil",
+		},
+		{
+			name:        "nil barbican provider should return error",
+			store:       makeSecretStoreWithNilBarbican(),
+			expectError: true,
+			errorMsg:    "provider barbican is nil",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			provider, err := getProvider(tc.store)
+
+			if tc.expectError {
+				assert.Error(t, err)
+				assert.Contains(t, err.Error(), tc.errorMsg)
+				assert.Nil(t, provider)
+			} else {
+				assert.NoError(t, err)
+				assert.NotNil(t, provider)
+				assert.Equal(t, testAuthURL, provider.AuthURL)
+				assert.Equal(t, testTenantName, provider.TenantName)
+				assert.Equal(t, testDomainName, provider.DomainName)
+				assert.Equal(t, testRegion, provider.Region)
+			}
+		})
+	}
+}
+
+func TestNewClient(t *testing.T) {
+	testCases := []struct {
+		name        string
+		store       esv1.GenericStore
+		kube        *clientfake.ClientBuilder
+		expectError bool
+		errorMsg    string
+	}{
+		{
+			name:        "missing authURL should return error",
+			store:       makeSecretStoreWithMissingAuthURL(),
+			kube:        clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
+			expectError: true,
+			errorMsg:    "missing required field",
+		},
+		{
+			name:        "username as value should pass",
+			store:       makeSecretStoreWithValueUsername(),
+			kube:        clientfake.NewClientBuilder().WithObjects(makeValidSecretWithNoUsername()),
+			expectError: false,
+		},
+		{
+			name:        "username as value and secret should pass",
+			store:       makeSecretStoreWithValueUsername(),
+			kube:        clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
+			expectError: false,
+		},
+		{
+			name:        "missing username secret should return error",
+			store:       makeValidSecretStore(),
+			kube:        clientfake.NewClientBuilder(),
+			expectError: true,
+			errorMsg:    "missing required field",
+		},
+		{
+			name:        "missing password in secret should return error",
+			store:       makeValidSecretStore(),
+			kube:        clientfake.NewClientBuilder().WithObjects(makeSecretWithMissingPassword()),
+			expectError: true,
+			errorMsg:    "missing required field",
+		},
+		{
+			name:        "nil barbican provider should return error",
+			store:       makeSecretStoreWithNilBarbican(),
+			kube:        clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
+			expectError: true,
+			errorMsg:    "provider barbican is nil",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			provider := &Provider{}
+			fakeClient := tc.kube.Build()
+
+			// Note: This test will fail when trying to actually connect to OpenStack
+			// In a real test environment, we would need to mock the OpenStack client
+			_, err := provider.NewClient(context.Background(), tc.store, fakeClient, testNamespace)
+
+			if tc.expectError {
+				assert.Error(t, err)
+				assert.Contains(t, err.Error(), tc.errorMsg)
+			} else {
+				// This would only pass with proper OpenStack mocking
+				assert.Error(t, err) // We expect an error due to missing OpenStack mock
+			}
+		})
+	}
+}
+
+// Helper functions to create test fixtures
+
+func makeValidSecretStore() *esv1.SecretStore {
+	return &esv1.SecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "test-store",
+			Namespace: testNamespace,
+		},
+		Spec: esv1.SecretStoreSpec{
+			Provider: &esv1.SecretStoreProvider{
+				Barbican: &esv1.BarbicanProvider{
+					AuthURL:    testAuthURL,
+					TenantName: testTenantName,
+					DomainName: testDomainName,
+					Region:     testRegion,
+					Auth: esv1.BarbicanAuth{
+						Username: esv1.BarbicanProviderUsernameRef{
+							SecretRef: &esmeta.SecretKeySelector{
+								Name: testSecretName,
+								Key:  "username",
+							},
+						},
+						Password: esv1.BarbicanProviderPasswordRef{
+							SecretRef: &esmeta.SecretKeySelector{
+								Name: testSecretName,
+								Key:  "password",
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+func makeSecretStoreWithValueUsername() *esv1.SecretStore {
+	store := makeValidSecretStore()
+	store.Spec.Provider.Barbican.Auth.Username = esv1.BarbicanProviderUsernameRef{
+		Value: testUsername,
+	}
+	return store
+}
+
+func makeSecretStoreWithNilProvider() *esv1.SecretStore {
+	store := makeValidSecretStore()
+	store.Spec.Provider = nil
+	return store
+}
+
+func makeSecretStoreWithNilBarbican() *esv1.SecretStore {
+	store := makeValidSecretStore()
+	store.Spec.Provider.Barbican = nil
+	return store
+}
+
+func makeSecretStoreWithMissingAuthURL() *esv1.SecretStore {
+	store := makeValidSecretStore()
+	store.Spec.Provider.Barbican.AuthURL = ""
+	return store
+}
+
+func makeValidSecret() *corev1.Secret {
+	return &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      testSecretName,
+			Namespace: testNamespace,
+		},
+		Data: map[string][]byte{
+			"username": []byte(testUsername),
+			"password": []byte(testPassword),
+		},
+	}
+}
+
+func makeValidSecretWithNoUsername() *corev1.Secret {
+	return &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      testSecretName,
+			Namespace: testNamespace,
+		},
+		Data: map[string][]byte{
+			"password": []byte(testPassword),
+		},
+	}
+}
+
+func makeSecretWithMissingPassword() *corev1.Secret {
+	return &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      testSecretName,
+			Namespace: testNamespace,
+		},
+		Data: map[string][]byte{
+			"username": []byte(testUsername),
+			// missing password key
+		},
+	}
+}

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

@@ -129,6 +129,23 @@ spec:
       tenantId: string
       tenantId: string
       useAzureSDK: false
       useAzureSDK: false
       vaultUrl: string
       vaultUrl: string
+    barbican:
+      auth:
+        password:
+          secretRef:
+            key: string
+            name: string
+            namespace: string
+        username:
+          secretRef:
+            key: string
+            name: string
+            namespace: string
+          value: string
+      authURL: string
+      domainName: string
+      region: string
+      tenantName: string
     beyondtrust:
     beyondtrust:
       auth:
       auth:
         apiKey:
         apiKey:

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

@@ -129,6 +129,23 @@ spec:
       tenantId: string
       tenantId: string
       useAzureSDK: false
       useAzureSDK: false
       vaultUrl: string
       vaultUrl: string
+    barbican:
+      auth:
+        password:
+          secretRef:
+            key: string
+            name: string
+            namespace: string
+        username:
+          secretRef:
+            key: string
+            name: string
+            namespace: string
+          value: string
+      authURL: string
+      domainName: string
+      region: string
+      tenantName: string
     beyondtrust:
     beyondtrust:
       auth:
       auth:
         apiKey:
         apiKey: