client.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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 impliec.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package doppler
  13. import (
  14. "context"
  15. "encoding/json"
  16. "fmt"
  17. "net/url"
  18. "strings"
  19. "time"
  20. corev1 "k8s.io/api/core/v1"
  21. "k8s.io/apimachinery/pkg/types"
  22. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  23. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  24. "github.com/external-secrets/external-secrets/pkg/find"
  25. dClient "github.com/external-secrets/external-secrets/pkg/provider/doppler/client"
  26. "github.com/external-secrets/external-secrets/pkg/utils"
  27. )
  28. const (
  29. customBaseURLEnvVar = "DOPPLER_BASE_URL"
  30. verifyTLSOverrideEnvVar = "DOPPLER_VERIFY_TLS"
  31. errGetSecret = "could not get secret %s: %s"
  32. errGetSecrets = "could not get secrets %s"
  33. errUnmarshalSecretMap = "unable to unmarshal secret %s: %w"
  34. secretsDownloadFileKey = "DOPPLER_SECRETS_FILE"
  35. errDopplerTokenSecretName = "missing auth.secretRef.dopplerToken.name"
  36. errInvalidClusterStoreMissingDopplerTokenNamespace = "missing auth.secretRef.dopplerToken.namespace"
  37. errFetchDopplerTokenSecret = "unable to find find DopplerToken secret: %w"
  38. errMissingDopplerToken = "auth.secretRef.dopplerToken.key '%s' not found in secret '%s'"
  39. )
  40. type Client struct {
  41. doppler SecretsClientInterface
  42. dopplerToken string
  43. project string
  44. config string
  45. nameTransformer string
  46. format string
  47. kube kclient.Client
  48. store *esv1beta1.DopplerProvider
  49. namespace string
  50. storeKind string
  51. }
  52. // SecretsClientInterface defines the required Doppler Client methods.
  53. type SecretsClientInterface interface {
  54. BaseURL() *url.URL
  55. Authenticate() error
  56. GetSecret(request dClient.SecretRequest) (*dClient.SecretResponse, error)
  57. GetSecrets(request dClient.SecretsRequest) (*dClient.SecretsResponse, error)
  58. }
  59. func (c *Client) setAuth(ctx context.Context) error {
  60. credentialsSecret := &corev1.Secret{}
  61. credentialsSecretName := c.store.Auth.SecretRef.DopplerToken.Name
  62. if credentialsSecretName == "" {
  63. return fmt.Errorf(errDopplerTokenSecretName)
  64. }
  65. objectKey := types.NamespacedName{
  66. Name: credentialsSecretName,
  67. Namespace: c.namespace,
  68. }
  69. // only ClusterStore is allowed to set namespace (and then it's required)
  70. if c.storeKind == esv1beta1.ClusterSecretStoreKind {
  71. if c.store.Auth.SecretRef.DopplerToken.Namespace == nil {
  72. return fmt.Errorf(errInvalidClusterStoreMissingDopplerTokenNamespace)
  73. }
  74. objectKey.Namespace = *c.store.Auth.SecretRef.DopplerToken.Namespace
  75. }
  76. err := c.kube.Get(ctx, objectKey, credentialsSecret)
  77. if err != nil {
  78. return fmt.Errorf(errFetchDopplerTokenSecret, err)
  79. }
  80. dopplerToken := credentialsSecret.Data[c.store.Auth.SecretRef.DopplerToken.Key]
  81. if (dopplerToken == nil) || (len(dopplerToken) == 0) {
  82. return fmt.Errorf(errMissingDopplerToken, c.store.Auth.SecretRef.DopplerToken.Key, credentialsSecretName)
  83. }
  84. c.dopplerToken = string(dopplerToken)
  85. return nil
  86. }
  87. func (c *Client) Validate() (esv1beta1.ValidationResult, error) {
  88. timeout := 15 * time.Second
  89. clientURL := c.doppler.BaseURL().String()
  90. if err := utils.NetworkValidate(clientURL, timeout); err != nil {
  91. return esv1beta1.ValidationResultError, err
  92. }
  93. if err := c.doppler.Authenticate(); err != nil {
  94. return esv1beta1.ValidationResultError, err
  95. }
  96. return esv1beta1.ValidationResultReady, nil
  97. }
  98. func (c *Client) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRef) error {
  99. return fmt.Errorf("not implemented")
  100. }
  101. func (c *Client) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
  102. return fmt.Errorf("not implemented")
  103. }
  104. func (c *Client) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  105. request := dClient.SecretRequest{
  106. Name: ref.Key,
  107. Project: c.project,
  108. Config: c.config,
  109. }
  110. secret, err := c.doppler.GetSecret(request)
  111. if err != nil {
  112. return nil, fmt.Errorf(errGetSecret, ref.Key, err)
  113. }
  114. return []byte(secret.Value), nil
  115. }
  116. func (c *Client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  117. data, err := c.GetSecret(ctx, ref)
  118. if err != nil {
  119. return nil, err
  120. }
  121. kv := make(map[string]json.RawMessage)
  122. err = json.Unmarshal(data, &kv)
  123. if err != nil {
  124. return nil, fmt.Errorf(errUnmarshalSecretMap, ref.Key, err)
  125. }
  126. secretData := make(map[string][]byte)
  127. for k, v := range kv {
  128. var strVal string
  129. err = json.Unmarshal(v, &strVal)
  130. if err == nil {
  131. secretData[k] = []byte(strVal)
  132. } else {
  133. secretData[k] = v
  134. }
  135. }
  136. return secretData, nil
  137. }
  138. func (c *Client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  139. secrets, err := c.getSecrets(ctx)
  140. selected := map[string][]byte{}
  141. if err != nil {
  142. return nil, err
  143. }
  144. if ref.Name == nil && ref.Path == nil {
  145. return secrets, nil
  146. }
  147. var matcher *find.Matcher
  148. if ref.Name != nil {
  149. m, err := find.New(*ref.Name)
  150. if err != nil {
  151. return nil, err
  152. }
  153. matcher = m
  154. }
  155. for key, value := range secrets {
  156. if (matcher != nil && !matcher.MatchName(key)) || (ref.Path != nil && !strings.HasPrefix(key, *ref.Path)) {
  157. continue
  158. }
  159. selected[key] = value
  160. }
  161. return selected, nil
  162. }
  163. func (c *Client) Close(_ context.Context) error {
  164. return nil
  165. }
  166. func (c *Client) getSecrets(_ context.Context) (map[string][]byte, error) {
  167. request := dClient.SecretsRequest{
  168. Project: c.project,
  169. Config: c.config,
  170. NameTransformer: c.nameTransformer,
  171. Format: c.format,
  172. }
  173. response, err := c.doppler.GetSecrets(request)
  174. if err != nil {
  175. return nil, fmt.Errorf(errGetSecrets, err)
  176. }
  177. if c.format != "" {
  178. return map[string][]byte{
  179. secretsDownloadFileKey: response.Body,
  180. }, nil
  181. }
  182. return externalSecretsFormat(response.Secrets), nil
  183. }
  184. func externalSecretsFormat(secrets dClient.Secrets) map[string][]byte {
  185. converted := make(map[string][]byte, len(secrets))
  186. for key, value := range secrets {
  187. converted[key] = []byte(value)
  188. }
  189. return converted
  190. }