lockbox_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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 lockbox
  13. import (
  14. "context"
  15. b64 "encoding/base64"
  16. "encoding/json"
  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/lockbox/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. "sigs.k8s.io/controller-runtime/pkg/client"
  26. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  27. esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  28. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  29. "github.com/external-secrets/external-secrets/pkg/provider/schema"
  30. "github.com/external-secrets/external-secrets/pkg/provider/yandex/lockbox/client/fake"
  31. )
  32. const (
  33. errMissingKey = "invalid Yandex Lockbox SecretStore resource: missing AuthorizedKey Name"
  34. errSecretPayloadPermissionDenied = "unable to request secret payload to get secret: permission denied"
  35. errSecretPayloadNotFound = "unable to request secret payload to get secret: secret not found"
  36. )
  37. func TestNewClient(t *testing.T) {
  38. ctx := context.Background()
  39. const namespace = "namespace"
  40. store := &esv1alpha1.SecretStore{
  41. ObjectMeta: metav1.ObjectMeta{
  42. Namespace: namespace,
  43. },
  44. Spec: esv1alpha1.SecretStoreSpec{
  45. Provider: &esv1alpha1.SecretStoreProvider{
  46. YandexLockbox: &esv1alpha1.YandexLockboxProvider{},
  47. },
  48. },
  49. }
  50. provider, err := schema.GetProvider(store)
  51. tassert.Nil(t, err)
  52. k8sClient := clientfake.NewClientBuilder().Build()
  53. secretClient, err := provider.NewClient(context.Background(), store, k8sClient, namespace)
  54. tassert.EqualError(t, err, errMissingKey)
  55. tassert.Nil(t, secretClient)
  56. store.Spec.Provider.YandexLockbox.Auth = esv1alpha1.YandexLockboxAuth{}
  57. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  58. tassert.EqualError(t, err, errMissingKey)
  59. tassert.Nil(t, secretClient)
  60. store.Spec.Provider.YandexLockbox.Auth.AuthorizedKey = esmeta.SecretKeySelector{}
  61. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  62. tassert.EqualError(t, err, errMissingKey)
  63. tassert.Nil(t, secretClient)
  64. const authorizedKeySecretName = "authorizedKeySecretName"
  65. const authorizedKeySecretKey = "authorizedKeySecretKey"
  66. store.Spec.Provider.YandexLockbox.Auth.AuthorizedKey.Name = authorizedKeySecretName
  67. store.Spec.Provider.YandexLockbox.Auth.AuthorizedKey.Key = authorizedKeySecretKey
  68. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  69. tassert.EqualError(t, err, "could not fetch AuthorizedKey secret: secrets \"authorizedKeySecretName\" not found")
  70. tassert.Nil(t, secretClient)
  71. err = createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, newFakeAuthorizedKey())
  72. tassert.Nil(t, err)
  73. secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
  74. tassert.EqualError(t, err, "failed to create Yandex Lockbox client: private key parsing failed: Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key")
  75. tassert.Nil(t, secretClient)
  76. }
  77. func TestGetSecretForAllEntries(t *testing.T) {
  78. ctx := context.Background()
  79. namespace := uuid.NewString()
  80. authorizedKey := newFakeAuthorizedKey()
  81. lockboxBackend := fake.NewLockboxBackend(time.Hour)
  82. k1, v1 := "k1", "v1"
  83. k2, v2 := "k2", []byte("v2")
  84. secretID, _ := lockboxBackend.CreateSecret(authorizedKey,
  85. textEntry(k1, v1),
  86. binaryEntry(k2, v2),
  87. )
  88. k8sClient := clientfake.NewClientBuilder().Build()
  89. const authorizedKeySecretName = "authorizedKeySecretName"
  90. const authorizedKeySecretKey = "authorizedKeySecretKey"
  91. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey)
  92. tassert.Nil(t, err)
  93. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  94. provider := newLockboxProvider(&fake.YandexCloudCreator{
  95. Backend: lockboxBackend,
  96. })
  97. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  98. tassert.Nil(t, err)
  99. data, err := secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID})
  100. tassert.Nil(t, err)
  101. tassert.Equal(
  102. t,
  103. map[string]string{
  104. k1: v1,
  105. k2: base64(v2),
  106. },
  107. unmarshalStringMap(t, data),
  108. )
  109. }
  110. func TestGetSecretForTextEntry(t *testing.T) {
  111. ctx := context.Background()
  112. namespace := uuid.NewString()
  113. authorizedKey := newFakeAuthorizedKey()
  114. lockboxBackend := fake.NewLockboxBackend(time.Hour)
  115. k1, v1 := "k1", "v1"
  116. k2, v2 := "k2", []byte("v2")
  117. secretID, _ := lockboxBackend.CreateSecret(authorizedKey,
  118. textEntry(k1, v1),
  119. binaryEntry(k2, v2),
  120. )
  121. k8sClient := clientfake.NewClientBuilder().Build()
  122. const authorizedKeySecretName = "authorizedKeySecretName"
  123. const authorizedKeySecretKey = "authorizedKeySecretKey"
  124. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey)
  125. tassert.Nil(t, err)
  126. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  127. provider := newLockboxProvider(&fake.YandexCloudCreator{
  128. Backend: lockboxBackend,
  129. })
  130. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  131. tassert.Nil(t, err)
  132. data, err := secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Property: k1})
  133. tassert.Nil(t, err)
  134. tassert.Equal(t, v1, string(data))
  135. }
  136. func TestGetSecretForBinaryEntry(t *testing.T) {
  137. ctx := context.Background()
  138. namespace := uuid.NewString()
  139. authorizedKey := newFakeAuthorizedKey()
  140. lockboxBackend := fake.NewLockboxBackend(time.Hour)
  141. k1, v1 := "k1", "v1"
  142. k2, v2 := "k2", []byte("v2")
  143. secretID, _ := lockboxBackend.CreateSecret(authorizedKey,
  144. textEntry(k1, v1),
  145. binaryEntry(k2, v2),
  146. )
  147. k8sClient := clientfake.NewClientBuilder().Build()
  148. const authorizedKeySecretName = "authorizedKeySecretName"
  149. const authorizedKeySecretKey = "authorizedKeySecretKey"
  150. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey)
  151. tassert.Nil(t, err)
  152. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  153. provider := newLockboxProvider(&fake.YandexCloudCreator{
  154. Backend: lockboxBackend,
  155. })
  156. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  157. tassert.Nil(t, err)
  158. data, err := secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Property: k2})
  159. tassert.Nil(t, err)
  160. tassert.Equal(t, v2, data)
  161. }
  162. func TestGetSecretByVersionID(t *testing.T) {
  163. ctx := context.Background()
  164. namespace := uuid.NewString()
  165. authorizedKey := newFakeAuthorizedKey()
  166. lockboxBackend := fake.NewLockboxBackend(time.Hour)
  167. oldKey, oldVal := "oldKey", "oldVal"
  168. secretID, oldVersionID := lockboxBackend.CreateSecret(authorizedKey,
  169. textEntry(oldKey, oldVal),
  170. )
  171. k8sClient := clientfake.NewClientBuilder().Build()
  172. const authorizedKeySecretName = "authorizedKeySecretName"
  173. const authorizedKeySecretKey = "authorizedKeySecretKey"
  174. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey)
  175. tassert.Nil(t, err)
  176. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  177. provider := newLockboxProvider(&fake.YandexCloudCreator{
  178. Backend: lockboxBackend,
  179. })
  180. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  181. tassert.Nil(t, err)
  182. data, err := secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Version: oldVersionID})
  183. tassert.Nil(t, err)
  184. tassert.Equal(t, map[string]string{oldKey: oldVal}, unmarshalStringMap(t, data))
  185. newKey, newVal := "newKey", "newVal"
  186. newVersionID := lockboxBackend.AddVersion(secretID,
  187. textEntry(newKey, newVal),
  188. )
  189. data, err = secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Version: oldVersionID})
  190. tassert.Nil(t, err)
  191. tassert.Equal(t, map[string]string{oldKey: oldVal}, unmarshalStringMap(t, data))
  192. data, err = secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Version: newVersionID})
  193. tassert.Nil(t, err)
  194. tassert.Equal(t, map[string]string{newKey: newVal}, unmarshalStringMap(t, data))
  195. }
  196. func TestGetSecretUnauthorized(t *testing.T) {
  197. ctx := context.Background()
  198. namespace := uuid.NewString()
  199. authorizedKeyA := newFakeAuthorizedKey()
  200. authorizedKeyB := newFakeAuthorizedKey()
  201. lockboxBackend := fake.NewLockboxBackend(time.Hour)
  202. secretID, _ := lockboxBackend.CreateSecret(authorizedKeyA,
  203. textEntry("k1", "v1"),
  204. )
  205. k8sClient := clientfake.NewClientBuilder().Build()
  206. const authorizedKeySecretName = "authorizedKeySecretName"
  207. const authorizedKeySecretKey = "authorizedKeySecretKey"
  208. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, authorizedKeyB)
  209. tassert.Nil(t, err)
  210. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  211. provider := newLockboxProvider(&fake.YandexCloudCreator{
  212. Backend: lockboxBackend,
  213. })
  214. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  215. tassert.Nil(t, err)
  216. _, err = secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID})
  217. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  218. }
  219. func TestGetSecretNotFound(t *testing.T) {
  220. ctx := context.Background()
  221. namespace := uuid.NewString()
  222. authorizedKey := newFakeAuthorizedKey()
  223. lockboxBackend := fake.NewLockboxBackend(time.Hour)
  224. k8sClient := clientfake.NewClientBuilder().Build()
  225. const authorizedKeySecretName = "authorizedKeySecretName"
  226. const authorizedKeySecretKey = "authorizedKeySecretKey"
  227. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey)
  228. tassert.Nil(t, err)
  229. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  230. provider := newLockboxProvider(&fake.YandexCloudCreator{
  231. Backend: lockboxBackend,
  232. })
  233. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  234. tassert.Nil(t, err)
  235. _, err = secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: "no-secret-with-this-id"})
  236. tassert.EqualError(t, err, errSecretPayloadNotFound)
  237. secretID, _ := lockboxBackend.CreateSecret(authorizedKey,
  238. textEntry("k1", "v1"),
  239. )
  240. _, err = secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Version: "no-version-with-this-id"})
  241. tassert.EqualError(t, err, "unable to request secret payload to get secret: version not found")
  242. }
  243. func TestGetSecretWithTwoNamespaces(t *testing.T) {
  244. ctx := context.Background()
  245. namespace1 := uuid.NewString()
  246. namespace2 := uuid.NewString()
  247. authorizedKey1 := newFakeAuthorizedKey()
  248. authorizedKey2 := newFakeAuthorizedKey()
  249. lockboxBackend := fake.NewLockboxBackend(time.Hour)
  250. k1, v1 := "k1", "v1"
  251. secretID1, _ := lockboxBackend.CreateSecret(authorizedKey1,
  252. textEntry(k1, v1),
  253. )
  254. k2, v2 := "k2", "v2"
  255. secretID2, _ := lockboxBackend.CreateSecret(authorizedKey2,
  256. textEntry(k2, v2),
  257. )
  258. k8sClient := clientfake.NewClientBuilder().Build()
  259. const authorizedKeySecretName = "authorizedKeySecretName"
  260. const authorizedKeySecretKey = "authorizedKeySecretKey"
  261. err := createK8sSecret(ctx, k8sClient, namespace1, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey1)
  262. tassert.Nil(t, err)
  263. err = createK8sSecret(ctx, k8sClient, namespace2, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey2)
  264. tassert.Nil(t, err)
  265. store1 := newYandexLockboxSecretStore("", namespace1, authorizedKeySecretName, authorizedKeySecretKey)
  266. store2 := newYandexLockboxSecretStore("", namespace2, authorizedKeySecretName, authorizedKeySecretKey)
  267. provider := newLockboxProvider(&fake.YandexCloudCreator{
  268. Backend: lockboxBackend,
  269. })
  270. secretsClient1, err := provider.NewClient(ctx, store1, k8sClient, namespace1)
  271. tassert.Nil(t, err)
  272. secretsClient2, err := provider.NewClient(ctx, store2, k8sClient, namespace2)
  273. tassert.Nil(t, err)
  274. data, err := secretsClient1.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID1, Property: k1})
  275. tassert.Equal(t, v1, string(data))
  276. tassert.Nil(t, err)
  277. data, err = secretsClient1.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID2, Property: k2})
  278. tassert.Nil(t, data)
  279. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  280. data, err = secretsClient2.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID1, Property: k1})
  281. tassert.Nil(t, data)
  282. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  283. data, err = secretsClient2.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID2, Property: k2})
  284. tassert.Equal(t, v2, string(data))
  285. tassert.Nil(t, err)
  286. }
  287. func TestGetSecretWithTwoApiEndpoints(t *testing.T) {
  288. ctx := context.Background()
  289. apiEndpoint1 := uuid.NewString()
  290. apiEndpoint2 := uuid.NewString()
  291. namespace := uuid.NewString()
  292. authorizedKey1 := newFakeAuthorizedKey()
  293. authorizedKey2 := newFakeAuthorizedKey()
  294. lockboxBackend1 := fake.NewLockboxBackend(time.Hour)
  295. k1, v1 := "k1", "v1"
  296. secretID1, _ := lockboxBackend1.CreateSecret(authorizedKey1,
  297. textEntry(k1, v1),
  298. )
  299. lockboxBackend2 := fake.NewLockboxBackend(time.Hour)
  300. k2, v2 := "k2", "v2"
  301. secretID2, _ := lockboxBackend2.CreateSecret(authorizedKey2,
  302. textEntry(k2, v2),
  303. )
  304. k8sClient := clientfake.NewClientBuilder().Build()
  305. const authorizedKeySecretName1 = "authorizedKeySecretName1"
  306. const authorizedKeySecretKey1 = "authorizedKeySecretKey1"
  307. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName1, authorizedKeySecretKey1, authorizedKey1)
  308. tassert.Nil(t, err)
  309. const authorizedKeySecretName2 = "authorizedKeySecretName2"
  310. const authorizedKeySecretKey2 = "authorizedKeySecretKey2"
  311. err = createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName2, authorizedKeySecretKey2, authorizedKey2)
  312. tassert.Nil(t, err)
  313. store1 := newYandexLockboxSecretStore(apiEndpoint1, namespace, authorizedKeySecretName1, authorizedKeySecretKey1)
  314. store2 := newYandexLockboxSecretStore(apiEndpoint2, namespace, authorizedKeySecretName2, authorizedKeySecretKey2)
  315. provider1 := newLockboxProvider(&fake.YandexCloudCreator{
  316. Backend: lockboxBackend1,
  317. })
  318. provider2 := newLockboxProvider(&fake.YandexCloudCreator{
  319. Backend: lockboxBackend2,
  320. })
  321. secretsClient1, err := provider1.NewClient(ctx, store1, k8sClient, namespace)
  322. tassert.Nil(t, err)
  323. secretsClient2, err := provider2.NewClient(ctx, store2, k8sClient, namespace)
  324. tassert.Nil(t, err)
  325. var data []byte
  326. data, err = secretsClient1.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID1, Property: k1})
  327. tassert.Equal(t, v1, string(data))
  328. tassert.Nil(t, err)
  329. data, err = secretsClient1.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID2, Property: k2})
  330. tassert.Nil(t, data)
  331. tassert.EqualError(t, err, errSecretPayloadNotFound)
  332. data, err = secretsClient2.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID1, Property: k1})
  333. tassert.Nil(t, data)
  334. tassert.EqualError(t, err, errSecretPayloadNotFound)
  335. data, err = secretsClient2.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID2, Property: k2})
  336. tassert.Equal(t, v2, string(data))
  337. tassert.Nil(t, err)
  338. }
  339. func TestGetSecretWithIamTokenExpiration(t *testing.T) {
  340. ctx := context.Background()
  341. namespace := uuid.NewString()
  342. authorizedKey := newFakeAuthorizedKey()
  343. tokenExpirationTime := time.Hour
  344. lockboxBackend := fake.NewLockboxBackend(tokenExpirationTime)
  345. k1, v1 := "k1", "v1"
  346. secretID, _ := lockboxBackend.CreateSecret(authorizedKey,
  347. textEntry(k1, v1),
  348. )
  349. k8sClient := clientfake.NewClientBuilder().Build()
  350. const authorizedKeySecretName = "authorizedKeySecretName"
  351. const authorizedKeySecretKey = "authorizedKeySecretKey"
  352. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey)
  353. tassert.Nil(t, err)
  354. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  355. provider := newLockboxProvider(&fake.YandexCloudCreator{
  356. Backend: lockboxBackend,
  357. })
  358. var data []byte
  359. oldSecretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  360. tassert.Nil(t, err)
  361. data, err = oldSecretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Property: k1})
  362. tassert.Equal(t, v1, string(data))
  363. tassert.Nil(t, err)
  364. lockboxBackend.AdvanceClock(2 * tokenExpirationTime)
  365. data, err = oldSecretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Property: k1})
  366. tassert.Nil(t, data)
  367. tassert.EqualError(t, err, "unable to request secret payload to get secret: iam token expired")
  368. newSecretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  369. tassert.Nil(t, err)
  370. data, err = newSecretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Property: k1})
  371. tassert.Equal(t, v1, string(data))
  372. tassert.Nil(t, err)
  373. }
  374. func TestGetSecretWithIamTokenCleanup(t *testing.T) {
  375. ctx := context.Background()
  376. namespace := uuid.NewString()
  377. authorizedKey1 := newFakeAuthorizedKey()
  378. authorizedKey2 := newFakeAuthorizedKey()
  379. tokenExpirationDuration := time.Hour
  380. lockboxBackend := fake.NewLockboxBackend(tokenExpirationDuration)
  381. secretID1, _ := lockboxBackend.CreateSecret(authorizedKey1,
  382. textEntry("k1", "v1"),
  383. )
  384. secretID2, _ := lockboxBackend.CreateSecret(authorizedKey2,
  385. textEntry("k2", "v2"),
  386. )
  387. var err error
  388. k8sClient := clientfake.NewClientBuilder().Build()
  389. const authorizedKeySecretName1 = "authorizedKeySecretName1"
  390. const authorizedKeySecretKey1 = "authorizedKeySecretKey1"
  391. err = createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName1, authorizedKeySecretKey1, authorizedKey1)
  392. tassert.Nil(t, err)
  393. const authorizedKeySecretName2 = "authorizedKeySecretName2"
  394. const authorizedKeySecretKey2 = "authorizedKeySecretKey2"
  395. err = createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName2, authorizedKeySecretKey2, authorizedKey2)
  396. tassert.Nil(t, err)
  397. store1 := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName1, authorizedKeySecretKey1)
  398. store2 := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName2, authorizedKeySecretKey2)
  399. provider := newLockboxProvider(&fake.YandexCloudCreator{
  400. Backend: lockboxBackend,
  401. })
  402. tassert.False(t, provider.isIamTokenCached(authorizedKey1))
  403. tassert.False(t, provider.isIamTokenCached(authorizedKey2))
  404. // Access secretID1 with authorizedKey1, IAM token for authorizedKey1 should be cached
  405. secretsClient, err := provider.NewClient(ctx, store1, k8sClient, namespace)
  406. tassert.Nil(t, err)
  407. _, err = secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID1})
  408. tassert.Nil(t, err)
  409. tassert.True(t, provider.isIamTokenCached(authorizedKey1))
  410. tassert.False(t, provider.isIamTokenCached(authorizedKey2))
  411. lockboxBackend.AdvanceClock(tokenExpirationDuration * 2)
  412. // Access secretID2 with authorizedKey2, IAM token for authorizedKey2 should be cached
  413. secretsClient, err = provider.NewClient(ctx, store2, k8sClient, namespace)
  414. tassert.Nil(t, err)
  415. _, err = secretsClient.GetSecret(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID2})
  416. tassert.Nil(t, err)
  417. tassert.True(t, provider.isIamTokenCached(authorizedKey1))
  418. tassert.True(t, provider.isIamTokenCached(authorizedKey2))
  419. lockboxBackend.AdvanceClock(tokenExpirationDuration)
  420. tassert.True(t, provider.isIamTokenCached(authorizedKey1))
  421. tassert.True(t, provider.isIamTokenCached(authorizedKey2))
  422. provider.cleanUpIamTokenMap()
  423. tassert.False(t, provider.isIamTokenCached(authorizedKey1))
  424. tassert.True(t, provider.isIamTokenCached(authorizedKey2))
  425. lockboxBackend.AdvanceClock(tokenExpirationDuration)
  426. tassert.False(t, provider.isIamTokenCached(authorizedKey1))
  427. tassert.True(t, provider.isIamTokenCached(authorizedKey2))
  428. provider.cleanUpIamTokenMap()
  429. tassert.False(t, provider.isIamTokenCached(authorizedKey1))
  430. tassert.False(t, provider.isIamTokenCached(authorizedKey2))
  431. }
  432. func TestGetSecretMap(t *testing.T) {
  433. ctx := context.Background()
  434. namespace := uuid.NewString()
  435. authorizedKey := newFakeAuthorizedKey()
  436. lockboxBackend := fake.NewLockboxBackend(time.Hour)
  437. k1, v1 := "k1", "v1"
  438. k2, v2 := "k2", []byte("v2")
  439. secretID, _ := lockboxBackend.CreateSecret(authorizedKey,
  440. textEntry(k1, v1),
  441. binaryEntry(k2, v2),
  442. )
  443. k8sClient := clientfake.NewClientBuilder().Build()
  444. const authorizedKeySecretName = "authorizedKeySecretName"
  445. const authorizedKeySecretKey = "authorizedKeySecretKey"
  446. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey)
  447. tassert.Nil(t, err)
  448. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  449. provider := newLockboxProvider(&fake.YandexCloudCreator{
  450. Backend: lockboxBackend,
  451. })
  452. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  453. tassert.Nil(t, err)
  454. data, err := secretsClient.GetSecretMap(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID})
  455. tassert.Nil(t, err)
  456. tassert.Equal(
  457. t,
  458. map[string][]byte{
  459. k1: []byte(v1),
  460. k2: v2,
  461. },
  462. data,
  463. )
  464. }
  465. func TestGetSecretMapByVersionID(t *testing.T) {
  466. ctx := context.Background()
  467. namespace := uuid.NewString()
  468. authorizedKey := newFakeAuthorizedKey()
  469. lockboxBackend := fake.NewLockboxBackend(time.Hour)
  470. oldKey, oldVal := "oldKey", "oldVal"
  471. secretID, oldVersionID := lockboxBackend.CreateSecret(authorizedKey,
  472. textEntry(oldKey, oldVal),
  473. )
  474. k8sClient := clientfake.NewClientBuilder().Build()
  475. const authorizedKeySecretName = "authorizedKeySecretName"
  476. const authorizedKeySecretKey = "authorizedKeySecretKey"
  477. err := createK8sSecret(ctx, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, authorizedKey)
  478. tassert.Nil(t, err)
  479. store := newYandexLockboxSecretStore("", namespace, authorizedKeySecretName, authorizedKeySecretKey)
  480. provider := newLockboxProvider(&fake.YandexCloudCreator{
  481. Backend: lockboxBackend,
  482. })
  483. secretsClient, err := provider.NewClient(ctx, store, k8sClient, namespace)
  484. tassert.Nil(t, err)
  485. data, err := secretsClient.GetSecretMap(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Version: oldVersionID})
  486. tassert.Nil(t, err)
  487. tassert.Equal(t, map[string][]byte{oldKey: []byte(oldVal)}, data)
  488. newKey, newVal := "newKey", "newVal"
  489. newVersionID := lockboxBackend.AddVersion(secretID,
  490. textEntry(newKey, newVal),
  491. )
  492. data, err = secretsClient.GetSecretMap(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Version: oldVersionID})
  493. tassert.Nil(t, err)
  494. tassert.Equal(t, map[string][]byte{oldKey: []byte(oldVal)}, data)
  495. data, err = secretsClient.GetSecretMap(ctx, esv1alpha1.ExternalSecretDataRemoteRef{Key: secretID, Version: newVersionID})
  496. tassert.Nil(t, err)
  497. tassert.Equal(t, map[string][]byte{newKey: []byte(newVal)}, data)
  498. }
  499. // helper functions
  500. func newYandexLockboxSecretStore(apiEndpoint, namespace, authorizedKeySecretName, authorizedKeySecretKey string) esv1alpha1.GenericStore {
  501. return &esv1alpha1.SecretStore{
  502. ObjectMeta: metav1.ObjectMeta{
  503. Namespace: namespace,
  504. },
  505. Spec: esv1alpha1.SecretStoreSpec{
  506. Provider: &esv1alpha1.SecretStoreProvider{
  507. YandexLockbox: &esv1alpha1.YandexLockboxProvider{
  508. APIEndpoint: apiEndpoint,
  509. Auth: esv1alpha1.YandexLockboxAuth{
  510. AuthorizedKey: esmeta.SecretKeySelector{
  511. Name: authorizedKeySecretName,
  512. Key: authorizedKeySecretKey,
  513. },
  514. },
  515. },
  516. },
  517. },
  518. }
  519. }
  520. func createK8sSecret(ctx context.Context, k8sClient client.Client, namespace, secretName, secretKey string, secretContent interface{}) error {
  521. data, err := json.Marshal(secretContent)
  522. if err != nil {
  523. return err
  524. }
  525. err = k8sClient.Create(ctx, &corev1.Secret{
  526. ObjectMeta: metav1.ObjectMeta{
  527. Namespace: namespace,
  528. Name: secretName,
  529. },
  530. Data: map[string][]byte{secretKey: data},
  531. })
  532. if err != nil {
  533. return err
  534. }
  535. return nil
  536. }
  537. func newFakeAuthorizedKey() *iamkey.Key {
  538. uniqueLabel := uuid.NewString()
  539. return &iamkey.Key{
  540. Id: uniqueLabel,
  541. Subject: &iamkey.Key_ServiceAccountId{
  542. ServiceAccountId: uniqueLabel,
  543. },
  544. PrivateKey: uniqueLabel,
  545. }
  546. }
  547. func textEntry(key, value string) *lockbox.Payload_Entry {
  548. return &lockbox.Payload_Entry{
  549. Key: key,
  550. Value: &lockbox.Payload_Entry_TextValue{
  551. TextValue: value,
  552. },
  553. }
  554. }
  555. func binaryEntry(key string, value []byte) *lockbox.Payload_Entry {
  556. return &lockbox.Payload_Entry{
  557. Key: key,
  558. Value: &lockbox.Payload_Entry_BinaryValue{
  559. BinaryValue: value,
  560. },
  561. }
  562. }
  563. func unmarshalStringMap(t *testing.T, data []byte) map[string]string {
  564. stringMap := make(map[string]string)
  565. err := json.Unmarshal(data, &stringMap)
  566. tassert.Nil(t, err)
  567. return stringMap
  568. }
  569. func base64(data []byte) string {
  570. return b64.StdEncoding.EncodeToString(data)
  571. }