lockbox_test.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  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, getRemoteDef(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, getRemoteDef(secretID, 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, getRemoteDef(secretID, 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, getRemoteDef(secretID, "", 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, getRemoteDef(secretID, "", oldVersionID))
  206. tassert.Nil(t, err)
  207. tassert.Equal(t, map[string]string{oldKey: oldVal}, unmarshalStringMap(t, data))
  208. data, err = secretsClient.GetSecret(ctx, getRemoteDef(secretID, "", 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, getRemoteDef(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, getRemoteDef("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, getRemoteDef(secretID, "", "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, getRemoteDef(secretID1, k1, ""))
  291. tassert.Equal(t, v1, string(data))
  292. tassert.Nil(t, err)
  293. data, err = secretsClient1.GetSecret(ctx, getRemoteDef(secretID2, k2, ""))
  294. tassert.Nil(t, data)
  295. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  296. data, err = secretsClient2.GetSecret(ctx, getRemoteDef(secretID1, k1, ""))
  297. tassert.Nil(t, data)
  298. tassert.EqualError(t, err, errSecretPayloadPermissionDenied)
  299. data, err = secretsClient2.GetSecret(ctx, getRemoteDef(secretID2, 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, getRemoteDef(secretID1, k1, ""))
  343. tassert.Equal(t, v1, string(data))
  344. tassert.Nil(t, err)
  345. data, err = secretsClient1.GetSecret(ctx, getRemoteDef(secretID2, k2, ""))
  346. tassert.Nil(t, data)
  347. tassert.EqualError(t, err, errSecretPayloadNotFound)
  348. data, err = secretsClient2.GetSecret(ctx, getRemoteDef(secretID1, k1, ""))
  349. tassert.Nil(t, data)
  350. tassert.EqualError(t, err, errSecretPayloadNotFound)
  351. data, err = secretsClient2.GetSecret(ctx, getRemoteDef(secretID2, 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, getRemoteDef(secretID, k1, ""))
  378. tassert.Equal(t, v1, string(data))
  379. tassert.Nil(t, err)
  380. lockboxBackend.AdvanceClock(2 * tokenExpirationTime)
  381. data, err = oldSecretsClient.GetSecret(ctx, getRemoteDef(secretID, 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, getRemoteDef(secretID, 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, getRemoteDef(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, getRemoteDef(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, getRemoteFromDef(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, getRemoteFromDef(secretID, "", 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, getRemoteFromDef(secretID, "", oldVersionID))
  509. tassert.Nil(t, err)
  510. tassert.Equal(t, map[string][]byte{oldKey: []byte(oldVal)}, data)
  511. data, err = secretsClient.GetSecretMap(ctx, getRemoteFromDef(secretID, "", 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 getRemoteDef(key, property, version string) esv1alpha1.ExternalSecretDataRemoteRef {
  537. return esv1alpha1.ExternalSecretDataRemoteRef{
  538. Key: key,
  539. Property: property,
  540. Version: version,
  541. }
  542. }
  543. func getRemoteFromDef(key, property, version string) esv1alpha1.ExternalSecretDataFromRemoteRef {
  544. return esv1alpha1.ExternalSecretDataFromRemoteRef{
  545. Extract: esv1alpha1.ExternalSecretExtract{
  546. Key: key,
  547. Property: property,
  548. Version: version,
  549. },
  550. }
  551. }
  552. func createK8sSecret(ctx context.Context, k8sClient client.Client, namespace, secretName, secretKey string, secretContent interface{}) error {
  553. data, err := json.Marshal(secretContent)
  554. if err != nil {
  555. return err
  556. }
  557. err = k8sClient.Create(ctx, &corev1.Secret{
  558. ObjectMeta: metav1.ObjectMeta{
  559. Namespace: namespace,
  560. Name: secretName,
  561. },
  562. Data: map[string][]byte{secretKey: data},
  563. })
  564. if err != nil {
  565. return err
  566. }
  567. return nil
  568. }
  569. func newFakeAuthorizedKey() *iamkey.Key {
  570. uniqueLabel := uuid.NewString()
  571. return &iamkey.Key{
  572. Id: uniqueLabel,
  573. Subject: &iamkey.Key_ServiceAccountId{
  574. ServiceAccountId: uniqueLabel,
  575. },
  576. PrivateKey: uniqueLabel,
  577. }
  578. }
  579. func newFakeCACertificate() []byte {
  580. cert := x509.Certificate{
  581. SerialNumber: big.NewInt(2019),
  582. Subject: pkix.Name{
  583. Organization: []string{"Company, INC."},
  584. Country: []string{"US"},
  585. Locality: []string{"San Francisco"},
  586. StreetAddress: []string{"Golden Gate Bridge"},
  587. PostalCode: []string{"94016"},
  588. },
  589. NotBefore: time.Now(),
  590. NotAfter: time.Now().AddDate(10, 0, 0),
  591. IsCA: true,
  592. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
  593. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
  594. BasicConstraintsValid: true,
  595. }
  596. return cert.Raw
  597. }
  598. func textEntry(key, value string) *lockbox.Payload_Entry {
  599. return &lockbox.Payload_Entry{
  600. Key: key,
  601. Value: &lockbox.Payload_Entry_TextValue{
  602. TextValue: value,
  603. },
  604. }
  605. }
  606. func binaryEntry(key string, value []byte) *lockbox.Payload_Entry {
  607. return &lockbox.Payload_Entry{
  608. Key: key,
  609. Value: &lockbox.Payload_Entry_BinaryValue{
  610. BinaryValue: value,
  611. },
  612. }
  613. }
  614. func unmarshalStringMap(t *testing.T, data []byte) map[string]string {
  615. stringMap := make(map[string]string)
  616. err := json.Unmarshal(data, &stringMap)
  617. tassert.Nil(t, err)
  618. return stringMap
  619. }
  620. func base64(data []byte) string {
  621. return b64.StdEncoding.EncodeToString(data)
  622. }