provider.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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 pulumi
  13. import (
  14. "context"
  15. "errors"
  16. "fmt"
  17. esc "github.com/pulumi/esc/cmd/esc/cli/client"
  18. kclient "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. "github.com/external-secrets/external-secrets/pkg/utils"
  22. "github.com/external-secrets/external-secrets/pkg/utils/resolvers"
  23. )
  24. type Provider struct{}
  25. var _ esv1beta1.Provider = &Provider{}
  26. const (
  27. errClusterStoreRequiresNamespace = "cluster store requires namespace"
  28. errCannotResolveSecretKeyRef = "cannot resolve secret key ref: %w"
  29. errStoreIsNil = "store is nil"
  30. errNoStoreTypeOrWrongStoreType = "no store type or wrong store type"
  31. errOrganizationIsRequired = "organization is required"
  32. errEnvironmentIsRequired = "environment is required"
  33. errSecretRefNameIsRequired = "secretRef.name is required"
  34. errSecretRefKeyIsRequired = "secretRef.key is required"
  35. )
  36. func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  37. cfg, err := getConfig(store)
  38. if err != nil {
  39. return nil, err
  40. }
  41. storeKind := store.GetKind()
  42. if storeKind == esv1beta1.ClusterSecretStoreKind && doesConfigDependOnNamespace(cfg) {
  43. return nil, errors.New(errClusterStoreRequiresNamespace)
  44. }
  45. accessToken, err := loadAccessTokenSecret(ctx, cfg.AccessToken, kube, storeKind, namespace)
  46. if err != nil {
  47. return nil, err
  48. }
  49. escClient := esc.New("external-secrets-operator", cfg.APIURL, accessToken, false)
  50. return &client{
  51. escClient: escClient,
  52. environment: cfg.Environment,
  53. organization: cfg.Organization,
  54. }, nil
  55. }
  56. func loadAccessTokenSecret(ctx context.Context, ref *esv1beta1.PulumiProviderSecretRef, kube kclient.Client, storeKind, namespace string) (string, error) {
  57. acctoken, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, ref.SecretRef)
  58. if err != nil {
  59. return "", fmt.Errorf(errCannotResolveSecretKeyRef, err)
  60. }
  61. return acctoken, nil
  62. }
  63. func doesConfigDependOnNamespace(cfg *esv1beta1.PulumiProvider) bool {
  64. if cfg.AccessToken.SecretRef != nil && cfg.AccessToken.SecretRef.Namespace == nil {
  65. return true
  66. }
  67. return false
  68. }
  69. func getConfig(store esv1beta1.GenericStore) (*esv1beta1.PulumiProvider, error) {
  70. if store == nil {
  71. return nil, errors.New(errStoreIsNil)
  72. }
  73. spec := store.GetSpec()
  74. if spec == nil || spec.Provider == nil || spec.Provider.Pulumi == nil {
  75. return nil, errors.New(errNoStoreTypeOrWrongStoreType)
  76. }
  77. cfg := spec.Provider.Pulumi
  78. if cfg.APIURL == "" {
  79. cfg.APIURL = "https://api.pulumi.com"
  80. }
  81. if cfg.Organization == "" {
  82. return nil, errors.New(errOrganizationIsRequired)
  83. }
  84. if cfg.Environment == "" {
  85. return nil, errors.New(errEnvironmentIsRequired)
  86. }
  87. err := validateStoreSecretRef(store, cfg.AccessToken)
  88. if err != nil {
  89. return nil, err
  90. }
  91. return cfg, nil
  92. }
  93. func validateStoreSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.PulumiProviderSecretRef) error {
  94. if ref != nil {
  95. if err := utils.ValidateReferentSecretSelector(store, *ref.SecretRef); err != nil {
  96. return err
  97. }
  98. }
  99. return validateSecretRef(ref)
  100. }
  101. func validateSecretRef(ref *esv1beta1.PulumiProviderSecretRef) error {
  102. if ref.SecretRef != nil {
  103. if ref.SecretRef.Name == "" {
  104. return errors.New(errSecretRefNameIsRequired)
  105. }
  106. if ref.SecretRef.Key == "" {
  107. return errors.New(errSecretRefKeyIsRequired)
  108. }
  109. }
  110. return nil
  111. }
  112. func (p *Provider) ValidateStore(store esv1beta1.GenericStore) (admission.Warnings, error) {
  113. _, err := getConfig(store)
  114. return nil, err
  115. }
  116. func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
  117. return esv1beta1.SecretStoreReadOnly
  118. }
  119. func init() {
  120. esv1beta1.Register(&Provider{}, &esv1beta1.SecretStoreProvider{
  121. Pulumi: &esv1beta1.PulumiProvider{},
  122. })
  123. }