lockbox_test.go 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  1. /*
  2. Copyright © The ESO Authors
  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. https://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 lockbox
  14. import (
  15. "context"
  16. b64 "encoding/base64"
  17. "encoding/json"
  18. "testing"
  19. "time"
  20. "github.com/google/uuid"
  21. tassert "github.com/stretchr/testify/assert"
  22. "github.com/yandex-cloud/go-genproto/yandex/cloud/lockbox/v1"
  23. "github.com/yandex-cloud/go-sdk/iamkey"
  24. corev1 "k8s.io/api/core/v1"
  25. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  26. ctrl "sigs.k8s.io/controller-runtime"
  27. k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
  28. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  29. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  30. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  31. ydxcommon "github.com/external-secrets/external-secrets/providers/v1/yandex/common"
  32. "github.com/external-secrets/external-secrets/providers/v1/yandex/common/clock"
  33. "github.com/external-secrets/external-secrets/providers/v1/yandex/lockbox/client"
  34. )
  35. const (
  36. errMissingKey = "invalid Yandex Lockbox SecretStore resource: missing AuthorizedKey Name"
  37. errSecretPayloadPermissionDenied = "unable to request secret payload to get secret: permission denied"
  38. errSecretPayloadNotFound = "unable to request secret payload to get secret: secret not found"
  39. errSecretPayloadVersionNotFound = "unable to request secret payload to get secret: version not found"
  40. )
  41. func TestNewClient(t *testing.T) {
  42. ctx := context.Background()
  43. const namespace = "namespace"
  44. const authorizedKeySecretName = "authorizedKeySecretName"
  45. const authorizedKeySecretKey = "authorizedKeySecretKey"
  46. store := &esv1.SecretStore{
  47. ObjectMeta: metav1.ObjectMeta{
  48. Namespace: namespace,
  49. },
  50. Spec: esv1.SecretStoreSpec{
  51. Provider: &esv1.SecretStoreProvider{
  52. YandexLockbox: &esv1.YandexLockboxProvider{
  53. Auth: esv1.YandexAuth{
  54. AuthorizedKey: esmeta.SecretKeySelector{
  55. Key: authorizedKeySecretKey,
  56. Name: authorizedKeySecretName,
  57. },
  58. },
  59. },
  60. },
  61. },
  62. }
  63. esv1.Register(NewProvider(), ProviderSpec(), MaintenanceStatus())
  64. provider, err := esv1.GetProvider(store)
  65. tassert.Nil(t, err)
  66. k8sClient := clientfake.NewClientBuilder().Build()
  67. secretClient, err := provider.NewClient(context.Background(), store, k8sClient, namespace)
  68. tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\" from namespace \"namespace\": secrets \"authorizedKeySecretName\" not found")
  69. tassert.Nil(t, secretClient)
  70. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
  71. tassert.Nil(t, err)
  72. const caCertificateSecretName = "caCertificateSecretName"
  73. const caCertificateSecretKey = "caCertificateSecretKey"
  74. store.Spec.Provider.YandexLockbox.CAProvider = &esv1.YandexCAProvider{
  75. Certificate: esmeta.SecretKeySelector{
  76. Key: caCertificateSecretKey,
  77. Name: caCertificateSecretName,
  78. },
  79. }
  80. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  81. tassert.EqualError(t, err, "cannot get Kubernetes secret \"caCertificateSecretName\" from namespace \"namespace\": secrets \"caCertificateSecretName\" not found")
  82. tassert.Nil(t, secretClient)
  83. err = createK8sSecret(ctx, t, k8sClient, namespace, caCertificateSecretName, caCertificateSecretKey, []byte("it-is-not-a-certificate"))
  84. tassert.Nil(t, err)
  85. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  86. tassert.EqualError(t, err, "failed to create Yandex.Cloud client: unable to read trusted CA certificates")
  87. tassert.Nil(t, secretClient)
  88. }
  89. func TestGetSecretForAllEntries(t *testing.T) {
  90. ctx := context.Background()
  91. namespace := uuid.NewString()
  92. authorizedKey := newFakeAuthorizedKey()
  93. fakeClock := clock.NewFakeClock()
  94. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  95. k1, v1 := "k1", "v1"
  96. k2, v2 := "k2", []byte("v2")
  97. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKey,
  98. "folderId", "secretName",
  99. textEntry(k1, v1),
  100. binaryEntry(k2, v2),
  101. )
  102. k8sClient := clientfake.NewClientBuilder().Build()
  103. const authorizedKeySecretName = "authorizedKeySecretName"
  104. const authorizedKeySecretKey = "authorizedKeySecretKey"
  105. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  106. tassert.Nil(t, err)
  107. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  108. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  109. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  110. tassert.Nil(t, err)
  111. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID})
  112. tassert.Nil(t, err)
  113. tassert.Equal(
  114. t,
  115. map[string]string{
  116. k1: v1,
  117. k2: base64(v2),
  118. },
  119. unmarshalStringMap(t, data),
  120. )
  121. }
  122. func TestGetSecretForTextEntry(t *testing.T) {
  123. ctx := context.Background()
  124. namespace := uuid.NewString()
  125. authorizedKey := newFakeAuthorizedKey()
  126. fakeClock := clock.NewFakeClock()
  127. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  128. k1, v1 := "k1", "v1"
  129. k2, v2 := "k2", []byte("v2")
  130. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKey,
  131. "folderId", "secretName",
  132. textEntry(k1, v1),
  133. binaryEntry(k2, v2),
  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 := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  141. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  142. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  143. tassert.Nil(t, err)
  144. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Property: k1})
  145. tassert.Nil(t, err)
  146. tassert.Equal(t, v1, string(data))
  147. }
  148. func TestGetSecretForBinaryEntry(t *testing.T) {
  149. ctx := context.Background()
  150. namespace := uuid.NewString()
  151. authorizedKey := newFakeAuthorizedKey()
  152. fakeClock := clock.NewFakeClock()
  153. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  154. k1, v1 := "k1", "v1"
  155. k2, v2 := "k2", []byte("v2")
  156. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKey,
  157. "folderId", "secretName",
  158. textEntry(k1, v1),
  159. binaryEntry(k2, v2),
  160. )
  161. k8sClient := clientfake.NewClientBuilder().Build()
  162. const authorizedKeySecretName = "authorizedKeySecretName"
  163. const authorizedKeySecretKey = "authorizedKeySecretKey"
  164. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  165. tassert.Nil(t, err)
  166. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  167. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  168. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  169. tassert.Nil(t, err)
  170. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Property: k2})
  171. tassert.Nil(t, err)
  172. tassert.Equal(t, v2, data)
  173. }
  174. func TestGetSecretByVersionID(t *testing.T) {
  175. ctx := context.Background()
  176. namespace := uuid.NewString()
  177. authorizedKey := newFakeAuthorizedKey()
  178. fakeClock := clock.NewFakeClock()
  179. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  180. const oldKey, oldVal = "oldKey", "oldVal"
  181. secretID, oldVersionID := fakeLockboxServer.CreateSecret(authorizedKey,
  182. "folderId", "secretName",
  183. textEntry(oldKey, oldVal),
  184. )
  185. k8sClient := clientfake.NewClientBuilder().Build()
  186. const authorizedKeySecretName = "authorizedKeySecretName"
  187. const authorizedKeySecretKey = "authorizedKeySecretKey"
  188. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  189. tassert.Nil(t, err)
  190. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  191. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  192. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  193. tassert.Nil(t, err)
  194. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Version: oldVersionID})
  195. tassert.Nil(t, err)
  196. tassert.Equal(t, map[string]string{oldKey: oldVal}, unmarshalStringMap(t, data))
  197. const newKey, newVal = "newKey", "newVal"
  198. newVersionID := fakeLockboxServer.AddVersion(secretID, textEntry(newKey, newVal))
  199. data, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Version: oldVersionID})
  200. tassert.Nil(t, err)
  201. tassert.Equal(t, map[string]string{oldKey: oldVal}, unmarshalStringMap(t, data))
  202. data, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Version: newVersionID})
  203. tassert.Nil(t, err)
  204. tassert.Equal(t, map[string]string{newKey: newVal}, unmarshalStringMap(t, data))
  205. }
  206. func TestGetSecretUnauthorized(t *testing.T) {
  207. ctx := context.Background()
  208. namespace := uuid.NewString()
  209. authorizedKeyA := newFakeAuthorizedKey()
  210. authorizedKeyB := newFakeAuthorizedKey()
  211. fakeClock := clock.NewFakeClock()
  212. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  213. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKeyA,
  214. "folderId", "secretName",
  215. textEntry("k1", "v1"),
  216. )
  217. k8sClient := clientfake.NewClientBuilder().Build()
  218. const authorizedKeySecretName = "authorizedKeySecretName"
  219. const authorizedKeySecretKey = "authorizedKeySecretKey"
  220. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKeyB))
  221. tassert.Nil(t, err)
  222. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  223. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  224. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  225. tassert.Nil(t, err)
  226. _, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID})
  227. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  228. }
  229. func TestGetSecretNotFound(t *testing.T) {
  230. ctx := context.Background()
  231. namespace := uuid.NewString()
  232. authorizedKey := newFakeAuthorizedKey()
  233. fakeClock := clock.NewFakeClock()
  234. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  235. k8sClient := clientfake.NewClientBuilder().Build()
  236. const authorizedKeySecretName = "authorizedKeySecretName"
  237. const authorizedKeySecretKey = "authorizedKeySecretKey"
  238. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  239. tassert.Nil(t, err)
  240. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  241. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  242. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  243. tassert.Nil(t, err)
  244. _, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: "no-secret-with-this-id"})
  245. tassert.EqualError(t, err, errSecretPayloadNotFound)
  246. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKey,
  247. "folderId", "secretName",
  248. textEntry("k1", "v1"),
  249. )
  250. _, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Version: "no-version-with-this-id"})
  251. tassert.EqualError(t, err, errSecretPayloadVersionNotFound)
  252. }
  253. func TestGetSecretWithTwoNamespaces(t *testing.T) {
  254. ctx := context.Background()
  255. namespace1 := uuid.NewString()
  256. namespace2 := uuid.NewString()
  257. authorizedKey1 := newFakeAuthorizedKey()
  258. authorizedKey2 := newFakeAuthorizedKey()
  259. fakeClock := clock.NewFakeClock()
  260. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  261. k1, v1 := "k1", "v1"
  262. secretID1, _ := fakeLockboxServer.CreateSecret(authorizedKey1,
  263. "folderId", "secretName1",
  264. textEntry(k1, v1),
  265. )
  266. k2, v2 := "k2", "v2"
  267. secretID2, _ := fakeLockboxServer.CreateSecret(authorizedKey2,
  268. "folderId", "secretName2",
  269. textEntry(k2, v2),
  270. textEntry(k2, v2),
  271. )
  272. k8sClient := clientfake.NewClientBuilder().Build()
  273. const authorizedKeySecretName = "authorizedKeySecretName"
  274. const authorizedKeySecretKey = "authorizedKeySecretKey"
  275. err := createK8sSecret(ctx, t, k8sClient, namespace1, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey1))
  276. tassert.Nil(t, err)
  277. err = createK8sSecret(ctx, t, k8sClient, namespace2, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey2))
  278. tassert.Nil(t, err)
  279. store1 := newYandexLockboxSecretStore("", namespace1, authorizedKeySecretName, authorizedKeySecretKey)
  280. store2 := newYandexLockboxSecretStore("", namespace2, authorizedKeySecretName, authorizedKeySecretKey)
  281. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  282. secretsClient1, err := provider.NewClient(ctx, store1, k8sClient, namespace1)
  283. tassert.Nil(t, err)
  284. secretsClient2, err := provider.NewClient(ctx, store2, k8sClient, namespace2)
  285. tassert.Nil(t, err)
  286. data, err := secretsClient1.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID1, Property: k1})
  287. tassert.Equal(t, v1, string(data))
  288. tassert.Nil(t, err)
  289. data, err = secretsClient1.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID2, Property: k2})
  290. tassert.Nil(t, data)
  291. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  292. data, err = secretsClient2.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID1, Property: k1})
  293. tassert.Nil(t, data)
  294. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  295. data, err = secretsClient2.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID2, Property: k2})
  296. tassert.Equal(t, v2, string(data))
  297. tassert.Nil(t, err)
  298. }
  299. func TestGetSecretWithTwoApiEndpoints(t *testing.T) {
  300. ctx := context.Background()
  301. apiEndpoint1 := uuid.NewString()
  302. apiEndpoint2 := uuid.NewString()
  303. namespace := uuid.NewString()
  304. authorizedKey1 := newFakeAuthorizedKey()
  305. authorizedKey2 := newFakeAuthorizedKey()
  306. fakeClock := clock.NewFakeClock()
  307. fakeLockboxServer1 := client.NewFakeLockboxServer(fakeClock, time.Hour)
  308. k1, v1 := "k1", "v1"
  309. secretID1, _ := fakeLockboxServer1.CreateSecret(authorizedKey1,
  310. "folderId", "secretName",
  311. textEntry(k1, v1),
  312. )
  313. fakeLockboxServer2 := client.NewFakeLockboxServer(fakeClock, time.Hour)
  314. k2, v2 := "k2", "v2"
  315. secretID2, _ := fakeLockboxServer2.CreateSecret(authorizedKey2,
  316. "folderId", "secretName",
  317. textEntry(k2, v2),
  318. )
  319. k8sClient := clientfake.NewClientBuilder().Build()
  320. const authorizedKeySecretName1 = "authorizedKeySecretName1"
  321. const authorizedKeySecretKey1 = "authorizedKeySecretKey1"
  322. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName1, authorizedKeySecretKey1, toJSON(t, authorizedKey1))
  323. tassert.Nil(t, err)
  324. const authorizedKeySecretName2 = "authorizedKeySecretName2"
  325. const authorizedKeySecretKey2 = "authorizedKeySecretKey2"
  326. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName2, authorizedKeySecretKey2, toJSON(t, authorizedKey2))
  327. tassert.Nil(t, err)
  328. store1 := newYandexLockboxSecretStore(apiEndpoint1, namespace, authorizedKeySecretName1, authorizedKeySecretKey1)
  329. store2 := newYandexLockboxSecretStore(apiEndpoint2, namespace, authorizedKeySecretName2, authorizedKeySecretKey2)
  330. provider1 := newLockboxProvider(fakeClock, fakeLockboxServer1)
  331. provider2 := newLockboxProvider(fakeClock, fakeLockboxServer2)
  332. secretsClient1, err := provider1.NewClient(ctx, store1, k8sClient, namespace)
  333. tassert.Nil(t, err)
  334. secretsClient2, err := provider2.NewClient(ctx, store2, k8sClient, namespace)
  335. tassert.Nil(t, err)
  336. var data []byte
  337. data, err = secretsClient1.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID1, Property: k1})
  338. tassert.Equal(t, v1, string(data))
  339. tassert.Nil(t, err)
  340. data, err = secretsClient1.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID2, Property: k2})
  341. tassert.Nil(t, data)
  342. tassert.EqualError(t, err, errSecretPayloadNotFound)
  343. data, err = secretsClient2.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID1, Property: k1})
  344. tassert.Nil(t, data)
  345. tassert.EqualError(t, err, errSecretPayloadNotFound)
  346. data, err = secretsClient2.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID2, Property: k2})
  347. tassert.Equal(t, v2, string(data))
  348. tassert.Nil(t, err)
  349. }
  350. func TestGetSecretWithIamTokenExpiration(t *testing.T) {
  351. ctx := context.Background()
  352. namespace := uuid.NewString()
  353. authorizedKey := newFakeAuthorizedKey()
  354. fakeClock := clock.NewFakeClock()
  355. tokenExpirationTime := time.Hour
  356. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, tokenExpirationTime)
  357. k1, v1 := "k1", "v1"
  358. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKey,
  359. "folderId", "secretName",
  360. textEntry(k1, v1),
  361. )
  362. k8sClient := clientfake.NewClientBuilder().Build()
  363. const authorizedKeySecretName = "authorizedKeySecretName"
  364. const authorizedKeySecretKey = "authorizedKeySecretKey"
  365. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  366. tassert.Nil(t, err)
  367. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  368. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  369. var data []byte
  370. oldSecretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  371. tassert.Nil(t, err)
  372. data, err = oldSecretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Property: k1})
  373. tassert.Equal(t, v1, string(data))
  374. tassert.Nil(t, err)
  375. fakeClock.AddDuration(2 * tokenExpirationTime)
  376. data, err = oldSecretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Property: k1})
  377. tassert.Nil(t, data)
  378. tassert.EqualError(t, err, "unable to request secret payload to get secret: iam token expired")
  379. newSecretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  380. tassert.Nil(t, err)
  381. data, err = newSecretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Property: k1})
  382. tassert.Equal(t, v1, string(data))
  383. tassert.Nil(t, err)
  384. }
  385. func TestGetSecretWithIamTokenCleanup(t *testing.T) {
  386. ctx := context.Background()
  387. namespace := uuid.NewString()
  388. authorizedKey1 := newFakeAuthorizedKey()
  389. authorizedKey2 := newFakeAuthorizedKey()
  390. fakeClock := clock.NewFakeClock()
  391. tokenExpirationDuration := time.Hour
  392. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, tokenExpirationDuration)
  393. secretID1, _ := fakeLockboxServer.CreateSecret(authorizedKey1,
  394. "folderId", "secretName1",
  395. textEntry("k1", "v1"),
  396. )
  397. secretID2, _ := fakeLockboxServer.CreateSecret(authorizedKey2,
  398. "folderId", "secretName2",
  399. textEntry("k2", "v2"),
  400. )
  401. var err error
  402. k8sClient := clientfake.NewClientBuilder().Build()
  403. const authorizedKeySecretName1 = "authorizedKeySecretName1"
  404. const authorizedKeySecretKey1 = "authorizedKeySecretKey1"
  405. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName1, authorizedKeySecretKey1, toJSON(t, authorizedKey1))
  406. tassert.Nil(t, err)
  407. const authorizedKeySecretName2 = "authorizedKeySecretName2"
  408. const authorizedKeySecretKey2 = "authorizedKeySecretKey2"
  409. err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName2, authorizedKeySecretKey2, toJSON(t, authorizedKey2))
  410. tassert.Nil(t, err)
  411. store1 := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName1, authorizedKeySecretKey1)
  412. store2 := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName2, authorizedKeySecretKey2)
  413. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  414. tassert.False(t, provider.IsIamTokenCached(authorizedKey1))
  415. tassert.False(t, provider.IsIamTokenCached(authorizedKey2))
  416. // Access secretID1 with authorizedKey1, IAM token for authorizedKey1 should be cached
  417. secretsClient, err := provider.NewClient(ctx, store1, k8sClient, namespace)
  418. tassert.Nil(t, err)
  419. _, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID1})
  420. tassert.Nil(t, err)
  421. tassert.True(t, provider.IsIamTokenCached(authorizedKey1))
  422. tassert.False(t, provider.IsIamTokenCached(authorizedKey2))
  423. fakeClock.AddDuration(tokenExpirationDuration * 2)
  424. // Access secretID2 with authorizedKey2, IAM token for authorizedKey2 should be cached
  425. secretsClient, err = provider.NewClient(ctx, store2, k8sClient, namespace)
  426. tassert.Nil(t, err)
  427. _, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID2})
  428. tassert.Nil(t, err)
  429. tassert.True(t, provider.IsIamTokenCached(authorizedKey1))
  430. tassert.True(t, provider.IsIamTokenCached(authorizedKey2))
  431. fakeClock.AddDuration(tokenExpirationDuration)
  432. tassert.True(t, provider.IsIamTokenCached(authorizedKey1))
  433. tassert.True(t, provider.IsIamTokenCached(authorizedKey2))
  434. provider.CleanUpIamTokenMap()
  435. tassert.False(t, provider.IsIamTokenCached(authorizedKey1))
  436. tassert.True(t, provider.IsIamTokenCached(authorizedKey2))
  437. fakeClock.AddDuration(tokenExpirationDuration)
  438. tassert.False(t, provider.IsIamTokenCached(authorizedKey1))
  439. tassert.True(t, provider.IsIamTokenCached(authorizedKey2))
  440. provider.CleanUpIamTokenMap()
  441. tassert.False(t, provider.IsIamTokenCached(authorizedKey1))
  442. tassert.False(t, provider.IsIamTokenCached(authorizedKey2))
  443. }
  444. func TestGetSecretMap(t *testing.T) {
  445. ctx := context.Background()
  446. namespace := uuid.NewString()
  447. authorizedKey := newFakeAuthorizedKey()
  448. fakeClock := clock.NewFakeClock()
  449. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  450. k1, v1 := "k1", "v1"
  451. k2, v2 := "k2", []byte("v2")
  452. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKey,
  453. "folderId", "secretName",
  454. textEntry(k1, v1),
  455. binaryEntry(k2, v2),
  456. )
  457. k8sClient := clientfake.NewClientBuilder().Build()
  458. const authorizedKeySecretName = "authorizedKeySecretName"
  459. const authorizedKeySecretKey = "authorizedKeySecretKey"
  460. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  461. tassert.Nil(t, err)
  462. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  463. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  464. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  465. tassert.Nil(t, err)
  466. data, err := secretsClient.GetSecretMap(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID})
  467. tassert.Nil(t, err)
  468. tassert.Equal(
  469. t,
  470. map[string][]byte{
  471. k1: []byte(v1),
  472. k2: v2,
  473. },
  474. data,
  475. )
  476. }
  477. func TestGetSecretMapByVersionID(t *testing.T) {
  478. ctx := context.Background()
  479. namespace := uuid.NewString()
  480. authorizedKey := newFakeAuthorizedKey()
  481. fakeClock := clock.NewFakeClock()
  482. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  483. oldKey, oldVal := "oldKey", "oldVal"
  484. secretID, oldVersionID := fakeLockboxServer.CreateSecret(authorizedKey,
  485. "folderId", "secretName",
  486. textEntry(oldKey, oldVal),
  487. )
  488. k8sClient := clientfake.NewClientBuilder().Build()
  489. const authorizedKeySecretName = "authorizedKeySecretName"
  490. const authorizedKeySecretKey = "authorizedKeySecretKey"
  491. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  492. tassert.Nil(t, err)
  493. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  494. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  495. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  496. tassert.Nil(t, err)
  497. data, err := secretsClient.GetSecretMap(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Version: oldVersionID})
  498. tassert.Nil(t, err)
  499. tassert.Equal(t, map[string][]byte{oldKey: []byte(oldVal)}, data)
  500. newKey, newVal := "newKey", "newVal"
  501. newVersionID := fakeLockboxServer.AddVersion(secretID, textEntry(newKey, newVal))
  502. data, err = secretsClient.GetSecretMap(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Version: oldVersionID})
  503. tassert.Nil(t, err)
  504. tassert.Equal(t, map[string][]byte{oldKey: []byte(oldVal)}, data)
  505. data, err = secretsClient.GetSecretMap(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Version: newVersionID})
  506. tassert.Nil(t, err)
  507. tassert.Equal(t, map[string][]byte{newKey: []byte(newVal)}, data)
  508. }
  509. func TestGetSecretWithByNameFetchingPolicyForAllEntries(t *testing.T) {
  510. ctx := context.Background()
  511. namespace := uuid.NewString()
  512. authorizedKey := newFakeAuthorizedKey()
  513. fakeClock := clock.NewFakeClock()
  514. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  515. folderID := uuid.NewString()
  516. const secretName = "secretName"
  517. k1, v1 := "k1", "v1"
  518. k2, v2 := "k2", []byte("v2")
  519. _, _ = fakeLockboxServer.CreateSecret(authorizedKey, folderID, secretName, textEntry(k1, v1), binaryEntry(k2, v2))
  520. k8sClient := clientfake.NewClientBuilder().Build()
  521. const authorizedKeySecretName = "authorizedKeySecretName"
  522. const authorizedKeySecretKey = "authorizedKeySecretKey"
  523. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  524. tassert.Nil(t, err)
  525. store := newYandexLockboxSecretStoreWithFetchByName("", namespace, authorizedKeySecretName, authorizedKeySecretKey, folderID)
  526. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  527. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  528. tassert.Nil(t, err)
  529. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretName})
  530. tassert.Nil(t, err)
  531. expected := map[string]string{
  532. k1: base64([]byte(v1)),
  533. k2: base64(v2),
  534. }
  535. tassert.Equal(t, expected, unmarshalStringMap(t, data))
  536. }
  537. func TestGetSecretWithByNameFetchingPolicyAndVersionID(t *testing.T) {
  538. ctx := context.Background()
  539. namespace := uuid.NewString()
  540. authorizedKey := newFakeAuthorizedKey()
  541. fakeClock := clock.NewFakeClock()
  542. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  543. folderID := uuid.NewString()
  544. const secretName = "secretName"
  545. oldKey, oldVal := "oldKey", "oldVal"
  546. secretID, oldVersionID := fakeLockboxServer.CreateSecret(authorizedKey, folderID, secretName, textEntry(oldKey, oldVal))
  547. k8sClient := clientfake.NewClientBuilder().Build()
  548. const authorizedKeySecretName = "authorizedKeySecretName"
  549. const authorizedKeySecretKey = "authorizedKeySecretKey"
  550. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  551. tassert.Nil(t, err)
  552. store := newYandexLockboxSecretStoreWithFetchByName("", namespace, authorizedKeySecretName, authorizedKeySecretKey, folderID)
  553. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  554. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  555. tassert.Nil(t, err)
  556. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretName, Version: oldVersionID})
  557. tassert.Nil(t, err)
  558. tassert.Equal(t, map[string]string{oldKey: base64([]byte(oldVal))}, unmarshalStringMap(t, data))
  559. newKey, newVal := "newKey", "newVal"
  560. newVersionID := fakeLockboxServer.AddVersion(secretID, textEntry(newKey, newVal))
  561. data, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretName, Version: oldVersionID})
  562. tassert.Nil(t, err)
  563. tassert.Equal(t, map[string]string{oldKey: base64([]byte(oldVal))}, unmarshalStringMap(t, data))
  564. data, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretName, Version: newVersionID})
  565. tassert.Nil(t, err)
  566. tassert.Equal(t, map[string]string{newKey: base64([]byte(newVal))}, unmarshalStringMap(t, data))
  567. }
  568. func TestGetSecretWithByNameFetchingPolicyForTextEntry(t *testing.T) {
  569. ctx := context.Background()
  570. namespace := uuid.NewString()
  571. authorizedKey := newFakeAuthorizedKey()
  572. fakeClock := clock.NewFakeClock()
  573. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  574. folderID := uuid.NewString()
  575. const secretName = "secretName"
  576. k1, v1 := "k1", "v1"
  577. k2, v2 := "k2", []byte("v2")
  578. _, _ = fakeLockboxServer.CreateSecret(authorizedKey, folderID, secretName, textEntry(k1, v1), binaryEntry(k2, v2))
  579. k8sClient := clientfake.NewClientBuilder().Build()
  580. const authorizedKeySecretName = "authorizedKeySecretName"
  581. const authorizedKeySecretKey = "authorizedKeySecretKey"
  582. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  583. tassert.Nil(t, err)
  584. store := newYandexLockboxSecretStoreWithFetchByName("", namespace, authorizedKeySecretName, authorizedKeySecretKey, folderID)
  585. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  586. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  587. tassert.Nil(t, err)
  588. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretName, Property: k1})
  589. tassert.Nil(t, err)
  590. tassert.Equal(t, v1, string(data))
  591. }
  592. func TestGetSecretWithByNameFetchingPolicyForBinaryEntry(t *testing.T) {
  593. ctx := context.Background()
  594. namespace := uuid.NewString()
  595. authorizedKey := newFakeAuthorizedKey()
  596. fakeClock := clock.NewFakeClock()
  597. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  598. folderID := uuid.NewString()
  599. const secretName = "secretName"
  600. k1, v1 := "k1", "v1"
  601. k2, v2 := "k2", []byte("v2")
  602. _, _ = fakeLockboxServer.CreateSecret(authorizedKey, folderID, secretName, textEntry(k1, v1), binaryEntry(k2, v2))
  603. k8sClient := clientfake.NewClientBuilder().Build()
  604. const authorizedKeySecretName = "authorizedKeySecretName"
  605. const authorizedKeySecretKey = "authorizedKeySecretKey"
  606. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  607. tassert.Nil(t, err)
  608. store := newYandexLockboxSecretStoreWithFetchByName("", namespace, authorizedKeySecretName, authorizedKeySecretKey, folderID)
  609. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  610. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  611. tassert.Nil(t, err)
  612. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretName, Property: k2})
  613. tassert.Nil(t, err)
  614. tassert.Equal(t, v2, data)
  615. }
  616. func TestGetSecretWithByNameFetchingPolicyNotFound(t *testing.T) {
  617. ctx := context.Background()
  618. namespace := uuid.NewString()
  619. authorizedKey := newFakeAuthorizedKey()
  620. fakeClock := clock.NewFakeClock()
  621. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  622. folderID := uuid.NewString()
  623. k8sClient := clientfake.NewClientBuilder().Build()
  624. const authorizedKeySecretName = "authorizedKeySecretName"
  625. const authorizedKeySecretKey = "authorizedKeySecretKey"
  626. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  627. tassert.Nil(t, err)
  628. store := newYandexLockboxSecretStoreWithFetchByName("", namespace, authorizedKeySecretName, authorizedKeySecretKey, folderID)
  629. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  630. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  631. tassert.Nil(t, err)
  632. _, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: "no-secret-with-such-name"})
  633. tassert.EqualError(t, err, errSecretPayloadNotFound)
  634. secretName := "secretName"
  635. _, _ = fakeLockboxServer.CreateSecret(authorizedKey, folderID, secretName, textEntry("k1", "v1"))
  636. _, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretName, Version: "no-version-with-such-id"})
  637. tassert.EqualError(t, err, errSecretPayloadVersionNotFound)
  638. }
  639. func TestGetSecretWithByNameFetchingPolicyUnauthorized(t *testing.T) {
  640. ctx := context.Background()
  641. namespace := uuid.NewString()
  642. authorizedKeyA := newFakeAuthorizedKey()
  643. authorizedKeyB := newFakeAuthorizedKey()
  644. fakeClock := clock.NewFakeClock()
  645. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  646. folderID := uuid.NewString()
  647. secretName := "secretName"
  648. _, _ = fakeLockboxServer.CreateSecret(authorizedKeyA, folderID, secretName, textEntry("k1", "v1"))
  649. k8sClient := clientfake.NewClientBuilder().Build()
  650. const authorizedKeySecretName = "authorizedKeySecretName"
  651. const authorizedKeySecretKey = "authorizedKeySecretKey"
  652. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKeyB))
  653. tassert.Nil(t, err)
  654. store := newYandexLockboxSecretStoreWithFetchByName("", namespace, authorizedKeySecretName, authorizedKeySecretKey, folderID)
  655. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  656. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  657. tassert.Nil(t, err)
  658. _, err = secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretName})
  659. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  660. }
  661. func TestGetSecretWithByNameFetchingPolicyWithoutFolderID(t *testing.T) {
  662. ctx := context.Background()
  663. namespace := uuid.NewString()
  664. authorizedKey := newFakeAuthorizedKey()
  665. fakeClock := clock.NewFakeClock()
  666. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  667. k8sClient := clientfake.NewClientBuilder().Build()
  668. const authorizedKeySecretName = "authorizedKeySecretName"
  669. const authorizedKeySecretKey = "authorizedKeySecretKey"
  670. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  671. tassert.Nil(t, err)
  672. store := newYandexLockboxSecretStoreWithFetchByName("", namespace, authorizedKeySecretName, authorizedKeySecretKey, "")
  673. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  674. _, err = provider.NewClient(ctx, store, k8sClient, namespace)
  675. tassert.EqualError(t, err, "folderID is required when fetching policy is 'byName'")
  676. }
  677. func TesGetSecretWithByIDFetchingPolicyForAllEntries(t *testing.T) {
  678. ctx := context.Background()
  679. namespace := uuid.NewString()
  680. authorizedKey := newFakeAuthorizedKey()
  681. fakeClock := clock.NewFakeClock()
  682. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  683. k1, v1 := "k1", "v1"
  684. k2, v2 := "k2", []byte("v2")
  685. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKey,
  686. "folderId", "secret",
  687. textEntry(k1, v1),
  688. binaryEntry(k2, v2),
  689. )
  690. k8sClient := clientfake.NewClientBuilder().Build()
  691. const authorizedKeySecretName = "authorizedKeySecretName"
  692. const authorizedKeySecretKey = "authorizedKeySecretKey"
  693. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  694. tassert.Nil(t, err)
  695. store := newYandexLockboxSecretStoreWithFetchByID("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  696. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  697. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  698. tassert.Nil(t, err)
  699. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID})
  700. tassert.Nil(t, err)
  701. expected := map[string]string{
  702. k1: v1,
  703. k2: base64(v2),
  704. }
  705. tassert.Equal(t, expected, unmarshalStringMap(t, data))
  706. }
  707. func TestGetSecretWithByIDFetchingPolicyForTextEntry(t *testing.T) {
  708. ctx := context.Background()
  709. namespace := uuid.NewString()
  710. authorizedKey := newFakeAuthorizedKey()
  711. fakeClock := clock.NewFakeClock()
  712. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  713. k1, v1 := "k1", "v1"
  714. k2, v2 := "k2", []byte("v2")
  715. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKey,
  716. "folderId", "secret",
  717. textEntry(k1, v1),
  718. binaryEntry(k2, v2),
  719. )
  720. k8sClient := clientfake.NewClientBuilder().Build()
  721. const authorizedKeySecretName = "authorizedKeySecretName"
  722. const authorizedKeySecretKey = "authorizedKeySecretKey"
  723. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  724. tassert.Nil(t, err)
  725. store := newYandexLockboxSecretStoreWithFetchByID("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  726. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  727. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  728. tassert.Nil(t, err)
  729. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Property: k1})
  730. tassert.Nil(t, err)
  731. tassert.Equal(t, v1, string(data))
  732. }
  733. func TestGetSecretWithByIDFetchingPolicyForBinaryEntry(t *testing.T) {
  734. ctx := context.Background()
  735. namespace := uuid.NewString()
  736. authorizedKey := newFakeAuthorizedKey()
  737. fakeClock := clock.NewFakeClock()
  738. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  739. k1, v1 := "k1", "v1"
  740. k2, v2 := "k2", []byte("v2")
  741. secretID, _ := fakeLockboxServer.CreateSecret(authorizedKey,
  742. "folderId", "secret",
  743. textEntry(k1, v1),
  744. binaryEntry(k2, v2),
  745. )
  746. k8sClient := clientfake.NewClientBuilder().Build()
  747. const authorizedKeySecretName = "authorizedKeySecretName"
  748. const authorizedKeySecretKey = "authorizedKeySecretKey"
  749. err := createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, authorizedKey))
  750. tassert.Nil(t, err)
  751. store := newYandexLockboxSecretStoreWithFetchByID("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  752. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  753. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  754. tassert.Nil(t, err)
  755. data, err := secretsClient.GetSecret(ctx, esv1.ExternalSecretDataRemoteRef{Key: secretID, Property: k2})
  756. tassert.Nil(t, err)
  757. tassert.Equal(t, v2, data)
  758. }
  759. func TestGetSecretWithInvalidFetchingPolicy(t *testing.T) {
  760. ctx := context.Background()
  761. namespace := uuid.NewString()
  762. authorizedKey := newFakeAuthorizedKey()
  763. fakeClock := clock.NewFakeClock()
  764. fakeLockboxServer := client.NewFakeLockboxServer(fakeClock, time.Hour)
  765. k8sClient := clientfake.NewClientBuilder().Build()
  766. const authorizedKeySecretName = "authorizedKeySecretName"
  767. const authorizedKeySecretKey = "authorizedKeySecretKey"
  768. err := createK8sSecret(
  769. ctx, t, k8sClient, namespace,
  770. authorizedKeySecretName, authorizedKeySecretKey,
  771. toJSON(t, authorizedKey),
  772. )
  773. tassert.Nil(t, err)
  774. store := &esv1.SecretStore{
  775. ObjectMeta: metav1.ObjectMeta{Namespace: namespace},
  776. Spec: esv1.SecretStoreSpec{
  777. Provider: &esv1.SecretStoreProvider{
  778. YandexLockbox: &esv1.YandexLockboxProvider{
  779. Auth: esv1.YandexAuth{
  780. AuthorizedKey: esmeta.SecretKeySelector{
  781. Name: authorizedKeySecretName,
  782. Key: authorizedKeySecretKey,
  783. },
  784. },
  785. FetchingPolicy: &esv1.FetchingPolicy{
  786. ByID: nil,
  787. ByName: nil,
  788. },
  789. },
  790. },
  791. },
  792. }
  793. provider := newLockboxProvider(fakeClock, fakeLockboxServer)
  794. _, err = provider.NewClient(ctx, store, k8sClient, namespace)
  795. tassert.EqualError(
  796. t,
  797. err,
  798. "invalid Yandex Lockbox SecretStore: requires either 'byName' or 'byID' policy",
  799. )
  800. }
  801. // helper fuxnctions
  802. func newLockboxProvider(clock clock.Clock, fakeLockboxServer *client.FakeLockboxServer) *ydxcommon.YandexCloudProvider {
  803. return ydxcommon.InitYandexCloudProvider(
  804. ctrl.Log.WithName("provider").WithName("yandex").WithName("lockbox"),
  805. clock,
  806. adaptInput,
  807. func(context.Context, string, *iamkey.Key, []byte) (ydxcommon.SecretGetter, error) {
  808. return newLockboxSecretGetter(client.NewFakeLockboxClient(fakeLockboxServer))
  809. },
  810. func(_ context.Context, _ string, authorizedKey *iamkey.Key, _ []byte) (*ydxcommon.IamToken, error) {
  811. return fakeLockboxServer.NewIamToken(authorizedKey), nil
  812. },
  813. 0,
  814. )
  815. }
  816. func newYandexLockboxSecretStore(apiEndpoint, namespace, authorizedKeySecretName, authorizedKeySecretKey string) esv1.GenericStore {
  817. return &esv1.SecretStore{
  818. ObjectMeta: metav1.ObjectMeta{
  819. Namespace: namespace,
  820. },
  821. Spec: esv1.SecretStoreSpec{
  822. Provider: &esv1.SecretStoreProvider{
  823. YandexLockbox: &esv1.YandexLockboxProvider{
  824. APIEndpoint: apiEndpoint,
  825. Auth: esv1.YandexAuth{
  826. AuthorizedKey: esmeta.SecretKeySelector{
  827. Name: authorizedKeySecretName,
  828. Key: authorizedKeySecretKey,
  829. },
  830. },
  831. },
  832. },
  833. },
  834. }
  835. }
  836. func newYandexLockboxSecretStoreWithFetchByName(apiEndpoint, namespace, authorizedKeySecretName, authorizedKeySecretKey, folderID string) esv1.GenericStore {
  837. return &esv1.SecretStore{
  838. ObjectMeta: metav1.ObjectMeta{
  839. Namespace: namespace,
  840. },
  841. Spec: esv1.SecretStoreSpec{
  842. Provider: &esv1.SecretStoreProvider{
  843. YandexLockbox: &esv1.YandexLockboxProvider{
  844. APIEndpoint: apiEndpoint,
  845. Auth: esv1.YandexAuth{
  846. AuthorizedKey: esmeta.SecretKeySelector{
  847. Name: authorizedKeySecretName,
  848. Key: authorizedKeySecretKey,
  849. },
  850. },
  851. FetchingPolicy: &esv1.FetchingPolicy{
  852. ByName: &esv1.ByName{
  853. FolderID: folderID,
  854. },
  855. },
  856. },
  857. },
  858. },
  859. }
  860. }
  861. func newYandexLockboxSecretStoreWithFetchByID(apiEndpoint, namespace, authorizedKeySecretName, authorizedKeySecretKey string) esv1.GenericStore {
  862. return &esv1.SecretStore{
  863. ObjectMeta: metav1.ObjectMeta{
  864. Namespace: namespace,
  865. },
  866. Spec: esv1.SecretStoreSpec{
  867. Provider: &esv1.SecretStoreProvider{
  868. YandexLockbox: &esv1.YandexLockboxProvider{
  869. APIEndpoint: apiEndpoint,
  870. Auth: esv1.YandexAuth{
  871. AuthorizedKey: esmeta.SecretKeySelector{
  872. Name: authorizedKeySecretName,
  873. Key: authorizedKeySecretKey,
  874. },
  875. },
  876. FetchingPolicy: &esv1.FetchingPolicy{
  877. ByID: &esv1.ByID{},
  878. },
  879. },
  880. },
  881. },
  882. }
  883. }
  884. func toJSON(t *testing.T, v any) []byte {
  885. jsonBytes, err := json.Marshal(v)
  886. tassert.Nil(t, err)
  887. return jsonBytes
  888. }
  889. func createK8sSecret(ctx context.Context, t *testing.T, k8sClient k8sclient.Client, namespace, secretName, secretKey string, secretValue []byte) error {
  890. err := k8sClient.Create(ctx, &corev1.Secret{
  891. ObjectMeta: metav1.ObjectMeta{
  892. Namespace: namespace,
  893. Name: secretName,
  894. },
  895. Data: map[string][]byte{secretKey: secretValue},
  896. })
  897. tassert.Nil(t, err)
  898. return nil
  899. }
  900. func newFakeAuthorizedKey() *iamkey.Key {
  901. uniqueLabel := uuid.NewString()
  902. return &iamkey.Key{
  903. Id: uniqueLabel,
  904. Subject: &iamkey.Key_ServiceAccountId{
  905. ServiceAccountId: uniqueLabel,
  906. },
  907. PrivateKey: uniqueLabel,
  908. }
  909. }
  910. func textEntry(key, value string) *lockbox.Payload_Entry {
  911. return &lockbox.Payload_Entry{
  912. Key: key,
  913. Value: &lockbox.Payload_Entry_TextValue{
  914. TextValue: value,
  915. },
  916. }
  917. }
  918. func binaryEntry(key string, value []byte) *lockbox.Payload_Entry {
  919. return &lockbox.Payload_Entry{
  920. Key: key,
  921. Value: &lockbox.Payload_Entry_BinaryValue{
  922. BinaryValue: value,
  923. },
  924. }
  925. }
  926. func unmarshalStringMap(t *testing.T, data []byte) map[string]string {
  927. stringMap := make(map[string]string)
  928. err := json.Unmarshal(data, &stringMap)
  929. tassert.Nil(t, err)
  930. return stringMap
  931. }
  932. func base64(data []byte) string {
  933. return b64.StdEncoding.EncodeToString(data)
  934. }