kubernetes.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 kubernetes
  13. import (
  14. "context"
  15. "encoding/json"
  16. "fmt"
  17. authv1 "k8s.io/api/authorization/v1"
  18. corev1 "k8s.io/api/core/v1"
  19. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  20. labels "k8s.io/apimachinery/pkg/labels"
  21. "k8s.io/client-go/kubernetes"
  22. "k8s.io/client-go/rest"
  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. "github.com/external-secrets/external-secrets/pkg/utils"
  27. )
  28. // https://github.com/external-secrets/external-secrets/issues/644
  29. var _ esv1beta1.SecretsClient = &ProviderKubernetes{}
  30. var _ esv1beta1.Provider = &ProviderKubernetes{}
  31. type KClient interface {
  32. Get(ctx context.Context, name string, opts metav1.GetOptions) (*corev1.Secret, error)
  33. List(ctx context.Context, opts metav1.ListOptions) (*corev1.SecretList, error)
  34. }
  35. type RClient interface {
  36. Create(ctx context.Context, selfSubjectRulesReview *authv1.SelfSubjectRulesReview, opts metav1.CreateOptions) (*authv1.SelfSubjectRulesReview, error)
  37. }
  38. // ProviderKubernetes is a provider for Kubernetes.
  39. type ProviderKubernetes struct {
  40. Client KClient
  41. ReviewClient RClient
  42. Namespace string
  43. store *esv1beta1.KubernetesProvider
  44. storeKind string
  45. }
  46. var _ esv1beta1.SecretsClient = &ProviderKubernetes{}
  47. type BaseClient struct {
  48. kube kclient.Client
  49. store *esv1beta1.KubernetesProvider
  50. storeKind string
  51. namespace string
  52. Certificate []byte
  53. Key []byte
  54. CA []byte
  55. BearerToken []byte
  56. }
  57. func init() {
  58. esv1beta1.Register(&ProviderKubernetes{}, &esv1beta1.SecretStoreProvider{
  59. Kubernetes: &esv1beta1.KubernetesProvider{},
  60. })
  61. }
  62. // NewClient constructs a Kubernetes Provider.
  63. func (p *ProviderKubernetes) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  64. storeSpec := store.GetSpec()
  65. if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.Kubernetes == nil {
  66. return nil, fmt.Errorf("no store type or wrong store type")
  67. }
  68. storeSpecKubernetes := storeSpec.Provider.Kubernetes
  69. client := BaseClient{
  70. kube: kube,
  71. store: storeSpecKubernetes,
  72. namespace: namespace,
  73. storeKind: store.GetObjectKind().GroupVersionKind().Kind,
  74. }
  75. p.Namespace = client.store.RemoteNamespace
  76. p.store = storeSpecKubernetes
  77. p.storeKind = store.GetObjectKind().GroupVersionKind().Kind
  78. // allow SecretStore controller validation to pass
  79. // when using referent namespace.
  80. if client.storeKind == esv1beta1.ClusterSecretStoreKind && client.namespace == "" && isReferentSpec(storeSpecKubernetes) {
  81. return p, nil
  82. }
  83. if err := client.setAuth(ctx); err != nil {
  84. return nil, err
  85. }
  86. config := &rest.Config{
  87. Host: client.store.Server.URL,
  88. BearerToken: string(client.BearerToken),
  89. TLSClientConfig: rest.TLSClientConfig{
  90. Insecure: false,
  91. CertData: client.Certificate,
  92. KeyData: client.Key,
  93. CAData: client.CA,
  94. },
  95. }
  96. kubeClientSet, err := kubernetes.NewForConfig(config)
  97. if err != nil {
  98. return nil, fmt.Errorf("error configuring clientset: %w", err)
  99. }
  100. p.Client = kubeClientSet.CoreV1().Secrets(client.store.RemoteNamespace)
  101. p.ReviewClient = kubeClientSet.AuthorizationV1().SelfSubjectRulesReviews()
  102. return p, nil
  103. }
  104. func isReferentSpec(prov *esv1beta1.KubernetesProvider) bool {
  105. if prov.Auth.Cert != nil {
  106. if prov.Auth.Cert.ClientCert.Namespace == nil {
  107. return true
  108. }
  109. if prov.Auth.Cert.ClientKey.Namespace == nil {
  110. return true
  111. }
  112. }
  113. if prov.Auth.ServiceAccount != nil {
  114. if prov.Auth.ServiceAccount.Namespace == nil {
  115. return true
  116. }
  117. }
  118. if prov.Auth.Token != nil {
  119. if prov.Auth.Token.BearerToken.Namespace == nil {
  120. return true
  121. }
  122. }
  123. return false
  124. }
  125. func (p *ProviderKubernetes) Close(ctx context.Context) error {
  126. return nil
  127. }
  128. func (p *ProviderKubernetes) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  129. secretMap, err := p.GetSecretMap(ctx, ref)
  130. if err != nil {
  131. return nil, err
  132. }
  133. if ref.Property != "" {
  134. val, ok := secretMap[ref.Property]
  135. if !ok {
  136. return nil, fmt.Errorf("property %s does not exist in key %s", ref.Property, ref.Key)
  137. }
  138. return val, nil
  139. }
  140. strMap := make(map[string]string)
  141. for k, v := range secretMap {
  142. strMap[k] = string(v)
  143. }
  144. jsonStr, err := json.Marshal(strMap)
  145. if err != nil {
  146. return nil, fmt.Errorf("unabled to marshal json: %w", err)
  147. }
  148. return jsonStr, nil
  149. }
  150. func (p *ProviderKubernetes) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  151. secret, err := p.Client.Get(ctx, ref.Key, metav1.GetOptions{})
  152. if err != nil {
  153. return nil, err
  154. }
  155. return secret.Data, nil
  156. }
  157. func (p *ProviderKubernetes) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  158. if ref.Tags != nil {
  159. return p.findByTags(ctx, ref)
  160. }
  161. if ref.Name != nil {
  162. return p.findByName(ctx, ref)
  163. }
  164. return nil, fmt.Errorf("unexpected find operator: %#v", ref)
  165. }
  166. func (p *ProviderKubernetes) findByTags(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  167. // empty/nil tags = everything
  168. sel, err := labels.ValidatedSelectorFromSet(ref.Tags)
  169. if err != nil {
  170. return nil, fmt.Errorf("unable to validate selector tags: %w", err)
  171. }
  172. secrets, err := p.Client.List(ctx, metav1.ListOptions{LabelSelector: sel.String()})
  173. if err != nil {
  174. return nil, fmt.Errorf("unable to list secrets: %w", err)
  175. }
  176. data := make(map[string][]byte)
  177. for _, secret := range secrets.Items {
  178. jsonStr, err := json.Marshal(convertMap(secret.Data))
  179. if err != nil {
  180. return nil, err
  181. }
  182. data[secret.Name] = jsonStr
  183. }
  184. return utils.ConvertKeys(ref.ConversionStrategy, data)
  185. }
  186. func (p *ProviderKubernetes) findByName(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  187. secrets, err := p.Client.List(ctx, metav1.ListOptions{})
  188. if err != nil {
  189. return nil, fmt.Errorf("unable to list secrets: %w", err)
  190. }
  191. matcher, err := find.New(*ref.Name)
  192. if err != nil {
  193. return nil, err
  194. }
  195. data := make(map[string][]byte)
  196. for _, secret := range secrets.Items {
  197. if !matcher.MatchName(secret.Name) {
  198. continue
  199. }
  200. jsonStr, err := json.Marshal(convertMap(secret.Data))
  201. if err != nil {
  202. return nil, err
  203. }
  204. data[secret.Name] = jsonStr
  205. }
  206. return utils.ConvertKeys(ref.ConversionStrategy, data)
  207. }
  208. func convertMap(in map[string][]byte) map[string]string {
  209. out := make(map[string]string)
  210. for k, v := range in {
  211. out[k] = string(v)
  212. }
  213. return out
  214. }