client.go 6.6 KB

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