provider.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Package conjur provides a Conjur provider for External Secrets.
  2. /*
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package conjur
  14. import (
  15. "context"
  16. "encoding/json"
  17. "fmt"
  18. "strings"
  19. "github.com/cyberark/conjur-api-go/conjurapi"
  20. "github.com/cyberark/conjur-api-go/conjurapi/authn"
  21. corev1 "k8s.io/api/core/v1"
  22. apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  23. "sigs.k8s.io/controller-runtime/pkg/client"
  24. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  25. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  26. "github.com/external-secrets/external-secrets/pkg/provider/conjur/util"
  27. "github.com/external-secrets/external-secrets/pkg/utils"
  28. )
  29. var (
  30. errConjurClient = "cannot setup new Conjur client: %w"
  31. errBadCertBundle = "caBundle failed to base64 decode: %w"
  32. errBadServiceUser = "could not get Auth.Apikey.UserRef: %w"
  33. errBadServiceAPIKey = "could not get Auth.Apikey.ApiKeyRef: %w"
  34. )
  35. // Provider is a provider for Conjur.
  36. type Provider struct {
  37. ConjurClient Client
  38. StoreKind string
  39. kube client.Client
  40. namespace string
  41. }
  42. // Client is an interface for the Conjur client.
  43. type Client interface {
  44. RetrieveSecret(secret string) (result []byte, err error)
  45. }
  46. // NewClient creates a new Conjur client.
  47. func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
  48. prov, err := util.GetConjurProvider(store)
  49. if err != nil {
  50. return nil, err
  51. }
  52. p.StoreKind = store.GetObjectKind().GroupVersionKind().Kind
  53. p.kube = kube
  54. p.namespace = namespace
  55. certBytes, decodeErr := utils.Decode(esv1beta1.ExternalSecretDecodeBase64, []byte(prov.CABundle))
  56. if decodeErr != nil {
  57. return nil, fmt.Errorf(errBadCertBundle, decodeErr)
  58. }
  59. cert := string(certBytes)
  60. config := conjurapi.Config{
  61. Account: prov.Auth.Apikey.Account,
  62. ApplianceURL: prov.URL,
  63. SSLCert: cert,
  64. }
  65. conjUser, secErr := p.secretKeyRef(ctx, prov.Auth.Apikey.UserRef)
  66. if secErr != nil {
  67. return nil, fmt.Errorf(errBadServiceUser, secErr)
  68. }
  69. conjAPIKey, secErr := p.secretKeyRef(ctx, prov.Auth.Apikey.APIKeyRef)
  70. if secErr != nil {
  71. return nil, fmt.Errorf(errBadServiceAPIKey, secErr)
  72. }
  73. conjur, err := conjurapi.NewClientFromKey(config,
  74. authn.LoginPair{
  75. Login: conjUser,
  76. APIKey: conjAPIKey,
  77. },
  78. )
  79. if err != nil {
  80. return nil, fmt.Errorf(errConjurClient, err)
  81. }
  82. p.ConjurClient = conjur
  83. return p, nil
  84. }
  85. // GetAllSecrets returns all secrets from the provider.
  86. // NOT IMPLEMENTED.
  87. func (p *Provider) GetAllSecrets(_ context.Context, _ esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  88. // TO be implemented
  89. return nil, fmt.Errorf("GetAllSecrets not implemented")
  90. }
  91. // GetSecret returns a single secret from the provider.
  92. func (p *Provider) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  93. secretValue, err := p.ConjurClient.RetrieveSecret(ref.Key)
  94. if err != nil {
  95. return nil, err
  96. }
  97. return secretValue, nil
  98. }
  99. // PushSecret will write a single secret into the provider.
  100. func (p *Provider) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
  101. // NOT IMPLEMENTED
  102. return nil
  103. }
  104. func (p *Provider) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRef) error {
  105. // NOT IMPLEMENTED
  106. return nil
  107. }
  108. // GetSecretMap returns multiple k/v pairs from the provider.
  109. func (p *Provider) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  110. // Gets a secret as normal, expecting secret value to be a json object
  111. data, err := p.GetSecret(ctx, ref)
  112. if err != nil {
  113. return nil, fmt.Errorf("error getting secret %s: %w", ref.Key, err)
  114. }
  115. // Maps the json data to a string:string map
  116. kv := make(map[string]string)
  117. err = json.Unmarshal(data, &kv)
  118. if err != nil {
  119. return nil, fmt.Errorf("unable to unmarshal secret %s: %w", ref.Key, err)
  120. }
  121. // Converts values in K:V pairs into bytes, while leaving keys as strings
  122. secretData := make(map[string][]byte)
  123. for k, v := range kv {
  124. secretData[k] = []byte(v)
  125. }
  126. return secretData, nil
  127. }
  128. // Close closes the provider.
  129. func (p *Provider) Close(_ context.Context) error {
  130. return nil
  131. }
  132. // Validate validates the provider.
  133. func (p *Provider) Validate() (esv1beta1.ValidationResult, error) {
  134. return esv1beta1.ValidationResultReady, nil
  135. }
  136. // ValidateStore validates the store.
  137. func (p *Provider) ValidateStore(store esv1beta1.GenericStore) error {
  138. prov, err := util.GetConjurProvider(store)
  139. if err != nil {
  140. return err
  141. }
  142. if prov.URL == "" {
  143. return fmt.Errorf("conjur URL cannot be empty")
  144. }
  145. if prov.Auth.Apikey != nil {
  146. if prov.Auth.Apikey.Account == "" {
  147. return fmt.Errorf("missing Auth.ApiKey.Account")
  148. }
  149. if prov.Auth.Apikey.UserRef == nil {
  150. return fmt.Errorf("missing Auth.Apikey.UserRef")
  151. }
  152. if prov.Auth.Apikey.APIKeyRef == nil {
  153. return fmt.Errorf("missing Auth.Apikey.ApiKeyRef")
  154. }
  155. if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.Apikey.UserRef); err != nil {
  156. return fmt.Errorf("invalid Auth.Apikey.UserRef: %w", err)
  157. }
  158. if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.Apikey.APIKeyRef); err != nil {
  159. return fmt.Errorf("invalid Auth.Apikey.ApiKeyRef: %w", err)
  160. }
  161. }
  162. // At least one auth must be configured
  163. if prov.Auth.Apikey == nil {
  164. return fmt.Errorf("missing Auth.* configuration")
  165. }
  166. return nil
  167. }
  168. // Capabilities returns the provider Capabilities (Read, Write, ReadWrite).
  169. func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
  170. return esv1beta1.SecretStoreReadOnly
  171. }
  172. func (p *Provider) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
  173. secret := &corev1.Secret{}
  174. ref := client.ObjectKey{
  175. Namespace: p.namespace,
  176. Name: secretRef.Name,
  177. }
  178. if (p.StoreKind == esv1beta1.ClusterSecretStoreKind) &&
  179. (secretRef.Namespace != nil) {
  180. ref.Namespace = *secretRef.Namespace
  181. }
  182. err := p.kube.Get(ctx, ref, secret)
  183. if err != nil {
  184. return "", err
  185. }
  186. keyBytes, ok := secret.Data[secretRef.Key]
  187. if !ok {
  188. return "", err
  189. }
  190. value := string(keyBytes)
  191. valueStr := strings.TrimSpace(value)
  192. return valueStr, nil
  193. }
  194. func init() {
  195. esv1beta1.Register(&Provider{}, &esv1beta1.SecretStoreProvider{
  196. Conjur: &esv1beta1.ConjurProvider{},
  197. })
  198. }