provider.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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 ibm
  13. import (
  14. "context"
  15. "encoding/json"
  16. "fmt"
  17. "github.com/IBM/go-sdk-core/v5/core"
  18. sm "github.com/IBM/secrets-manager-go-sdk/secretsmanagerv1"
  19. corev1 "k8s.io/api/core/v1"
  20. "k8s.io/apimachinery/pkg/types"
  21. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  22. esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  23. "github.com/external-secrets/external-secrets/pkg/provider"
  24. "github.com/external-secrets/external-secrets/pkg/provider/schema"
  25. "github.com/external-secrets/external-secrets/pkg/utils"
  26. )
  27. const (
  28. SecretsManagerEndpointEnv = "IBM_SECRETSMANAGER_ENDPOINT"
  29. STSEndpointEnv = "IBM_STS_ENDPOINT"
  30. SSMEndpointEnv = "IBM_SSM_ENDPOINT"
  31. errIBMClient = "cannot setup new ibm client: %w"
  32. errIBMCredSecretName = "invalid IBM SecretStore resource: missing IBM APIKey"
  33. errUninitalizedIBMProvider = "provider IBM is not initialized"
  34. errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
  35. errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
  36. errMissingSAK = "missing SecretAccessKey"
  37. errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
  38. )
  39. type SecretManagerClient interface {
  40. GetSecret(getSecretOptions *sm.GetSecretOptions) (result *sm.GetSecret, response *core.DetailedResponse, err error)
  41. }
  42. type providerIBM struct {
  43. IBMClient SecretManagerClient
  44. }
  45. type client struct {
  46. kube kclient.Client
  47. store *esv1alpha1.IBMProvider
  48. namespace string
  49. storeKind string
  50. credentials []byte
  51. }
  52. func (c *client) setAuth(ctx context.Context) error {
  53. credentialsSecret := &corev1.Secret{}
  54. credentialsSecretName := c.store.Auth.SecretRef.SecretAPIKey.Name
  55. if credentialsSecretName == "" {
  56. return fmt.Errorf(errIBMCredSecretName)
  57. }
  58. objectKey := types.NamespacedName{
  59. Name: credentialsSecretName,
  60. Namespace: c.namespace,
  61. }
  62. // only ClusterStore is allowed to set namespace (and then it's required)
  63. if c.storeKind == esv1alpha1.ClusterSecretStoreKind {
  64. if c.store.Auth.SecretRef.SecretAPIKey.Namespace == nil {
  65. return fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
  66. }
  67. objectKey.Namespace = *c.store.Auth.SecretRef.SecretAPIKey.Namespace
  68. }
  69. err := c.kube.Get(ctx, objectKey, credentialsSecret)
  70. if err != nil {
  71. return fmt.Errorf(errFetchSAKSecret, err)
  72. }
  73. c.credentials = credentialsSecret.Data[c.store.Auth.SecretRef.SecretAPIKey.Key]
  74. if (c.credentials == nil) || (len(c.credentials) == 0) {
  75. return fmt.Errorf(errMissingSAK)
  76. }
  77. return nil
  78. }
  79. func (ibm *providerIBM) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
  80. if utils.IsNil(ibm.IBMClient) {
  81. return nil, fmt.Errorf(errUninitalizedIBMProvider)
  82. }
  83. response, _, err := ibm.IBMClient.GetSecret(
  84. &sm.GetSecretOptions{
  85. SecretType: core.StringPtr(sm.GetSecretOptionsSecretTypeArbitraryConst),
  86. ID: &ref.Key,
  87. })
  88. if err != nil {
  89. return nil, err
  90. }
  91. secret := response.Resources[0].(*sm.SecretResource)
  92. secretData := secret.SecretData.(map[string]interface{})
  93. arbitrarySecretPayload := secretData["payload"].(string)
  94. return []byte(arbitrarySecretPayload), nil
  95. }
  96. func (ibm *providerIBM) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  97. if utils.IsNil(ibm.IBMClient) {
  98. return nil, fmt.Errorf(errUninitalizedIBMProvider)
  99. }
  100. response, _, err := ibm.IBMClient.GetSecret(
  101. &sm.GetSecretOptions{
  102. SecretType: core.StringPtr(sm.GetSecretOptionsSecretTypeArbitraryConst),
  103. ID: &ref.Key,
  104. })
  105. if err != nil {
  106. return nil, err
  107. }
  108. secret := response.Resources[0].(*sm.SecretResource)
  109. secretData := secret.SecretData.(map[string]interface{})
  110. arbitrarySecretPayload := secretData["payload"].(string)
  111. kv := make(map[string]string)
  112. err = json.Unmarshal([]byte(arbitrarySecretPayload), &kv)
  113. if err != nil {
  114. return nil, fmt.Errorf(errJSONSecretUnmarshal, err)
  115. }
  116. secretMap := make(map[string][]byte)
  117. for k, v := range kv {
  118. secretMap[k] = []byte(v)
  119. }
  120. return secretMap, nil
  121. }
  122. func (ibm *providerIBM) Close() error {
  123. return nil
  124. }
  125. func (ibm *providerIBM) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube kclient.Client, namespace string) (provider.SecretsClient, error) {
  126. storeSpec := store.GetSpec()
  127. ibmSpec := storeSpec.Provider.IBM
  128. iStore := &client{
  129. kube: kube,
  130. store: ibmSpec,
  131. namespace: namespace,
  132. storeKind: store.GetObjectKind().GroupVersionKind().Kind,
  133. }
  134. if err := iStore.setAuth(ctx); err != nil {
  135. return nil, err
  136. }
  137. secretsManager, err := sm.NewSecretsManagerV1(&sm.SecretsManagerV1Options{
  138. URL: *storeSpec.Provider.IBM.ServiceURL,
  139. Authenticator: &core.IamAuthenticator{
  140. ApiKey: string(iStore.credentials),
  141. },
  142. })
  143. if err != nil {
  144. return nil, fmt.Errorf(errIBMClient, err)
  145. }
  146. ibm.IBMClient = secretsManager
  147. return ibm, nil
  148. }
  149. func init() {
  150. schema.Register(&providerIBM{}, &esv1alpha1.SecretStoreProvider{
  151. IBM: &esv1alpha1.IBMProvider{},
  152. })
  153. }