provider.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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 implieclient.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package infisical
  13. import (
  14. "context"
  15. "errors"
  16. "fmt"
  17. "net/http"
  18. "time"
  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/pkg/provider/infisical/api"
  24. "github.com/external-secrets/external-secrets/pkg/utils"
  25. "github.com/external-secrets/external-secrets/pkg/utils/resolvers"
  26. )
  27. type Provider struct {
  28. apiClient *api.InfisicalClient
  29. apiScope *InfisicalClientScope
  30. }
  31. type InfisicalClientScope struct {
  32. EnvironmentSlug string
  33. ProjectSlug string
  34. Recursive bool
  35. SecretPath string
  36. ExpandSecretReferences bool
  37. }
  38. // https://github.com/external-secrets/external-secrets/issues/644
  39. var _ esv1.SecretsClient = &Provider{}
  40. var _ esv1.Provider = &Provider{}
  41. func init() {
  42. esv1.Register(&Provider{}, &esv1.SecretStoreProvider{
  43. Infisical: &esv1.InfisicalProvider{},
  44. }, esv1.MaintenanceStatusMaintained)
  45. }
  46. func (p *Provider) Capabilities() esv1.SecretStoreCapabilities {
  47. return esv1.SecretStoreReadOnly
  48. }
  49. func (p *Provider) NewClient(ctx context.Context, store esv1.GenericStore, kube kclient.Client, namespace string) (esv1.SecretsClient, error) {
  50. storeSpec := store.GetSpec()
  51. if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.Infisical == nil {
  52. return nil, errors.New("invalid infisical store")
  53. }
  54. infisicalSpec := storeSpec.Provider.Infisical
  55. apiClient, err := api.NewAPIClient(infisicalSpec.HostAPI, &http.Client{
  56. Timeout: time.Second * 15,
  57. })
  58. if err != nil {
  59. return nil, err
  60. }
  61. if infisicalSpec.Auth.UniversalAuthCredentials != nil {
  62. universalAuthCredentials := infisicalSpec.Auth.UniversalAuthCredentials
  63. clientID, err := GetStoreSecretData(ctx, store, kube, namespace, universalAuthCredentials.ClientID)
  64. if err != nil {
  65. return nil, err
  66. }
  67. clientSecret, err := GetStoreSecretData(ctx, store, kube, namespace, universalAuthCredentials.ClientSecret)
  68. if err != nil {
  69. return nil, err
  70. }
  71. if err := apiClient.SetTokenViaMachineIdentity(clientID, clientSecret); err != nil {
  72. return nil, fmt.Errorf("failed to authenticate via universal auth %w", err)
  73. }
  74. secretPath := infisicalSpec.SecretsScope.SecretsPath
  75. if secretPath == "" {
  76. secretPath = "/"
  77. }
  78. return &Provider{
  79. apiClient: apiClient,
  80. apiScope: &InfisicalClientScope{
  81. EnvironmentSlug: infisicalSpec.SecretsScope.EnvironmentSlug,
  82. ProjectSlug: infisicalSpec.SecretsScope.ProjectSlug,
  83. Recursive: infisicalSpec.SecretsScope.Recursive,
  84. SecretPath: secretPath,
  85. ExpandSecretReferences: infisicalSpec.SecretsScope.ExpandSecretReferences,
  86. },
  87. }, nil
  88. }
  89. return &Provider{}, errors.New("authentication method not found")
  90. }
  91. func (p *Provider) Close(ctx context.Context) error {
  92. if err := p.apiClient.RevokeAccessToken(); err != nil {
  93. return err
  94. }
  95. return nil
  96. }
  97. func GetStoreSecretData(ctx context.Context, store esv1.GenericStore, kube kclient.Client, namespace string, secret esmeta.SecretKeySelector) (string, error) {
  98. secretRef := esmeta.SecretKeySelector{
  99. Name: secret.Name,
  100. Key: secret.Key,
  101. }
  102. if secret.Namespace != nil {
  103. secretRef.Namespace = secret.Namespace
  104. }
  105. secretData, err := resolvers.SecretKeyRef(ctx, kube, store.GetObjectKind().GroupVersionKind().Kind, namespace, &secretRef)
  106. if err != nil {
  107. return "", err
  108. }
  109. return secretData, nil
  110. }
  111. func (p *Provider) ValidateStore(store esv1.GenericStore) (admission.Warnings, error) {
  112. storeSpec := store.GetSpec()
  113. infisicalStoreSpec := storeSpec.Provider.Infisical
  114. if infisicalStoreSpec == nil {
  115. return nil, errors.New("invalid infisical store")
  116. }
  117. if infisicalStoreSpec.SecretsScope.EnvironmentSlug == "" || infisicalStoreSpec.SecretsScope.ProjectSlug == "" {
  118. return nil, errors.New("secretsScope.projectSlug and secretsScope.environmentSlug cannot be empty")
  119. }
  120. if infisicalStoreSpec.Auth.UniversalAuthCredentials != nil {
  121. uaCredential := infisicalStoreSpec.Auth.UniversalAuthCredentials
  122. // to validate reference authentication
  123. err := utils.ValidateReferentSecretSelector(store, uaCredential.ClientID)
  124. if err != nil {
  125. return nil, err
  126. }
  127. err = utils.ValidateReferentSecretSelector(store, uaCredential.ClientSecret)
  128. if err != nil {
  129. return nil, err
  130. }
  131. if uaCredential.ClientID.Key == "" || uaCredential.ClientSecret.Key == "" {
  132. return nil, errors.New("universalAuthCredentials.clientId and universalAuthCredentials.clientSecret cannot be empty")
  133. }
  134. }
  135. return nil, nil
  136. }