provider.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package dvls
  14. import (
  15. "context"
  16. "fmt"
  17. "net/url"
  18. "strings"
  19. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  20. "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
  21. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  22. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  23. "github.com/external-secrets/external-secrets/runtime/esutils"
  24. )
  25. var _ esv1.Provider = &Provider{}
  26. // Provider implements the external-secrets Provider interface for DVLS.
  27. type Provider struct{}
  28. // NewClient creates a new DVLS SecretsClient.
  29. func (p *Provider) NewClient(ctx context.Context, store esv1.GenericStore, kube kclient.Client, namespace string) (esv1.SecretsClient, error) {
  30. dvlsProvider, err := getDVLSProvider(store)
  31. if err != nil {
  32. return nil, err
  33. }
  34. storeKind := store.GetObjectKind().GroupVersionKind().Kind
  35. credClient, vaultID, err := NewDVLSClient(ctx, kube, storeKind, namespace, dvlsProvider)
  36. if err != nil {
  37. return nil, fmt.Errorf("failed to create DVLS client: %w", err)
  38. }
  39. return NewClient(credClient, vaultID), nil
  40. }
  41. // ValidateStore validates the SecretStore configuration.
  42. func (p *Provider) ValidateStore(store esv1.GenericStore) (admission.Warnings, error) {
  43. dvlsProvider, err := getDVLSProvider(store)
  44. if err != nil {
  45. return nil, err
  46. }
  47. if dvlsProvider.ServerURL == "" {
  48. return nil, fmt.Errorf("serverUrl is required")
  49. }
  50. vault := strings.TrimSpace(dvlsProvider.Vault)
  51. if vault != dvlsProvider.Vault {
  52. return nil, fmt.Errorf("vault must not contain leading or trailing whitespace")
  53. }
  54. parsedURL, err := url.Parse(dvlsProvider.ServerURL)
  55. if err != nil {
  56. return nil, fmt.Errorf("serverUrl must be a valid URL: %w", err)
  57. }
  58. if parsedURL.Scheme == "" || parsedURL.Host == "" {
  59. return nil, fmt.Errorf("serverUrl must be a valid URL with scheme and host")
  60. }
  61. if parsedURL.Scheme != "https" && parsedURL.Scheme != "http" {
  62. return nil, fmt.Errorf("serverUrl scheme must be http or https, got %q", parsedURL.Scheme)
  63. }
  64. if parsedURL.Scheme == "http" && !dvlsProvider.Insecure {
  65. return nil, fmt.Errorf("http URLs require 'insecure: true' to be set explicitly")
  66. }
  67. // Validate auth configuration
  68. if err := validateAuthSecretRef(store, &dvlsProvider.Auth.SecretRef); err != nil {
  69. return nil, err
  70. }
  71. return nil, nil
  72. }
  73. // Capabilities returns the provider's capabilities.
  74. func (p *Provider) Capabilities() esv1.SecretStoreCapabilities {
  75. return esv1.SecretStoreReadWrite
  76. }
  77. // validateAuthSecretRef validates the authentication secret references.
  78. func validateAuthSecretRef(store esv1.GenericStore, ref *esv1.DVLSAuthSecretRef) error {
  79. if err := requireSecretSelector(ref.AppID, "appId"); err != nil {
  80. return err
  81. }
  82. if err := esutils.ValidateSecretSelector(store, ref.AppID); err != nil {
  83. return fmt.Errorf("invalid appId: %w", err)
  84. }
  85. if err := requireSecretSelector(ref.AppSecret, "appSecret"); err != nil {
  86. return err
  87. }
  88. if err := esutils.ValidateSecretSelector(store, ref.AppSecret); err != nil {
  89. return fmt.Errorf("invalid appSecret: %w", err)
  90. }
  91. return nil
  92. }
  93. func requireSecretSelector(sel esmeta.SecretKeySelector, field string) error {
  94. if sel.Name == "" {
  95. return fmt.Errorf("%s secret name is required", field)
  96. }
  97. if sel.Key == "" {
  98. return fmt.Errorf("%s secret key is required", field)
  99. }
  100. return nil
  101. }
  102. // getDVLSProvider extracts the DVLS provider configuration from the store.
  103. func getDVLSProvider(store esv1.GenericStore) (*esv1.DVLSProvider, error) {
  104. spec := store.GetSpec()
  105. if spec == nil || spec.Provider == nil || spec.Provider.DVLS == nil {
  106. return nil, fmt.Errorf("DVLS provider configuration is missing")
  107. }
  108. return spec.Provider.DVLS, nil
  109. }
  110. // NewProvider creates a new DVLS Provider instance.
  111. func NewProvider() esv1.Provider {
  112. return &Provider{}
  113. }
  114. // ProviderSpec returns the provider specification for registration.
  115. func ProviderSpec() *esv1.SecretStoreProvider {
  116. return &esv1.SecretStoreProvider{
  117. DVLS: &esv1.DVLSProvider{},
  118. }
  119. }
  120. // MaintenanceStatus returns the maintenance status of the provider.
  121. func MaintenanceStatus() esv1.MaintenanceStatus {
  122. return esv1.MaintenanceStatusMaintained
  123. }