kubernetes_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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. "errors"
  16. "fmt"
  17. "reflect"
  18. "strings"
  19. "testing"
  20. authv1 "k8s.io/api/authorization/v1"
  21. corev1 "k8s.io/api/core/v1"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. fclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
  24. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  25. v1 "github.com/external-secrets/external-secrets/apis/meta/v1"
  26. )
  27. const (
  28. errTestFetchCredentialsSecret = "test could not fetch Credentials secret failed"
  29. errTestAuthValue = "test failed key didn't match expected value"
  30. errSomethingWentWrong = "Something went wrong"
  31. errExpectedErr = "wanted error got nil"
  32. )
  33. type fakeClient struct {
  34. secretMap map[string]corev1.Secret
  35. }
  36. func (fk fakeClient) Get(ctx context.Context, name string, opts metav1.GetOptions) (*corev1.Secret, error) {
  37. secret, ok := fk.secretMap[name]
  38. if !ok {
  39. return nil, errors.New(errSomethingWentWrong)
  40. }
  41. return &secret, nil
  42. }
  43. type fakeReviewClient struct {
  44. authReview *authv1.SelfSubjectAccessReview
  45. }
  46. func (fk fakeReviewClient) Create(ctx context.Context, selfSubjectAccessReview *authv1.SelfSubjectAccessReview, opts metav1.CreateOptions) (*authv1.SelfSubjectAccessReview, error) {
  47. if fk.authReview == nil {
  48. return nil, errors.New(errSomethingWentWrong)
  49. }
  50. return fk.authReview, nil
  51. }
  52. func TestKubernetesSecretManagerGetSecret(t *testing.T) {
  53. expected := make(map[string][]byte)
  54. value := "bar"
  55. expected["foo"] = []byte(value)
  56. mysecret := corev1.Secret{Data: expected}
  57. mysecretmap := make(map[string]corev1.Secret)
  58. mysecretmap["Key"] = mysecret
  59. fk := fakeClient{secretMap: mysecretmap}
  60. kp := ProviderKubernetes{Client: fk}
  61. ref := esv1beta1.ExternalSecretDataRemoteRef{Key: "Key", Property: "foo"}
  62. ctx := context.Background()
  63. output, _ := kp.GetSecret(ctx, ref)
  64. if string(output) != value {
  65. t.Error("missing match value of the secret")
  66. }
  67. ref = esv1beta1.ExternalSecretDataRemoteRef{Key: "Key2", Property: "foo"}
  68. _, err := kp.GetSecret(ctx, ref)
  69. if err.Error() != errSomethingWentWrong {
  70. t.Error("test failed")
  71. }
  72. ref = esv1beta1.ExternalSecretDataRemoteRef{Key: "Key", Property: "foo2"}
  73. _, err = kp.GetSecret(ctx, ref)
  74. expectedError := fmt.Sprintf("property %s does not exist in key %s", ref.Property, ref.Key)
  75. if err.Error() != expectedError {
  76. t.Error("test not existing property failed")
  77. }
  78. kp = ProviderKubernetes{Client: nil}
  79. _, err = kp.GetSecret(ctx, ref)
  80. if err.Error() != errUninitalizedKubernetesProvider {
  81. t.Error("test nil Client failed")
  82. }
  83. ref = esv1beta1.ExternalSecretDataRemoteRef{Key: "Key", Property: ""}
  84. _, err = kp.GetSecret(ctx, ref)
  85. if err.Error() != "property field not found on extrenal secrets" {
  86. t.Error("test nil Property failed")
  87. }
  88. }
  89. func TestKubernetesSecretManagerGetSecretMap(t *testing.T) {
  90. expected := make(map[string][]byte)
  91. value := "bar"
  92. expected["foo"] = []byte(value)
  93. expected["foo2"] = []byte(value)
  94. mysecret := corev1.Secret{Data: expected}
  95. mysecretmap := make(map[string]corev1.Secret)
  96. mysecretmap["Key"] = mysecret
  97. fk := fakeClient{secretMap: mysecretmap}
  98. kp := ProviderKubernetes{Client: fk}
  99. ref := esv1beta1.ExternalSecretDataRemoteRef{Key: "Key", Property: ""}
  100. ctx := context.Background()
  101. output, err := kp.GetSecretMap(ctx, ref)
  102. if err != nil {
  103. t.Error("test failed")
  104. }
  105. if !reflect.DeepEqual(output, expected) {
  106. t.Error("Objects are not equal")
  107. }
  108. }
  109. func TestKubernetesSecretManagerSetAuth(t *testing.T) {
  110. secretName := "good-name"
  111. CABundle := "CABundle"
  112. kp := esv1beta1.KubernetesProvider{Server: esv1beta1.KubernetesServer{}}
  113. fs := &corev1.Secret{
  114. ObjectMeta: metav1.ObjectMeta{Name: secretName},
  115. Data: make(map[string][]byte),
  116. }
  117. fs.Data["cert"] = []byte("secret-cert")
  118. fs.Data["ca"] = []byte("secret-ca")
  119. fs.Data["bearerToken"] = []byte("bearerToken")
  120. fs2 := &corev1.Secret{
  121. ObjectMeta: metav1.ObjectMeta{Name: "secret-for-the-key"},
  122. Data: make(map[string][]byte),
  123. }
  124. fs2.Data["key"] = []byte("secret-key")
  125. fk := fclient.NewClientBuilder().WithObjects(fs, fs2).Build()
  126. bc := BaseClient{fk, &kp, "", "", nil, nil, nil, nil}
  127. ctx := context.Background()
  128. err := bc.setAuth(ctx)
  129. if err.Error() != "no Certificate Authority provided" {
  130. fmt.Println(err.Error())
  131. t.Error("test no Certificate Authority provided failed")
  132. }
  133. kp.Server.CAProvider = &esv1beta1.CAProvider{
  134. Type: esv1beta1.CAProviderTypeConfigMap,
  135. Name: fs.ObjectMeta.Name,
  136. Namespace: &fs.ObjectMeta.Namespace,
  137. Key: "ca",
  138. }
  139. bc.setAuth(ctx)
  140. if string(bc.CA) != "secret-ca" {
  141. t.Error("failed to set CA provider")
  142. }
  143. kp.Server.CABundle = []byte(CABundle)
  144. err = bc.setAuth(ctx)
  145. if err.Error() != "no credentials provided" {
  146. fmt.Println(err.Error())
  147. t.Error("test kubernetes credentials not empty failed")
  148. }
  149. if string(bc.CA) != CABundle {
  150. t.Error("failed to set CA provider")
  151. }
  152. kp = esv1beta1.KubernetesProvider{
  153. Auth: esv1beta1.KubernetesAuth{
  154. Cert: &esv1beta1.CertAuth{
  155. ClientCert: v1.SecretKeySelector{
  156. Name: "fake-name",
  157. },
  158. },
  159. },
  160. }
  161. kp.Server.CABundle = []byte(CABundle)
  162. err = bc.setAuth(ctx)
  163. if err.Error() != "could not fetch Credentials secret: secrets \"fake-name\" not found" {
  164. fmt.Println(err.Error())
  165. t.Error(errTestFetchCredentialsSecret)
  166. }
  167. kp.Auth.Cert.ClientCert.Name = fs.ObjectMeta.Name
  168. err = bc.setAuth(ctx)
  169. if err.Error() != fmt.Errorf(errMissingCredentials, "cert").Error() {
  170. fmt.Println(err.Error())
  171. t.Error(errTestFetchCredentialsSecret)
  172. }
  173. kp.Auth.Cert.ClientCert.Key = "cert"
  174. kp.Auth.Cert.ClientKey.Name = "secret-for-the-key"
  175. err = bc.setAuth(ctx)
  176. if err.Error() != fmt.Errorf(errMissingCredentials, "key").Error() {
  177. fmt.Println(err.Error())
  178. t.Error(errTestFetchCredentialsSecret)
  179. }
  180. kp.Auth.Cert.ClientKey.Key = "key"
  181. bc.setAuth(ctx)
  182. kp.Auth.Token = &esv1beta1.TokenAuth{BearerToken: v1.SecretKeySelector{Name: secretName}}
  183. err = bc.setAuth(ctx)
  184. if err.Error() != fmt.Errorf(errMissingCredentials, "bearerToken").Error() {
  185. fmt.Println(err.Error())
  186. t.Error(errTestFetchCredentialsSecret)
  187. }
  188. kp.Auth.Token = &esv1beta1.TokenAuth{BearerToken: v1.SecretKeySelector{Name: secretName, Key: "bearerToken"}}
  189. err = bc.setAuth(ctx)
  190. if err != nil {
  191. fmt.Println(err.Error())
  192. t.Error(errTestFetchCredentialsSecret)
  193. }
  194. if string(bc.CA) != CABundle {
  195. t.Error(errTestAuthValue)
  196. }
  197. if string(bc.Certificate) != "secret-cert" {
  198. t.Error(errTestAuthValue)
  199. }
  200. if string(bc.Key) != "secret-key" {
  201. t.Errorf(errTestAuthValue)
  202. }
  203. if string(bc.BearerToken) != "bearerToken" {
  204. t.Error(errTestAuthValue)
  205. }
  206. }
  207. func TestValidateStore(t *testing.T) {
  208. p := ProviderKubernetes{}
  209. store := &esv1beta1.SecretStore{
  210. Spec: esv1beta1.SecretStoreSpec{
  211. Provider: &esv1beta1.SecretStoreProvider{
  212. Kubernetes: &esv1beta1.KubernetesProvider{},
  213. },
  214. },
  215. }
  216. secretName := "my-secret-name"
  217. secretKey := "my-secert-key"
  218. err := p.ValidateStore(store)
  219. if err == nil {
  220. t.Errorf(errExpectedErr)
  221. } else if err.Error() != "a CABundle or CAProvider is required" {
  222. t.Errorf("service CA test failed, got %v", err.Error())
  223. }
  224. bundle := []byte("ca-bundle")
  225. store.Spec.Provider.Kubernetes.Server.CABundle = bundle
  226. err = p.ValidateStore(store)
  227. if err == nil {
  228. t.Errorf(errExpectedErr)
  229. } else if err.Error() != "an Auth type must be specified" {
  230. t.Errorf("empty Auth test failed")
  231. }
  232. store.Spec.Provider.Kubernetes.Auth = esv1beta1.KubernetesAuth{Cert: &esv1beta1.CertAuth{}}
  233. err = p.ValidateStore(store)
  234. if err == nil {
  235. t.Errorf(errExpectedErr)
  236. } else if err.Error() != "ClientCert.Name cannot be empty" {
  237. t.Errorf("KeySelector test failed: expected clientCert name is required, got %v", err)
  238. }
  239. store.Spec.Provider.Kubernetes.Auth.Cert.ClientCert.Name = secretName
  240. err = p.ValidateStore(store)
  241. if err == nil {
  242. t.Errorf(errExpectedErr)
  243. } else if err.Error() != "ClientCert.Key cannot be empty" {
  244. t.Errorf("KeySelector test failed: expected clientCert Key is required, got %v", err)
  245. }
  246. store.Spec.Provider.Kubernetes.Auth.Cert.ClientCert.Key = secretKey
  247. ns := "ns-one"
  248. store.Spec.Provider.Kubernetes.Auth.Cert.ClientCert.Namespace = &ns
  249. err = p.ValidateStore(store)
  250. if err == nil {
  251. t.Errorf(errExpectedErr)
  252. } else if err.Error() != "namespace not allowed with namespaced SecretStore" {
  253. t.Errorf("KeySelector test failed: expected namespace not allowed, got %v", err)
  254. }
  255. store.Spec.Provider.Kubernetes.Auth = esv1beta1.KubernetesAuth{Token: &esv1beta1.TokenAuth{}}
  256. err = p.ValidateStore(store)
  257. if err == nil {
  258. t.Errorf(errExpectedErr)
  259. } else if err.Error() != "BearerToken.Name cannot be empty" {
  260. t.Errorf("KeySelector test failed: expected bearer token name is required, got %v", err)
  261. }
  262. store.Spec.Provider.Kubernetes.Auth.Token.BearerToken.Name = secretName
  263. err = p.ValidateStore(store)
  264. if err == nil {
  265. t.Errorf(errExpectedErr)
  266. } else if err.Error() != "BearerToken.Key cannot be empty" {
  267. t.Errorf("KeySelector test failed: expected bearer token key is required, got %v", err)
  268. }
  269. store.Spec.Provider.Kubernetes.Auth.Token.BearerToken.Key = secretKey
  270. store.Spec.Provider.Kubernetes.Auth.Token.BearerToken.Namespace = &ns
  271. err = p.ValidateStore(store)
  272. if err == nil {
  273. t.Errorf(errExpectedErr)
  274. } else if err.Error() != "namespace not allowed with namespaced SecretStore" {
  275. t.Errorf("KeySelector test failed: expected namespace not allowed, got %v", err)
  276. }
  277. store.Spec.Provider.Kubernetes.Auth = esv1beta1.KubernetesAuth{
  278. Cert: &esv1beta1.CertAuth{
  279. ClientCert: v1.SecretKeySelector{
  280. Name: secretName,
  281. Key: secretKey,
  282. },
  283. },
  284. Token: &esv1beta1.TokenAuth{
  285. BearerToken: v1.SecretKeySelector{
  286. Name: secretName,
  287. Key: secretKey,
  288. },
  289. },
  290. }
  291. err = p.ValidateStore(store)
  292. if err == nil {
  293. t.Errorf(errExpectedErr)
  294. } else if err.Error() != "only one authentication method is allowed" {
  295. t.Errorf("KeySelector test failed: expected only one auth method allowed, got %v", err)
  296. }
  297. }
  298. func ErrorContains(out error, want string) bool {
  299. if out == nil {
  300. return want == ""
  301. }
  302. if want == "" {
  303. return false
  304. }
  305. return strings.Contains(out.Error(), want)
  306. }
  307. func TestValidate(t *testing.T) {
  308. authReview := authv1.SelfSubjectAccessReview{
  309. Status: authv1.SubjectAccessReviewStatus{
  310. Allowed: true,
  311. },
  312. }
  313. fakeClient := fakeReviewClient{authReview: &authReview}
  314. k := ProviderKubernetes{ReviewClient: fakeClient}
  315. validationResult, err := k.Validate()
  316. if err != nil {
  317. t.Errorf("Test Failed! %v", err)
  318. }
  319. if validationResult != esv1beta1.ValidationResultReady {
  320. t.Errorf("Test Failed! Wanted could not indicate validationResult is %s, got: %s", esv1beta1.ValidationResultReady, validationResult)
  321. }
  322. authReview = authv1.SelfSubjectAccessReview{
  323. Status: authv1.SubjectAccessReviewStatus{
  324. Allowed: false,
  325. },
  326. }
  327. fakeClient = fakeReviewClient{authReview: &authReview}
  328. k = ProviderKubernetes{ReviewClient: fakeClient}
  329. validationResult, err = k.Validate()
  330. if err.Error() != "client is not allowed to get secrets" {
  331. t.Errorf("Test Failed! Wanted client is not allowed to get secrets got: %v", err)
  332. }
  333. if validationResult != esv1beta1.ValidationResultError {
  334. t.Errorf("Test Failed! Wanted could not indicate validationResult is %s, got: %s", esv1beta1.ValidationResultError, validationResult)
  335. }
  336. fakeClient = fakeReviewClient{}
  337. k = ProviderKubernetes{ReviewClient: fakeClient}
  338. validationResult, err = k.Validate()
  339. if err.Error() != "could not verify if client is valid: Something went wrong" {
  340. t.Errorf("Test Failed! Wanted could not verify if client is valid: Something went wrong got: %v", err)
  341. }
  342. if validationResult != esv1beta1.ValidationResultUnknown {
  343. t.Errorf("Test Failed! Wanted could not indicate validationResult is %s, got: %s", esv1beta1.ValidationResultUnknown, validationResult)
  344. }
  345. }