certificatemanager_test.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  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 certificatemanager
  13. import (
  14. "context"
  15. "encoding/json"
  16. "strings"
  17. "testing"
  18. "time"
  19. "github.com/google/uuid"
  20. tassert "github.com/stretchr/testify/assert"
  21. "github.com/yandex-cloud/go-genproto/yandex/cloud/certificatemanager/v1"
  22. "github.com/yandex-cloud/go-sdk/iamkey"
  23. corev1 "k8s.io/api/core/v1"
  24. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  25. ctrl "sigs.k8s.io/controller-runtime"
  26. k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
  27. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  28. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  29. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  30. "github.com/external-secrets/external-secrets/pkg/provider/yandex/certificatemanager/client"
  31. "github.com/external-secrets/external-secrets/pkg/provider/yandex/common"
  32. "github.com/external-secrets/external-secrets/pkg/provider/yandex/common/clock"
  33. )
  34. const (
  35. errMissingKey = "invalid Yandex Certificate Manager SecretStore resource: missing AuthorizedKey Name"
  36. errSecretPayloadPermissionDenied = "unable to request certificate content to get secret: permission denied"
  37. errSecretPayloadNotFound = "unable to request certificate content to get secret: certificate not found"
  38. )
  39. func TestNewClient(t *testing.T) {
  40. ctx := context.Background()
  41. const namespace = "namespace"
  42. store := &esv1beta1.SecretStore{
  43. ObjectMeta: metav1.ObjectMeta{
  44. Namespace: namespace,
  45. },
  46. Spec: esv1beta1.SecretStoreSpec{
  47. Provider: &esv1beta1.SecretStoreProvider{
  48. YandexCertificateManager: &esv1beta1.YandexCertificateManagerProvider{},
  49. },
  50. },
  51. }
  52. provider, err := esv1beta1.GetProvider(store)
  53. tassert.Nil(t, err)
  54. k8sClient := clientfake.NewClientBuilder().Build()
  55. secretClient, err := provider.NewClient(context.Background(), store, k8sClient, namespace)
  56. tassert.EqualError(t, err, errMissingKey)
  57. tassert.Nil(t, secretClient)
  58. store.Spec.Provider.YandexCertificateManager.Auth = esv1beta1.YandexCertificateManagerAuth{}
  59. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  60. tassert.EqualError(t, err, errMissingKey)
  61. tassert.Nil(t, secretClient)
  62. store.Spec.Provider.YandexCertificateManager.Auth.AuthorizedKey = esmeta.SecretKeySelector{}
  63. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  64. tassert.EqualError(t, err, errMissingKey)
  65. tassert.Nil(t, secretClient)
  66. const authorizedKeySecretName = "authorizedKeySecretName"
  67. const authorizedKeySecretKey = "authorizedKeySecretKey"
  68. store.Spec.Provider.YandexCertificateManager.Auth.AuthorizedKey.Name = authorizedKeySecretName
  69. store.Spec.Provider.YandexCertificateManager.Auth.AuthorizedKey.Key = authorizedKeySecretKey
  70. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  71. tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\": secrets \"authorizedKeySecretName\" not found")
  72. tassert.Nil(t, secretClient)
  73. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
  74. tassert.Nil(t, err)
  75. const caCertificateSecretName = "caCertificateSecretName"
  76. const caCertificateSecretKey = "caCertificateSecretKey"
  77. store.Spec.Provider.YandexCertificateManager.CAProvider = &esv1beta1.YandexCertificateManagerCAProvider{
  78. Certificate: esmeta.SecretKeySelector{
  79. Key: caCertificateSecretKey,
  80. Name: caCertificateSecretName,
  81. },
  82. }
  83. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  84. tassert.EqualError(t, err, "cannot get Kubernetes secret \"caCertificateSecretName\": secrets \"caCertificateSecretName\" not found")
  85. tassert.Nil(t, secretClient)
  86. err = createK8sSecret(ctx, t, k8sClient, namespace, caCertificateSecretName, caCertificateSecretKey, []byte("it-is-not-a-certificate"))
  87. tassert.Nil(t, err)
  88. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  89. tassert.EqualError(t, err, "failed to create Yandex.Cloud client: unable to read trusted CA certificates")
  90. tassert.Nil(t, secretClient)
  91. }
  92. func TestGetSecretWithoutProperty(t *testing.T) {
  93. ctx := context.Background()
  94. namespace := uuid.NewString()
  95. authorizedKey := newFakeAuthorizedKey()
  96. fakeClock := clock.NewFakeClock()
  97. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  98. certificate1 := uuid.NewString()
  99. certificate2 := uuid.NewString()
  100. privateKey := uuid.NewString()
  101. certificateID, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKey, &certificatemanager.GetCertificateContentResponse{
  102. CertificateChain: []string{certificate1, certificate2},
  103. PrivateKey: privateKey,
  104. })
  105. k8sClient := clientfake.NewClientBuilder().Build()
  106. const authorizedKeySecretName = "authorizedKeySecretName"
  107. const authorizedKeySecretKey = "authorizedKeySecretKey"
  108. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  109. tassert.Nil(t, err)
  110. store := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  111. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  112. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  113. tassert.Nil(t, err)
  114. data, err := secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID})
  115. tassert.Nil(t, err)
  116. tassert.Equal(
  117. t,
  118. strings.TrimSpace(strings.Join([]string{certificate1, certificate2, privateKey}, "\n")),
  119. strings.TrimSpace(string(data)),
  120. )
  121. }
  122. func TestGetSecretWithProperty(t *testing.T) {
  123. ctx := context.Background()
  124. namespace := uuid.NewString()
  125. authorizedKey := newFakeAuthorizedKey()
  126. fakeClock := clock.NewFakeClock()
  127. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  128. certificate1 := uuid.NewString()
  129. certificate2 := uuid.NewString()
  130. privateKey := uuid.NewString()
  131. certificateID, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKey, &certificatemanager.GetCertificateContentResponse{
  132. CertificateChain: []string{certificate1, certificate2},
  133. PrivateKey: privateKey,
  134. })
  135. k8sClient := clientfake.NewClientBuilder().Build()
  136. const authorizedKeySecretName = "authorizedKeySecretName"
  137. const authorizedKeySecretKey = "authorizedKeySecretKey"
  138. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  139. tassert.Nil(t, err)
  140. store := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  141. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  142. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  143. tassert.Nil(t, err)
  144. chainData, err := secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Property: chainProperty})
  145. tassert.Nil(t, err)
  146. tassert.Equal(
  147. t,
  148. strings.TrimSpace(certificate1+"\n"+certificate2),
  149. strings.TrimSpace(string(chainData)),
  150. )
  151. privateKeyData, err := secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Property: privateKeyProperty})
  152. tassert.Nil(t, err)
  153. tassert.Equal(
  154. t,
  155. strings.TrimSpace(privateKey),
  156. strings.TrimSpace(string(privateKeyData)),
  157. )
  158. chainAndPrivateKeyData, err := secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Property: chainAndPrivateKeyProperty})
  159. tassert.Nil(t, err)
  160. tassert.Equal(
  161. t,
  162. strings.TrimSpace(strings.Join([]string{certificate1, certificate2, privateKey}, "\n")),
  163. strings.TrimSpace(string(chainAndPrivateKeyData)),
  164. )
  165. }
  166. func TestGetSecretByVersionID(t *testing.T) {
  167. ctx := context.Background()
  168. namespace := uuid.NewString()
  169. authorizedKey := newFakeAuthorizedKey()
  170. fakeClock := clock.NewFakeClock()
  171. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  172. oldCertificate1 := uuid.NewString()
  173. oldCertificate2 := uuid.NewString()
  174. oldPrivateKey := uuid.NewString()
  175. certificateID, oldVersionID := fakeCertificateManagerServer.CreateCertificate(authorizedKey, &certificatemanager.GetCertificateContentResponse{
  176. CertificateChain: []string{oldCertificate1, oldCertificate2},
  177. PrivateKey: oldPrivateKey,
  178. })
  179. k8sClient := clientfake.NewClientBuilder().Build()
  180. const authorizedKeySecretName = "authorizedKeySecretName"
  181. const authorizedKeySecretKey = "authorizedKeySecretKey"
  182. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  183. tassert.Nil(t, err)
  184. store := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  185. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  186. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  187. tassert.Nil(t, err)
  188. data, err := secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Version: oldVersionID})
  189. tassert.Nil(t, err)
  190. tassert.Equal(
  191. t,
  192. strings.TrimSpace(strings.Join([]string{oldCertificate1, oldCertificate2, oldPrivateKey}, "\n")),
  193. strings.TrimSpace(string(data)),
  194. )
  195. newCertificate1 := uuid.NewString()
  196. newCertificate2 := uuid.NewString()
  197. newPrivateKey := uuid.NewString()
  198. newVersionID := fakeCertificateManagerServer.AddVersion(certificateID, &certificatemanager.GetCertificateContentResponse{
  199. CertificateChain: []string{newCertificate1, newCertificate2},
  200. PrivateKey: newPrivateKey,
  201. })
  202. data, err = secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Version: oldVersionID})
  203. tassert.Nil(t, err)
  204. tassert.Equal(
  205. t,
  206. strings.TrimSpace(strings.Join([]string{oldCertificate1, oldCertificate2, oldPrivateKey}, "\n")),
  207. strings.TrimSpace(string(data)),
  208. )
  209. data, err = secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Version: newVersionID})
  210. tassert.Nil(t, err)
  211. tassert.Equal(
  212. t,
  213. strings.TrimSpace(strings.Join([]string{newCertificate1, newCertificate2, newPrivateKey}, "\n")),
  214. strings.TrimSpace(string(data)),
  215. )
  216. }
  217. func TestGetSecretUnauthorized(t *testing.T) {
  218. ctx := context.Background()
  219. namespace := uuid.NewString()
  220. authorizedKeyA := newFakeAuthorizedKey()
  221. authorizedKeyB := newFakeAuthorizedKey()
  222. fakeClock := clock.NewFakeClock()
  223. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  224. certificateID, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKeyA, &certificatemanager.GetCertificateContentResponse{
  225. CertificateChain: []string{uuid.NewString()},
  226. PrivateKey: uuid.NewString(),
  227. })
  228. k8sClient := clientfake.NewClientBuilder().Build()
  229. const authorizedKeySecretName = "authorizedKeySecretName"
  230. const authorizedKeySecretKey = "authorizedKeySecretKey"
  231. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKeyB))
  232. tassert.Nil(t, err)
  233. store := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  234. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  235. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  236. tassert.Nil(t, err)
  237. _, err = secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID})
  238. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  239. }
  240. func TestGetSecretNotFound(t *testing.T) {
  241. ctx := context.Background()
  242. namespace := uuid.NewString()
  243. authorizedKey := newFakeAuthorizedKey()
  244. fakeClock := clock.NewFakeClock()
  245. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  246. k8sClient := clientfake.NewClientBuilder().Build()
  247. const authorizedKeySecretName = "authorizedKeySecretName"
  248. const authorizedKeySecretKey = "authorizedKeySecretKey"
  249. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  250. tassert.Nil(t, err)
  251. store := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  252. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  253. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  254. tassert.Nil(t, err)
  255. _, err = secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: "no-secret-with-this-id"})
  256. tassert.EqualError(t, err, errSecretPayloadNotFound)
  257. certificateID, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKey, &certificatemanager.GetCertificateContentResponse{
  258. CertificateChain: []string{uuid.NewString()},
  259. PrivateKey: uuid.NewString(),
  260. })
  261. _, err = secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Version: "no-version-with-this-id"})
  262. tassert.EqualError(t, err, "unable to request certificate content to get secret: version not found")
  263. }
  264. func TestGetSecretWithTwoNamespaces(t *testing.T) {
  265. ctx := context.Background()
  266. namespace1 := uuid.NewString()
  267. namespace2 := uuid.NewString()
  268. authorizedKey1 := newFakeAuthorizedKey()
  269. authorizedKey2 := newFakeAuthorizedKey()
  270. fakeClock := clock.NewFakeClock()
  271. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  272. certificate1 := uuid.NewString()
  273. privateKey1 := uuid.NewString()
  274. certificateID1, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKey1, &certificatemanager.GetCertificateContentResponse{
  275. CertificateChain: []string{certificate1},
  276. PrivateKey: privateKey1,
  277. })
  278. certificate2 := uuid.NewString()
  279. privateKey2 := uuid.NewString()
  280. certificateID2, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKey2, &certificatemanager.GetCertificateContentResponse{
  281. CertificateChain: []string{certificate2},
  282. PrivateKey: privateKey2,
  283. })
  284. k8sClient := clientfake.NewClientBuilder().Build()
  285. const authorizedKeySecretName = "authorizedKeySecretName"
  286. const authorizedKeySecretKey = "authorizedKeySecretKey"
  287. err := createK8sSecret(ctx, t, k8sClient, namespace1, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey1))
  288. tassert.Nil(t, err)
  289. err = createK8sSecret(ctx, t, k8sClient, namespace2, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey2))
  290. tassert.Nil(t, err)
  291. store1 := newYandexCertificateManagerSecretStore("", namespace1, authorizedKeySecretName, authorizedKeySecretKey)
  292. store2 := newYandexCertificateManagerSecretStore("", namespace2, authorizedKeySecretName, authorizedKeySecretKey)
  293. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  294. secretsClient1, err := provider.NewClient(ctx, store1, k8sClient, namespace1)
  295. tassert.Nil(t, err)
  296. secretsClient2, err := provider.NewClient(ctx, store2, k8sClient, namespace2)
  297. tassert.Nil(t, err)
  298. data, err := secretsClient1.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID1, Property: privateKeyProperty})
  299. tassert.Equal(t, privateKey1, strings.TrimSpace(string(data)))
  300. tassert.Nil(t, err)
  301. data, err = secretsClient1.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID2, Property: privateKeyProperty})
  302. tassert.Nil(t, data)
  303. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  304. data, err = secretsClient2.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID1, Property: privateKeyProperty})
  305. tassert.Nil(t, data)
  306. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  307. data, err = secretsClient2.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID2, Property: privateKeyProperty})
  308. tassert.Equal(t, privateKey2, strings.TrimSpace(string(data)))
  309. tassert.Nil(t, err)
  310. }
  311. func TestGetSecretWithTwoApiEndpoints(t *testing.T) {
  312. ctx := context.Background()
  313. apiEndpoint1 := uuid.NewString()
  314. apiEndpoint2 := uuid.NewString()
  315. namespace := uuid.NewString()
  316. authorizedKey1 := newFakeAuthorizedKey()
  317. authorizedKey2 := newFakeAuthorizedKey()
  318. fakeClock := clock.NewFakeClock()
  319. fakeCertificateManagerServer1 := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  320. certificate1 := uuid.NewString()
  321. privateKey1 := uuid.NewString()
  322. certificateID1, _ := fakeCertificateManagerServer1.CreateCertificate(authorizedKey1, &certificatemanager.GetCertificateContentResponse{
  323. CertificateChain: []string{certificate1},
  324. PrivateKey: privateKey1,
  325. })
  326. fakeCertificateManagerServer2 := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  327. certificate2 := uuid.NewString()
  328. privateKey2 := uuid.NewString()
  329. certificateID2, _ := fakeCertificateManagerServer2.CreateCertificate(authorizedKey2, &certificatemanager.GetCertificateContentResponse{
  330. CertificateChain: []string{certificate2},
  331. PrivateKey: privateKey2,
  332. })
  333. k8sClient := clientfake.NewClientBuilder().Build()
  334. const authorizedKeySecretName1 = "authorizedKeySecretName1"
  335. const authorizedKeySecretKey1 = "authorizedKeySecretKey1"
  336. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName1, authorizedKeySecretKey1, toJSON(t, authorizedKey1))
  337. tassert.Nil(t, err)
  338. const authorizedKeySecretName2 = "authorizedKeySecretName2"
  339. const authorizedKeySecretKey2 = "authorizedKeySecretKey2"
  340. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName2, authorizedKeySecretKey2, toJSON(t, authorizedKey2))
  341. tassert.Nil(t, err)
  342. store1 := newYandexCertificateManagerSecretStore(apiEndpoint1, namespace, authorizedKeySecretName1, authorizedKeySecretKey1)
  343. store2 := newYandexCertificateManagerSecretStore(apiEndpoint2, namespace, authorizedKeySecretName2, authorizedKeySecretKey2)
  344. provider1 := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer1)
  345. provider2 := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer2)
  346. secretsClient1, err := provider1.NewClient(ctx, store1, k8sClient, namespace)
  347. tassert.Nil(t, err)
  348. secretsClient2, err := provider2.NewClient(ctx, store2, k8sClient, namespace)
  349. tassert.Nil(t, err)
  350. var data []byte
  351. data, err = secretsClient1.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID1, Property: chainProperty})
  352. tassert.Equal(t, certificate1, strings.TrimSpace(string(data)))
  353. tassert.Nil(t, err)
  354. data, err = secretsClient1.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID2, Property: chainProperty})
  355. tassert.Nil(t, data)
  356. tassert.EqualError(t, err, errSecretPayloadNotFound)
  357. data, err = secretsClient2.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID1, Property: chainProperty})
  358. tassert.Nil(t, data)
  359. tassert.EqualError(t, err, errSecretPayloadNotFound)
  360. data, err = secretsClient2.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID2, Property: chainProperty})
  361. tassert.Equal(t, certificate2, strings.TrimSpace(string(data)))
  362. tassert.Nil(t, err)
  363. }
  364. func TestGetSecretWithIamTokenExpiration(t *testing.T) {
  365. ctx := context.Background()
  366. namespace := uuid.NewString()
  367. authorizedKey := newFakeAuthorizedKey()
  368. fakeClock := clock.NewFakeClock()
  369. tokenExpirationTime := time.Hour
  370. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, tokenExpirationTime)
  371. certificate := uuid.NewString()
  372. privateKey := uuid.NewString()
  373. certificateID, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKey, &certificatemanager.GetCertificateContentResponse{
  374. CertificateChain: []string{certificate},
  375. PrivateKey: privateKey,
  376. })
  377. k8sClient := clientfake.NewClientBuilder().Build()
  378. const authorizedKeySecretName = "authorizedKeySecretName"
  379. const authorizedKeySecretKey = "authorizedKeySecretKey"
  380. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  381. tassert.Nil(t, err)
  382. store := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  383. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  384. var data []byte
  385. oldSecretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  386. tassert.Nil(t, err)
  387. data, err = oldSecretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Property: privateKeyProperty})
  388. tassert.Equal(t, privateKey, strings.TrimSpace(string(data)))
  389. tassert.Nil(t, err)
  390. fakeClock.AddDuration(2 * tokenExpirationTime)
  391. data, err = oldSecretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Property: privateKeyProperty})
  392. tassert.Nil(t, data)
  393. tassert.EqualError(t, err, "unable to request certificate content to get secret: iam token expired")
  394. newSecretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  395. tassert.Nil(t, err)
  396. data, err = newSecretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Property: privateKeyProperty})
  397. tassert.Equal(t, privateKey, strings.TrimSpace(string(data)))
  398. tassert.Nil(t, err)
  399. }
  400. func TestGetSecretWithIamTokenCleanup(t *testing.T) {
  401. ctx := context.Background()
  402. namespace := uuid.NewString()
  403. authorizedKey1 := newFakeAuthorizedKey()
  404. authorizedKey2 := newFakeAuthorizedKey()
  405. fakeClock := clock.NewFakeClock()
  406. tokenExpirationDuration := time.Hour
  407. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, tokenExpirationDuration)
  408. certificateID1, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKey1, &certificatemanager.GetCertificateContentResponse{
  409. CertificateChain: []string{uuid.NewString()},
  410. PrivateKey: uuid.NewString(),
  411. })
  412. certificateID2, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKey2, &certificatemanager.GetCertificateContentResponse{
  413. CertificateChain: []string{uuid.NewString()},
  414. PrivateKey: uuid.NewString(),
  415. })
  416. var err error
  417. k8sClient := clientfake.NewClientBuilder().Build()
  418. const authorizedKeySecretName1 = "authorizedKeySecretName1"
  419. const authorizedKeySecretKey1 = "authorizedKeySecretKey1"
  420. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName1, authorizedKeySecretKey1, toJSON(t, authorizedKey1))
  421. tassert.Nil(t, err)
  422. const authorizedKeySecretName2 = "authorizedKeySecretName2"
  423. const authorizedKeySecretKey2 = "authorizedKeySecretKey2"
  424. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName2, authorizedKeySecretKey2, toJSON(t, authorizedKey2))
  425. tassert.Nil(t, err)
  426. store1 := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName1, authorizedKeySecretKey1)
  427. store2 := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName2, authorizedKeySecretKey2)
  428. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  429. tassert.False(t, provider.IsIamTokenCached(authorizedKey1))
  430. tassert.False(t, provider.IsIamTokenCached(authorizedKey2))
  431. // Access secretID1 with authorizedKey1, IAM token for authorizedKey1 should be cached
  432. secretsClient, err := provider.NewClient(ctx, store1, k8sClient, namespace)
  433. tassert.Nil(t, err)
  434. _, err = secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID1})
  435. tassert.Nil(t, err)
  436. tassert.True(t, provider.IsIamTokenCached(authorizedKey1))
  437. tassert.False(t, provider.IsIamTokenCached(authorizedKey2))
  438. fakeClock.AddDuration(tokenExpirationDuration * 2)
  439. // Access secretID2 with authorizedKey2, IAM token for authorizedKey2 should be cached
  440. secretsClient, err = provider.NewClient(ctx, store2, k8sClient, namespace)
  441. tassert.Nil(t, err)
  442. _, err = secretsClient.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID2})
  443. tassert.Nil(t, err)
  444. tassert.True(t, provider.IsIamTokenCached(authorizedKey1))
  445. tassert.True(t, provider.IsIamTokenCached(authorizedKey2))
  446. fakeClock.AddDuration(tokenExpirationDuration)
  447. tassert.True(t, provider.IsIamTokenCached(authorizedKey1))
  448. tassert.True(t, provider.IsIamTokenCached(authorizedKey2))
  449. provider.CleanUpIamTokenMap()
  450. tassert.False(t, provider.IsIamTokenCached(authorizedKey1))
  451. tassert.True(t, provider.IsIamTokenCached(authorizedKey2))
  452. fakeClock.AddDuration(tokenExpirationDuration)
  453. tassert.False(t, provider.IsIamTokenCached(authorizedKey1))
  454. tassert.True(t, provider.IsIamTokenCached(authorizedKey2))
  455. provider.CleanUpIamTokenMap()
  456. tassert.False(t, provider.IsIamTokenCached(authorizedKey1))
  457. tassert.False(t, provider.IsIamTokenCached(authorizedKey2))
  458. }
  459. func TestGetSecretMap(t *testing.T) {
  460. ctx := context.Background()
  461. namespace := uuid.NewString()
  462. authorizedKey := newFakeAuthorizedKey()
  463. fakeClock := clock.NewFakeClock()
  464. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  465. certificate1 := uuid.NewString()
  466. certificate2 := uuid.NewString()
  467. privateKey := uuid.NewString()
  468. certificateID, _ := fakeCertificateManagerServer.CreateCertificate(authorizedKey, &certificatemanager.GetCertificateContentResponse{
  469. CertificateChain: []string{certificate1, certificate2},
  470. PrivateKey: privateKey,
  471. })
  472. k8sClient := clientfake.NewClientBuilder().Build()
  473. const authorizedKeySecretName = "authorizedKeySecretName"
  474. const authorizedKeySecretKey = "authorizedKeySecretKey"
  475. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  476. tassert.Nil(t, err)
  477. store := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  478. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  479. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  480. tassert.Nil(t, err)
  481. data, err := secretsClient.GetSecretMap(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID})
  482. tassert.Nil(t, err)
  483. tassert.Equal(
  484. t,
  485. map[string][]byte{
  486. chainProperty: []byte(certificate1 + "\n" + certificate2),
  487. privateKeyProperty: []byte(privateKey),
  488. },
  489. data,
  490. )
  491. }
  492. func TestGetSecretMapByVersionID(t *testing.T) {
  493. ctx := context.Background()
  494. namespace := uuid.NewString()
  495. authorizedKey := newFakeAuthorizedKey()
  496. fakeClock := clock.NewFakeClock()
  497. fakeCertificateManagerServer := client.NewFakeCertificateManagerServer(fakeClock, time.Hour)
  498. oldCertificate := uuid.NewString()
  499. oldPrivateKey := uuid.NewString()
  500. certificateID, oldVersionID := fakeCertificateManagerServer.CreateCertificate(authorizedKey, &certificatemanager.GetCertificateContentResponse{
  501. CertificateChain: []string{oldCertificate},
  502. PrivateKey: oldPrivateKey,
  503. })
  504. k8sClient := clientfake.NewClientBuilder().Build()
  505. const authorizedKeySecretName = "authorizedKeySecretName"
  506. const authorizedKeySecretKey = "authorizedKeySecretKey"
  507. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  508. tassert.Nil(t, err)
  509. store := newYandexCertificateManagerSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  510. provider := newCertificateManagerProvider(fakeClock, fakeCertificateManagerServer)
  511. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  512. tassert.Nil(t, err)
  513. data, err := secretsClient.GetSecretMap(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Version: oldVersionID})
  514. tassert.Nil(t, err)
  515. tassert.Equal(
  516. t,
  517. map[string][]byte{
  518. chainProperty: []byte(oldCertificate),
  519. privateKeyProperty: []byte(oldPrivateKey),
  520. },
  521. data,
  522. )
  523. newCertificate := uuid.NewString()
  524. newPrivateKey := uuid.NewString()
  525. newVersionID := fakeCertificateManagerServer.AddVersion(certificateID, &certificatemanager.GetCertificateContentResponse{
  526. CertificateChain: []string{newCertificate},
  527. PrivateKey: newPrivateKey,
  528. })
  529. data, err = secretsClient.GetSecretMap(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Version: oldVersionID})
  530. tassert.Nil(t, err)
  531. tassert.Equal(
  532. t,
  533. map[string][]byte{
  534. chainProperty: []byte(oldCertificate),
  535. privateKeyProperty: []byte(oldPrivateKey),
  536. },
  537. data,
  538. )
  539. data, err = secretsClient.GetSecretMap(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: certificateID, Version: newVersionID})
  540. tassert.Nil(t, err)
  541. tassert.Equal(
  542. t,
  543. map[string][]byte{
  544. chainProperty: []byte(newCertificate),
  545. privateKeyProperty: []byte(newPrivateKey),
  546. },
  547. data,
  548. )
  549. }
  550. // helper functions
  551. func newCertificateManagerProvider(clock clock.Clock, fakeCertificateManagerServer *client.FakeCertificateManagerServer) *common.YandexCloudProvider {
  552. return common.InitYandexCloudProvider(
  553. ctrl.Log.WithName("provider").WithName("yandex").WithName("certificatemanager"),
  554. clock,
  555. adaptInput,
  556. func(ctx context.Context, apiEndpoint string, authorizedKey *iamkey.Key, caCertificate []byte) (common.SecretGetter, error) {
  557. return newCertificateManagerSecretGetter(client.NewFakeCertificateManagerClient(fakeCertificateManagerServer))
  558. },
  559. func(ctx context.Context, apiEndpoint string, authorizedKey *iamkey.Key, caCertificate []byte) (*common.IamToken, error) {
  560. return fakeCertificateManagerServer.NewIamToken(authorizedKey), nil
  561. },
  562. 0,
  563. )
  564. }
  565. func newYandexCertificateManagerSecretStore(apiEndpoint, namespace, authorizedKeySecretName, authorizedKeySecretKey string) esv1beta1.GenericStore {
  566. return &esv1beta1.SecretStore{
  567. ObjectMeta: metav1.ObjectMeta{
  568. Namespace: namespace,
  569. },
  570. Spec: esv1beta1.SecretStoreSpec{
  571. Provider: &esv1beta1.SecretStoreProvider{
  572. YandexCertificateManager: &esv1beta1.YandexCertificateManagerProvider{
  573. APIEndpoint: apiEndpoint,
  574. Auth: esv1beta1.YandexCertificateManagerAuth{
  575. AuthorizedKey: esmeta.SecretKeySelector{
  576. Name: authorizedKeySecretName,
  577. Key: authorizedKeySecretKey,
  578. },
  579. },
  580. },
  581. },
  582. },
  583. }
  584. }
  585. func toJSON(t *testing.T, v any) []byte {
  586. jsonBytes, err := json.Marshal(v)
  587. tassert.Nil(t, err)
  588. return jsonBytes
  589. }
  590. func createK8sSecret(ctx context.Context, t *testing.T, k8sClient k8sclient.Client, namespace, secretName, secretKey string, secretValue []byte) error {
  591. err := k8sClient.Create(ctx, &corev1.Secret{
  592. ObjectMeta: metav1.ObjectMeta{
  593. Namespace: namespace,
  594. Name: secretName,
  595. },
  596. Data: map[string][]byte{secretKey: secretValue},
  597. })
  598. tassert.Nil(t, err)
  599. return nil
  600. }
  601. func newFakeAuthorizedKey() *iamkey.Key {
  602. uniqueLabel := uuid.NewString()
  603. return &iamkey.Key{
  604. Id: uniqueLabel,
  605. Subject: &iamkey.Key_ServiceAccountId{
  606. ServiceAccountId: uniqueLabel,
  607. },
  608. PrivateKey: uniqueLabel,
  609. }
  610. }