lockbox_test.go 26 KB

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