auth_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  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. "testing"
  16. "github.com/stretchr/testify/assert"
  17. corev1 "k8s.io/api/core/v1"
  18. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  19. typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  20. "k8s.io/client-go/rest"
  21. pointer "k8s.io/utils/ptr"
  22. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  23. fclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
  24. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  25. v1 "github.com/external-secrets/external-secrets/apis/meta/v1"
  26. utilfake "github.com/external-secrets/external-secrets/pkg/provider/util/fake"
  27. )
  28. const (
  29. caCert = `-----BEGIN CERTIFICATE-----
  30. MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw
  31. CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp
  32. Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2
  33. MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
  34. bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG
  35. ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS
  36. 7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp
  37. 0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS
  38. B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49
  39. BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ
  40. LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4
  41. DXZDjC5Ty3zfDBeWUA==
  42. -----END CERTIFICATE-----
  43. `
  44. authTestKubeConfig = `apiVersion: v1
  45. clusters:
  46. - cluster:
  47. server: https://api.my-domain.tld
  48. certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNHVENDQVorZ0F3SUJBZ0lRQ2VDVFphejMyY2k1UGh3TEJDb3U4ekFLQmdncWhrak9QUVFEQXpCT01Rc3cKQ1FZRFZRUUdFd0pWVXpFWE1CVUdBMVVFQ2hNT1JHbG5hVU5sY25Rc0lFbHVZeTR4SmpBa0JnTlZCQU1USFVScApaMmxEWlhKMElGUk1VeUJGUTBNZ1VETTROQ0JTYjI5MElFYzFNQjRYRFRJeE1ERXhOVEF3TURBd01Gb1hEVFEyCk1ERXhOREl6TlRrMU9Wb3dUakVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFvVERrUnBaMmxEWlhKMExDQkoKYm1NdU1TWXdKQVlEVlFRREV4MUVhV2RwUTJWeWRDQlVURk1nUlVORElGQXpPRFFnVW05dmRDQkhOVEIyTUJBRwpCeXFHU000OUFnRUdCU3VCQkFBaUEySUFCTUZFb2M4UmwxQ2EzaU9DTlFmTjBNc1luZEx4ZjNjMVR6dmRsSEpTCjdjSTcrT3o2ZTJ0WUlPeVpyc244YUxOMXVkc0o3TWdUOVU3R0NoMW1NRXk3SDBjS1BHRVFRaWw4cFFnTzRDTHAKMHpWb3pwdGpuNFMxbVUxWW9JNzFWT2VWeWFOQ01FQXdIUVlEVlIwT0JCWUVGTUZSUlZCWnF6N25MRnI2SUNJUwpCNENJZkJGcU1BNEdBMVVkRHdFQi93UUVBd0lCaGpBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUFvR0NDcUdTTTQ5CkJBTURBMmdBTUdVQ01RQ0phbzFINSt6OGJsVUQyV2RzSms2RHh2M0oreXNUdkxkNmpMUmwwbWxwWXhOak95WlEKTGdHaGVRYVJuVWkvd3I0Q01FZkRGWHV4b0pHWlNaT29QSHpvUmdhTExQSXhBSlNkWXNpSnZSbUVGT21sK3dHNApEWFpEakM1VHkzemZEQmVXVUE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
  49. name: mycluster
  50. contexts:
  51. - context:
  52. cluster: mycluster
  53. user: myuser
  54. name: mycontext
  55. current-context: mycontext
  56. kind: Config
  57. preferences: {}
  58. users:
  59. - name: myuser
  60. user:
  61. token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE3MTkzOTY4OTksImV4cCI6MTc1MDkzMjg4NywiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjpbIk1hbmFnZXIiLCJQcm9qZWN0IEFkbWluaXN0cmF0b3IiXX0.xXrfIl0akhfjWU_BDl7Ad54SXje0YlJdnugzwh96VmM
  62. `
  63. serverURL = "https://my.test.tld"
  64. )
  65. func TestSetAuth(t *testing.T) {
  66. type fields struct {
  67. kube kclient.Client
  68. kubeclientset typedcorev1.CoreV1Interface
  69. store *esv1.KubernetesProvider
  70. namespace string
  71. storeKind string
  72. }
  73. type want = rest.Config
  74. tests := []struct {
  75. name string
  76. fields fields
  77. want *want
  78. wantErr bool
  79. }{
  80. {
  81. name: "should return err if no ca provided",
  82. fields: fields{
  83. store: &esv1.KubernetesProvider{
  84. Server: esv1.KubernetesServer{},
  85. },
  86. },
  87. want: nil,
  88. wantErr: true,
  89. },
  90. {
  91. name: "should return err if no auth provided",
  92. fields: fields{
  93. store: &esv1.KubernetesProvider{
  94. Server: esv1.KubernetesServer{
  95. CABundle: []byte(caCert),
  96. },
  97. },
  98. },
  99. want: nil,
  100. wantErr: true,
  101. },
  102. {
  103. name: "should fetch ca from Secret",
  104. fields: fields{
  105. namespace: "default",
  106. kube: fclient.NewClientBuilder().WithObjects(&corev1.Secret{
  107. ObjectMeta: metav1.ObjectMeta{
  108. Name: "foobar",
  109. Namespace: "default",
  110. },
  111. Data: map[string][]byte{
  112. "cert": []byte(caCert),
  113. "token": []byte("mytoken"),
  114. },
  115. }).Build(),
  116. store: &esv1.KubernetesProvider{
  117. Server: esv1.KubernetesServer{
  118. URL: serverURL,
  119. CAProvider: &esv1.CAProvider{
  120. Type: esv1.CAProviderTypeSecret,
  121. Name: "foobar",
  122. Key: "cert",
  123. },
  124. },
  125. Auth: &esv1.KubernetesAuth{
  126. Token: &esv1.TokenAuth{
  127. BearerToken: v1.SecretKeySelector{
  128. Name: "foobar",
  129. Namespace: pointer.To("shouldnotberelevant"),
  130. Key: "token",
  131. },
  132. },
  133. },
  134. },
  135. },
  136. want: &want{
  137. Host: serverURL,
  138. BearerToken: "mytoken",
  139. TLSClientConfig: rest.TLSClientConfig{
  140. CAData: []byte(caCert),
  141. },
  142. },
  143. wantErr: false,
  144. },
  145. {
  146. name: "should fetch ca from ConfigMap",
  147. fields: fields{
  148. namespace: "default",
  149. kube: fclient.NewClientBuilder().WithObjects(&corev1.Secret{
  150. ObjectMeta: metav1.ObjectMeta{
  151. Name: "foobar",
  152. Namespace: "default",
  153. },
  154. Data: map[string][]byte{
  155. "token": []byte("mytoken"),
  156. },
  157. }, &corev1.ConfigMap{
  158. ObjectMeta: metav1.ObjectMeta{
  159. Name: "foobar",
  160. Namespace: "default",
  161. },
  162. Data: map[string]string{
  163. "cert": "1234",
  164. },
  165. }).Build(),
  166. store: &esv1.KubernetesProvider{
  167. Server: esv1.KubernetesServer{
  168. URL: serverURL,
  169. CAProvider: &esv1.CAProvider{
  170. Type: esv1.CAProviderTypeConfigMap,
  171. Name: "foobar",
  172. Key: "cert",
  173. },
  174. },
  175. Auth: &esv1.KubernetesAuth{
  176. Token: &esv1.TokenAuth{
  177. BearerToken: v1.SecretKeySelector{
  178. Name: "foobar",
  179. Namespace: pointer.To("shouldnotberelevant"),
  180. Key: "token",
  181. },
  182. },
  183. },
  184. },
  185. },
  186. want: &want{
  187. Host: serverURL,
  188. BearerToken: "mytoken",
  189. TLSClientConfig: rest.TLSClientConfig{
  190. CAData: []byte("1234"),
  191. },
  192. },
  193. wantErr: false,
  194. },
  195. {
  196. name: "should set token from secret",
  197. fields: fields{
  198. namespace: "default",
  199. kube: fclient.NewClientBuilder().WithObjects(&corev1.Secret{
  200. ObjectMeta: metav1.ObjectMeta{
  201. Name: "foobar",
  202. Namespace: "default",
  203. },
  204. Data: map[string][]byte{
  205. "token": []byte("mytoken"),
  206. },
  207. }).Build(),
  208. store: &esv1.KubernetesProvider{
  209. Server: esv1.KubernetesServer{
  210. URL: serverURL,
  211. CABundle: []byte(caCert),
  212. },
  213. Auth: &esv1.KubernetesAuth{
  214. Token: &esv1.TokenAuth{
  215. BearerToken: v1.SecretKeySelector{
  216. Name: "foobar",
  217. Namespace: pointer.To("shouldnotberelevant"),
  218. Key: "token",
  219. },
  220. },
  221. },
  222. },
  223. },
  224. want: &want{
  225. Host: serverURL,
  226. BearerToken: "mytoken",
  227. TLSClientConfig: rest.TLSClientConfig{
  228. CAData: []byte(caCert),
  229. },
  230. },
  231. wantErr: false,
  232. },
  233. {
  234. name: "should set client cert from secret",
  235. fields: fields{
  236. namespace: "default",
  237. kube: fclient.NewClientBuilder().WithObjects(&corev1.Secret{
  238. ObjectMeta: metav1.ObjectMeta{
  239. Name: "mycert",
  240. Namespace: "default",
  241. },
  242. Data: map[string][]byte{
  243. "cert": []byte("my-cert"),
  244. "key": []byte("my-key"),
  245. },
  246. }).Build(),
  247. store: &esv1.KubernetesProvider{
  248. Server: esv1.KubernetesServer{
  249. URL: serverURL,
  250. CABundle: []byte(caCert),
  251. },
  252. Auth: &esv1.KubernetesAuth{
  253. Cert: &esv1.CertAuth{
  254. ClientCert: v1.SecretKeySelector{
  255. Name: "mycert",
  256. Key: "cert",
  257. },
  258. ClientKey: v1.SecretKeySelector{
  259. Name: "mycert",
  260. Key: "key",
  261. },
  262. },
  263. },
  264. },
  265. },
  266. want: &want{
  267. Host: serverURL,
  268. TLSClientConfig: rest.TLSClientConfig{
  269. CAData: []byte(caCert),
  270. CertData: []byte("my-cert"),
  271. KeyData: []byte("my-key"),
  272. },
  273. },
  274. wantErr: false,
  275. },
  276. {
  277. name: "should set token from service account",
  278. fields: fields{
  279. namespace: "default",
  280. kube: fclient.NewClientBuilder().WithObjects(&corev1.ServiceAccount{
  281. ObjectMeta: metav1.ObjectMeta{
  282. Name: "my-sa",
  283. Namespace: "default",
  284. },
  285. }).Build(),
  286. kubeclientset: utilfake.NewCreateTokenMock().WithToken("my-sa-token"),
  287. store: &esv1.KubernetesProvider{
  288. Server: esv1.KubernetesServer{
  289. URL: serverURL,
  290. CABundle: []byte(caCert),
  291. },
  292. Auth: &esv1.KubernetesAuth{
  293. ServiceAccount: &v1.ServiceAccountSelector{
  294. Name: "my-sa",
  295. Namespace: pointer.To("shouldnotberelevant"),
  296. },
  297. },
  298. },
  299. },
  300. want: &want{
  301. Host: serverURL,
  302. BearerToken: "my-sa-token",
  303. TLSClientConfig: rest.TLSClientConfig{
  304. CAData: []byte(caCert),
  305. },
  306. },
  307. wantErr: false,
  308. },
  309. {
  310. name: "should fail with missing URL",
  311. fields: fields{
  312. namespace: "default",
  313. kube: fclient.NewClientBuilder().WithObjects(&corev1.ServiceAccount{
  314. ObjectMeta: metav1.ObjectMeta{
  315. Name: "my-sa",
  316. Namespace: "default",
  317. },
  318. }).Build(),
  319. kubeclientset: utilfake.NewCreateTokenMock().WithToken("my-sa-token"),
  320. store: &esv1.KubernetesProvider{
  321. Server: esv1.KubernetesServer{
  322. CABundle: []byte(caCert),
  323. },
  324. Auth: &esv1.KubernetesAuth{
  325. ServiceAccount: &v1.ServiceAccountSelector{
  326. Name: "my-sa",
  327. Namespace: pointer.To("shouldnotberelevant"),
  328. },
  329. },
  330. },
  331. },
  332. want: nil,
  333. wantErr: true,
  334. },
  335. {
  336. name: "should read config from secret",
  337. fields: fields{
  338. namespace: "default",
  339. kube: fclient.NewClientBuilder().WithObjects(&corev1.Secret{
  340. ObjectMeta: metav1.ObjectMeta{
  341. Name: "foobar",
  342. Namespace: "default",
  343. },
  344. Data: map[string][]byte{
  345. "config": []byte(authTestKubeConfig),
  346. },
  347. }).Build(),
  348. store: &esv1.KubernetesProvider{
  349. AuthRef: &v1.SecretKeySelector{
  350. Name: "foobar",
  351. Namespace: pointer.To("default"),
  352. Key: "config",
  353. },
  354. },
  355. },
  356. want: &want{
  357. Host: "https://api.my-domain.tld",
  358. BearerToken: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE3MTkzOTY4OTksImV4cCI6MTc1MDkzMjg4NywiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjpbIk1hbmFnZXIiLCJQcm9qZWN0IEFkbWluaXN0cmF0b3IiXX0.xXrfIl0akhfjWU_BDl7Ad54SXje0YlJdnugzwh96VmM",
  359. TLSClientConfig: rest.TLSClientConfig{
  360. CAData: []byte(caCert),
  361. },
  362. },
  363. wantErr: false,
  364. },
  365. }
  366. for _, tt := range tests {
  367. t.Run(tt.name, func(t *testing.T) {
  368. k := &Client{
  369. ctrlClientset: tt.fields.kubeclientset,
  370. ctrlClient: tt.fields.kube,
  371. store: tt.fields.store,
  372. namespace: tt.fields.namespace,
  373. storeKind: tt.fields.storeKind,
  374. }
  375. cfg, err := k.getAuth(context.Background())
  376. if (err != nil) != tt.wantErr {
  377. t.Errorf("BaseClient.setAuth() error = %v, wantErr %v", err, tt.wantErr)
  378. }
  379. assert.Equal(t, tt.want, cfg)
  380. })
  381. }
  382. }