client.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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 onboardbase
  13. import (
  14. "context"
  15. "encoding/json"
  16. "errors"
  17. "fmt"
  18. "net/url"
  19. "strings"
  20. "time"
  21. "github.com/tidwall/gjson"
  22. corev1 "k8s.io/api/core/v1"
  23. "k8s.io/apimachinery/pkg/types"
  24. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  25. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  26. "github.com/external-secrets/external-secrets/pkg/find"
  27. onboardbaseClient "github.com/external-secrets/external-secrets/pkg/provider/onboardbase/client"
  28. "github.com/external-secrets/external-secrets/pkg/utils"
  29. )
  30. const (
  31. errGetSecret = "could not get secret %s: %s"
  32. errGetSecrets = "could not get secrets %s"
  33. errUnmarshalSecretMap = "unable to unmarshal secret %s: %w"
  34. errOnboardbaseAPIKeySecretName = "missing auth.secretRef.onboardbaseAPIKey.name"
  35. errInvalidClusterStoreMissingOnboardbaseAPIKeyNamespace = "missing auth.secretRef.onboardbaseAPIKey.namespace"
  36. errFetchOnboardbaseAPIKeySecret = "unable to find find OnboardbaseAPIKey secret: %w"
  37. errMissingOnboardbaseAPIKey = "auth.secretRef.onboardbaseAPIKey.key '%s' not found in secret '%s'"
  38. errMissingOnboardbasePasscode = "auth.secretRef.onboardbasePasscode.key '%s' not found in secret '%s'"
  39. errSecretKeyFmt = "cannot find property %s in secret data for key: %q"
  40. )
  41. type Client struct {
  42. onboardbase SecretsClientInterface
  43. onboardbaseAPIKey string
  44. onboardbasePasscode string
  45. project string
  46. environment string
  47. kube kclient.Client
  48. store *esv1beta1.OnboardbaseProvider
  49. namespace string
  50. storeKind string
  51. }
  52. // SecretsClientInterface defines the required Onboardbase Client methods.
  53. type SecretsClientInterface interface {
  54. BaseURL() *url.URL
  55. Authenticate() error
  56. GetSecret(request onboardbaseClient.SecretRequest) (*onboardbaseClient.SecretResponse, error)
  57. DeleteSecret(request onboardbaseClient.SecretRequest) error
  58. GetSecrets(request onboardbaseClient.SecretsRequest) (*onboardbaseClient.SecretsResponse, error)
  59. }
  60. func (c *Client) setAuth(ctx context.Context) error {
  61. credentialsSecret := &corev1.Secret{}
  62. credentialsSecretName := c.store.Auth.OnboardbaseAPIKeyRef.Name
  63. if credentialsSecretName == "" {
  64. return errors.New(errOnboardbaseAPIKeySecretName)
  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.OnboardbaseAPIKeyRef.Namespace == nil {
  73. return errors.New(errInvalidClusterStoreMissingOnboardbaseAPIKeyNamespace)
  74. }
  75. objectKey.Namespace = *c.store.Auth.OnboardbaseAPIKeyRef.Namespace
  76. }
  77. err := c.kube.Get(ctx, objectKey, credentialsSecret)
  78. if err != nil {
  79. return fmt.Errorf(errFetchOnboardbaseAPIKeySecret, err)
  80. }
  81. onboardbaseAPIKey := credentialsSecret.Data[c.store.Auth.OnboardbaseAPIKeyRef.Key]
  82. if (onboardbaseAPIKey == nil) || (len(onboardbaseAPIKey) == 0) {
  83. return fmt.Errorf(errMissingOnboardbaseAPIKey, c.store.Auth.OnboardbaseAPIKeyRef.Key, credentialsSecretName)
  84. }
  85. c.onboardbaseAPIKey = string(onboardbaseAPIKey)
  86. onboardbasePasscode := credentialsSecret.Data[c.store.Auth.OnboardbasePasscodeRef.Key]
  87. if (onboardbasePasscode == nil) || (len(onboardbasePasscode) == 0) {
  88. return fmt.Errorf(errMissingOnboardbasePasscode, c.store.Auth.OnboardbasePasscodeRef.Key, credentialsSecretName)
  89. }
  90. c.onboardbasePasscode = string(onboardbasePasscode)
  91. return nil
  92. }
  93. func (c *Client) Validate() (esv1beta1.ValidationResult, error) {
  94. timeout := 15 * time.Second
  95. clientURL := c.onboardbase.BaseURL().String()
  96. if err := utils.NetworkValidate(clientURL, timeout); err != nil {
  97. return esv1beta1.ValidationResultError, err
  98. }
  99. if err := c.onboardbase.Authenticate(); err != nil {
  100. return esv1beta1.ValidationResultError, err
  101. }
  102. return esv1beta1.ValidationResultReady, nil
  103. }
  104. func (c *Client) DeleteSecret(_ context.Context, _ esv1beta1.PushSecretRemoteRef) error {
  105. // not implemented
  106. return nil
  107. }
  108. func (c *Client) SecretExists(_ context.Context, _ esv1beta1.PushSecretRemoteRef) (bool, error) {
  109. // not implemented
  110. return false, nil
  111. }
  112. func (c *Client) PushSecret(_ context.Context, _ *corev1.Secret, _ esv1beta1.PushSecretData) error {
  113. // not implemented
  114. return nil
  115. }
  116. func (c *Client) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  117. request := onboardbaseClient.SecretRequest{
  118. Project: c.project,
  119. Environment: c.environment,
  120. Name: ref.Key,
  121. }
  122. secret, err := c.onboardbase.GetSecret(request)
  123. if err != nil {
  124. return nil, fmt.Errorf(errGetSecret, ref.Key, err)
  125. }
  126. value := secret.Value
  127. if ref.Property != "" {
  128. jsonRes := gjson.Get(secret.Value, ref.Property)
  129. if !jsonRes.Exists() {
  130. return nil, fmt.Errorf(errSecretKeyFmt, ref.Property, ref.Key)
  131. }
  132. value = jsonRes.Raw
  133. }
  134. return []byte(value), nil
  135. }
  136. func (c *Client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  137. data, err := c.GetSecret(ctx, ref)
  138. if err != nil {
  139. return nil, err
  140. }
  141. kv := make(map[string]json.RawMessage)
  142. err = json.Unmarshal(data, &kv)
  143. if err != nil {
  144. return nil, fmt.Errorf(errUnmarshalSecretMap, ref.Key, err)
  145. }
  146. secretData := make(map[string][]byte)
  147. for k, v := range kv {
  148. var strVal string
  149. err = json.Unmarshal(v, &strVal)
  150. if err == nil {
  151. secretData[k] = []byte(strVal)
  152. } else {
  153. secretData[k] = v
  154. }
  155. }
  156. return secretData, nil
  157. }
  158. func (c *Client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  159. if len(ref.Tags) > 0 {
  160. return nil, errors.New("find by tags not supported")
  161. }
  162. secrets, err := c.getSecrets(ctx)
  163. if err != nil {
  164. return nil, err
  165. }
  166. if ref.Name == nil && ref.Path == nil {
  167. return secrets, nil
  168. }
  169. var matcher *find.Matcher
  170. if ref.Name != nil {
  171. m, err := find.New(*ref.Name)
  172. if err != nil {
  173. return nil, err
  174. }
  175. matcher = m
  176. }
  177. selected := map[string][]byte{}
  178. for key, value := range secrets {
  179. if (matcher != nil && !matcher.MatchName(key)) || (ref.Path != nil && !strings.HasPrefix(key, *ref.Path)) {
  180. continue
  181. }
  182. selected[key] = value
  183. }
  184. return selected, nil
  185. }
  186. func (c *Client) Close(_ context.Context) error {
  187. return nil
  188. }
  189. func (c *Client) getSecrets(_ context.Context) (map[string][]byte, error) {
  190. request := onboardbaseClient.SecretsRequest{
  191. Project: c.project,
  192. Environment: c.environment,
  193. }
  194. response, err := c.onboardbase.GetSecrets(request)
  195. if err != nil {
  196. return nil, fmt.Errorf(errGetSecrets, err)
  197. }
  198. return externalSecretsFormat(response.Secrets), nil
  199. }
  200. func externalSecretsFormat(secrets onboardbaseClient.Secrets) map[string][]byte {
  201. converted := make(map[string][]byte, len(secrets))
  202. for key, value := range secrets {
  203. converted[key] = []byte(value)
  204. }
  205. return converted
  206. }