lockbox_test.go 26 KB

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