provider.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package delinea
  13. import (
  14. "context"
  15. "errors"
  16. "fmt"
  17. "github.com/DelineaXPM/dsv-sdk-go/v2/vault"
  18. kubeClient "sigs.k8s.io/controller-runtime/pkg/client"
  19. "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
  20. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  21. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  22. "github.com/external-secrets/external-secrets/pkg/utils"
  23. "github.com/external-secrets/external-secrets/pkg/utils/resolvers"
  24. )
  25. var (
  26. errEmptyTenant = errors.New("tenant must not be empty")
  27. errEmptyClientID = errors.New("clientID must be set")
  28. errEmptyClientSecret = errors.New("clientSecret must be set")
  29. errSecretRefAndValueConflict = errors.New("cannot specify both secret reference and value")
  30. errSecretRefAndValueMissing = errors.New("must specify either secret reference or direct value")
  31. errMissingStore = errors.New("missing store specification")
  32. errInvalidSpec = errors.New("invalid specification for delinea provider")
  33. errMissingSecretName = errors.New("must specify a secret name")
  34. errMissingSecretKey = errors.New("must specify a secret key")
  35. errClusterStoreRequiresNamespace = errors.New("when using a ClusterSecretStore, namespaces must be explicitly set")
  36. )
  37. type Provider struct{}
  38. var _ esv1beta1.Provider = &Provider{}
  39. // Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
  40. func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
  41. return esv1beta1.SecretStoreReadOnly
  42. }
  43. func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kubeClient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  44. cfg, err := getConfig(store)
  45. if err != nil {
  46. return nil, err
  47. }
  48. if store.GetKind() == esv1beta1.ClusterSecretStoreKind && doesConfigDependOnNamespace(cfg) {
  49. // we are not attached to a specific namespace, but some config values are dependent on it
  50. return nil, errClusterStoreRequiresNamespace
  51. }
  52. clientID, err := loadConfigSecret(ctx, store.GetKind(), cfg.ClientID, kube, namespace)
  53. if err != nil {
  54. return nil, err
  55. }
  56. clientSecret, err := loadConfigSecret(ctx, store.GetKind(), cfg.ClientSecret, kube, namespace)
  57. if err != nil {
  58. return nil, err
  59. }
  60. dsvClient, err := vault.New(vault.Configuration{
  61. Credentials: vault.ClientCredential{
  62. ClientID: clientID,
  63. ClientSecret: clientSecret,
  64. },
  65. Tenant: cfg.Tenant,
  66. TLD: cfg.TLD,
  67. URLTemplate: cfg.URLTemplate,
  68. })
  69. if err != nil {
  70. return nil, err
  71. }
  72. return &client{
  73. api: dsvClient,
  74. }, nil
  75. }
  76. func loadConfigSecret(
  77. ctx context.Context,
  78. storeKind string,
  79. ref *esv1beta1.DelineaProviderSecretRef,
  80. kube kubeClient.Client,
  81. namespace string) (string, error) {
  82. if ref.SecretRef == nil {
  83. return ref.Value, nil
  84. }
  85. if err := validateSecretRef(ref); err != nil {
  86. return "", err
  87. }
  88. return resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, ref.SecretRef)
  89. }
  90. func validateStoreSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.DelineaProviderSecretRef) error {
  91. if ref.SecretRef != nil {
  92. if err := utils.ValidateReferentSecretSelector(store, *ref.SecretRef); err != nil {
  93. return err
  94. }
  95. }
  96. return validateSecretRef(ref)
  97. }
  98. func validateSecretRef(ref *esv1beta1.DelineaProviderSecretRef) error {
  99. if ref.SecretRef != nil {
  100. if ref.Value != "" {
  101. return errSecretRefAndValueConflict
  102. }
  103. if ref.SecretRef.Name == "" {
  104. return errMissingSecretName
  105. }
  106. if ref.SecretRef.Key == "" {
  107. return errMissingSecretKey
  108. }
  109. } else if ref.Value == "" {
  110. return errSecretRefAndValueMissing
  111. }
  112. return nil
  113. }
  114. func doesConfigDependOnNamespace(cfg *esv1beta1.DelineaProvider) bool {
  115. if cfg.ClientID.SecretRef != nil && cfg.ClientID.SecretRef.Namespace == nil {
  116. return true
  117. }
  118. if cfg.ClientSecret.SecretRef != nil && cfg.ClientSecret.SecretRef.Namespace == nil {
  119. return true
  120. }
  121. return false
  122. }
  123. func getConfig(store esv1beta1.GenericStore) (*esv1beta1.DelineaProvider, error) {
  124. if store == nil {
  125. return nil, errMissingStore
  126. }
  127. storeSpec := store.GetSpec()
  128. if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.Delinea == nil {
  129. return nil, errInvalidSpec
  130. }
  131. cfg := storeSpec.Provider.Delinea
  132. if cfg.Tenant == "" {
  133. return nil, errEmptyTenant
  134. }
  135. if cfg.ClientID == nil {
  136. return nil, errEmptyClientID
  137. }
  138. if cfg.ClientSecret == nil {
  139. return nil, errEmptyClientSecret
  140. }
  141. err := validateStoreSecretRef(store, cfg.ClientID)
  142. if err != nil {
  143. return nil, err
  144. }
  145. err = validateStoreSecretRef(store, cfg.ClientSecret)
  146. if err != nil {
  147. return nil, err
  148. }
  149. return cfg, nil
  150. }
  151. func (p *Provider) ValidateStore(store esv1beta1.GenericStore) (admission.Warnings, error) {
  152. _, err := getConfig(store)
  153. return nil, err
  154. }
  155. func (p *Provider) ApplyReferent(spec kubeClient.Object, _ esmeta.ReferentCallOrigin, _ string) (kubeClient.Object, error) {
  156. return spec, nil
  157. }
  158. func (p *Provider) NewClientFromObj(_ context.Context, _ kubeClient.Object, _ kubeClient.Client, _ string) (esv1beta1.SecretsClient, error) {
  159. return nil, fmt.Errorf("not implemented")
  160. }
  161. func (p *Provider) Convert(_ esv1beta1.GenericStore) (kubeClient.Object, error) {
  162. return nil, nil
  163. }
  164. func init() {
  165. esv1beta1.Register(&Provider{}, &esv1beta1.SecretStoreProvider{
  166. Delinea: &esv1beta1.DelineaProvider{},
  167. })
  168. }