secretsmanager_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  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 secretsmanager
  13. import (
  14. "context"
  15. "fmt"
  16. "os"
  17. "strings"
  18. "testing"
  19. "time"
  20. "github.com/aws/aws-sdk-go/aws"
  21. "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
  22. "github.com/aws/aws-sdk-go/aws/session"
  23. awssm "github.com/aws/aws-sdk-go/service/secretsmanager"
  24. "github.com/aws/aws-sdk-go/service/sts"
  25. "github.com/google/go-cmp/cmp"
  26. "github.com/stretchr/testify/assert"
  27. v1 "k8s.io/api/core/v1"
  28. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  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. awsprovider "github.com/external-secrets/external-secrets/pkg/provider/aws"
  33. fakesm "github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager/fake"
  34. )
  35. func TestConstructor(t *testing.T) {
  36. rows := []ConstructorRow{
  37. {
  38. name: "nil store",
  39. expectErr: "found nil store",
  40. store: nil,
  41. },
  42. {
  43. name: "not store spec",
  44. expectErr: "storeSpec is missing provider",
  45. store: &esv1alpha1.SecretStore{},
  46. },
  47. {
  48. name: "store spec has no provider",
  49. expectErr: "storeSpec is missing provider",
  50. store: &esv1alpha1.SecretStore{
  51. Spec: esv1alpha1.SecretStoreSpec{},
  52. },
  53. },
  54. {
  55. name: "spec has no awssm field",
  56. expectErr: "Missing AWSSM field",
  57. store: &esv1alpha1.SecretStore{
  58. Spec: esv1alpha1.SecretStoreSpec{
  59. Provider: &esv1alpha1.SecretStoreProvider{},
  60. },
  61. },
  62. },
  63. {
  64. name: "configure aws using environment variables",
  65. store: &esv1alpha1.SecretStore{
  66. Spec: esv1alpha1.SecretStoreSpec{
  67. Provider: &esv1alpha1.SecretStoreProvider{
  68. AWSSM: &esv1alpha1.AWSSMProvider{},
  69. },
  70. },
  71. },
  72. env: map[string]string{
  73. "AWS_ACCESS_KEY_ID": "1111",
  74. "AWS_SECRET_ACCESS_KEY": "2222",
  75. },
  76. expectProvider: true,
  77. expectedKeyID: "1111",
  78. expectedSecretKey: "2222",
  79. },
  80. {
  81. name: "configure aws using environment variables + assume role",
  82. stsProvider: func(*session.Session) stscreds.AssumeRoler {
  83. return &fakesm.AssumeRoler{
  84. AssumeRoleFunc: func(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
  85. assert.Equal(t, *input.RoleArn, "foo-bar-baz")
  86. return &sts.AssumeRoleOutput{
  87. AssumedRoleUser: &sts.AssumedRoleUser{
  88. Arn: aws.String("1123132"),
  89. AssumedRoleId: aws.String("xxxxx"),
  90. },
  91. Credentials: &sts.Credentials{
  92. AccessKeyId: aws.String("3333"),
  93. SecretAccessKey: aws.String("4444"),
  94. Expiration: aws.Time(time.Now().Add(time.Hour)),
  95. SessionToken: aws.String("6666"),
  96. },
  97. }, nil
  98. },
  99. }
  100. },
  101. store: &esv1alpha1.SecretStore{
  102. Spec: esv1alpha1.SecretStoreSpec{
  103. Provider: &esv1alpha1.SecretStoreProvider{
  104. AWSSM: &esv1alpha1.AWSSMProvider{
  105. Role: "foo-bar-baz",
  106. },
  107. },
  108. },
  109. },
  110. env: map[string]string{
  111. "AWS_ACCESS_KEY_ID": "1111",
  112. "AWS_SECRET_ACCESS_KEY": "2222",
  113. },
  114. expectProvider: true,
  115. expectedKeyID: "3333",
  116. expectedSecretKey: "4444",
  117. },
  118. {
  119. name: "error out when secret with credentials does not exist",
  120. namespace: "foo",
  121. store: &esv1alpha1.SecretStore{
  122. Spec: esv1alpha1.SecretStoreSpec{
  123. Provider: &esv1alpha1.SecretStoreProvider{
  124. AWSSM: &esv1alpha1.AWSSMProvider{
  125. Auth: &esv1alpha1.AWSSMAuth{
  126. SecretRef: esv1alpha1.AWSSMAuthSecretRef{
  127. AccessKeyID: esmeta.SecretKeySelector{
  128. Name: "othersecret",
  129. Key: "one",
  130. },
  131. SecretAccessKey: esmeta.SecretKeySelector{
  132. Name: "othersecret",
  133. Key: "two",
  134. },
  135. },
  136. },
  137. },
  138. },
  139. },
  140. },
  141. expectErr: `secrets "othersecret" not found`,
  142. },
  143. {
  144. name: "use credentials from secret to configure aws",
  145. namespace: "foo",
  146. store: &esv1alpha1.SecretStore{
  147. Spec: esv1alpha1.SecretStoreSpec{
  148. Provider: &esv1alpha1.SecretStoreProvider{
  149. AWSSM: &esv1alpha1.AWSSMProvider{
  150. Auth: &esv1alpha1.AWSSMAuth{
  151. SecretRef: esv1alpha1.AWSSMAuthSecretRef{
  152. AccessKeyID: esmeta.SecretKeySelector{
  153. Name: "onesecret",
  154. // Namespace is not set
  155. Key: "one",
  156. },
  157. SecretAccessKey: esmeta.SecretKeySelector{
  158. Name: "onesecret",
  159. // Namespace is not set
  160. Key: "two",
  161. },
  162. },
  163. },
  164. },
  165. },
  166. },
  167. },
  168. secrets: []v1.Secret{
  169. {
  170. ObjectMeta: metav1.ObjectMeta{
  171. Name: "onesecret",
  172. Namespace: "foo",
  173. },
  174. Data: map[string][]byte{
  175. "one": []byte("1111"),
  176. "two": []byte("2222"),
  177. },
  178. },
  179. },
  180. expectProvider: true,
  181. expectedKeyID: "1111",
  182. expectedSecretKey: "2222",
  183. },
  184. {
  185. name: "error out when secret key does not exist",
  186. namespace: "foo",
  187. store: &esv1alpha1.SecretStore{
  188. Spec: esv1alpha1.SecretStoreSpec{
  189. Provider: &esv1alpha1.SecretStoreProvider{
  190. AWSSM: &esv1alpha1.AWSSMProvider{
  191. Auth: &esv1alpha1.AWSSMAuth{
  192. SecretRef: esv1alpha1.AWSSMAuthSecretRef{
  193. AccessKeyID: esmeta.SecretKeySelector{
  194. Name: "brokensecret",
  195. Key: "one",
  196. },
  197. SecretAccessKey: esmeta.SecretKeySelector{
  198. Name: "brokensecret",
  199. Key: "two",
  200. },
  201. },
  202. },
  203. },
  204. },
  205. },
  206. },
  207. secrets: []v1.Secret{
  208. {
  209. ObjectMeta: metav1.ObjectMeta{
  210. Name: "brokensecret",
  211. Namespace: "foo",
  212. },
  213. Data: map[string][]byte{},
  214. },
  215. },
  216. expectErr: "missing SecretAccessKey",
  217. },
  218. {
  219. name: "should not be able to access secrets from different namespace",
  220. namespace: "foo",
  221. store: &esv1alpha1.SecretStore{
  222. Spec: esv1alpha1.SecretStoreSpec{
  223. Provider: &esv1alpha1.SecretStoreProvider{
  224. AWSSM: &esv1alpha1.AWSSMProvider{
  225. Auth: &esv1alpha1.AWSSMAuth{
  226. SecretRef: esv1alpha1.AWSSMAuthSecretRef{
  227. AccessKeyID: esmeta.SecretKeySelector{
  228. Name: "onesecret",
  229. Namespace: aws.String("evil"), // this should not be possible!
  230. Key: "one",
  231. },
  232. SecretAccessKey: esmeta.SecretKeySelector{
  233. Name: "onesecret",
  234. Namespace: aws.String("evil"),
  235. Key: "two",
  236. },
  237. },
  238. },
  239. },
  240. },
  241. },
  242. },
  243. secrets: []v1.Secret{
  244. {
  245. ObjectMeta: metav1.ObjectMeta{
  246. Name: "onesecret",
  247. Namespace: "evil",
  248. },
  249. Data: map[string][]byte{
  250. "one": []byte("1111"),
  251. "two": []byte("2222"),
  252. },
  253. },
  254. },
  255. expectErr: `secrets "onesecret" not found`,
  256. },
  257. {
  258. name: "ClusterStore should use credentials from a specific namespace",
  259. namespace: "es-namespace",
  260. store: &esv1alpha1.ClusterSecretStore{
  261. TypeMeta: metav1.TypeMeta{
  262. APIVersion: esv1alpha1.ClusterSecretStoreKindAPIVersion,
  263. Kind: esv1alpha1.ClusterSecretStoreKind,
  264. },
  265. Spec: esv1alpha1.SecretStoreSpec{
  266. Provider: &esv1alpha1.SecretStoreProvider{
  267. AWSSM: &esv1alpha1.AWSSMProvider{
  268. Auth: &esv1alpha1.AWSSMAuth{
  269. SecretRef: esv1alpha1.AWSSMAuthSecretRef{
  270. AccessKeyID: esmeta.SecretKeySelector{
  271. Name: "onesecret",
  272. Namespace: aws.String("platform-team-ns"),
  273. Key: "one",
  274. },
  275. SecretAccessKey: esmeta.SecretKeySelector{
  276. Name: "onesecret",
  277. Namespace: aws.String("platform-team-ns"),
  278. Key: "two",
  279. },
  280. },
  281. },
  282. },
  283. },
  284. },
  285. },
  286. secrets: []v1.Secret{
  287. {
  288. ObjectMeta: metav1.ObjectMeta{
  289. Name: "onesecret",
  290. Namespace: "platform-team-ns",
  291. },
  292. Data: map[string][]byte{
  293. "one": []byte("1111"),
  294. "two": []byte("2222"),
  295. },
  296. },
  297. },
  298. expectProvider: true,
  299. expectedKeyID: "1111",
  300. expectedSecretKey: "2222",
  301. },
  302. {
  303. name: "namespace is mandatory when using ClusterStore with SecretKeySelector",
  304. namespace: "es-namespace",
  305. store: &esv1alpha1.ClusterSecretStore{
  306. TypeMeta: metav1.TypeMeta{
  307. APIVersion: esv1alpha1.ClusterSecretStoreKindAPIVersion,
  308. Kind: esv1alpha1.ClusterSecretStoreKind,
  309. },
  310. Spec: esv1alpha1.SecretStoreSpec{
  311. Provider: &esv1alpha1.SecretStoreProvider{
  312. AWSSM: &esv1alpha1.AWSSMProvider{
  313. Auth: &esv1alpha1.AWSSMAuth{
  314. SecretRef: esv1alpha1.AWSSMAuthSecretRef{
  315. AccessKeyID: esmeta.SecretKeySelector{
  316. Name: "onesecret",
  317. Key: "one",
  318. },
  319. SecretAccessKey: esmeta.SecretKeySelector{
  320. Name: "onesecret",
  321. Key: "two",
  322. },
  323. },
  324. },
  325. },
  326. },
  327. },
  328. },
  329. expectErr: "invalid ClusterSecretStore: missing AWSSM AccessKeyID Namespace",
  330. },
  331. }
  332. for i := range rows {
  333. row := rows[i]
  334. t.Run(row.name, func(t *testing.T) {
  335. testRow(t, row)
  336. })
  337. }
  338. }
  339. type ConstructorRow struct {
  340. name string
  341. store esv1alpha1.GenericStore
  342. secrets []v1.Secret
  343. namespace string
  344. stsProvider awsprovider.STSProvider
  345. expectProvider bool
  346. expectErr string
  347. expectedKeyID string
  348. expectedSecretKey string
  349. env map[string]string
  350. }
  351. func testRow(t *testing.T, row ConstructorRow) {
  352. kc := clientfake.NewClientBuilder().Build()
  353. for i := range row.secrets {
  354. err := kc.Create(context.Background(), &row.secrets[i])
  355. assert.Nil(t, err)
  356. }
  357. for k, v := range row.env {
  358. os.Setenv(k, v)
  359. }
  360. defer func() {
  361. for k := range row.env {
  362. os.Unsetenv(k)
  363. }
  364. }()
  365. sm := SecretsManager{
  366. stsProvider: row.stsProvider,
  367. }
  368. newsm, err := sm.New(context.Background(), row.store, kc, row.namespace)
  369. if !ErrorContains(err, row.expectErr) {
  370. t.Errorf("expected error %s but found %s", row.expectErr, err.Error())
  371. }
  372. // pass test on expected error
  373. if err != nil {
  374. return
  375. }
  376. if row.expectProvider && newsm == nil {
  377. t.Errorf("expected provider object, found nil")
  378. return
  379. }
  380. creds, _ := newsm.(*SecretsManager).session.Config.Credentials.Get()
  381. assert.Equal(t, creds.AccessKeyID, row.expectedKeyID)
  382. assert.Equal(t, creds.SecretAccessKey, row.expectedSecretKey)
  383. }
  384. func TestSMEnvCredentials(t *testing.T) {
  385. k8sClient := clientfake.NewClientBuilder().Build()
  386. sm := &SecretsManager{}
  387. os.Setenv("AWS_SECRET_ACCESS_KEY", "1111")
  388. os.Setenv("AWS_ACCESS_KEY_ID", "2222")
  389. defer os.Unsetenv("AWS_SECRET_ACCESS_KEY")
  390. defer os.Unsetenv("AWS_ACCESS_KEY_ID")
  391. smi, err := sm.New(context.Background(), &esv1alpha1.SecretStore{
  392. Spec: esv1alpha1.SecretStoreSpec{
  393. Provider: &esv1alpha1.SecretStoreProvider{
  394. // defaults
  395. AWSSM: &esv1alpha1.AWSSMProvider{},
  396. },
  397. },
  398. }, k8sClient, "example-ns")
  399. assert.Nil(t, err)
  400. assert.NotNil(t, smi)
  401. creds, err := sm.session.Config.Credentials.Get()
  402. assert.Nil(t, err)
  403. assert.Equal(t, creds.AccessKeyID, "2222")
  404. assert.Equal(t, creds.SecretAccessKey, "1111")
  405. }
  406. func TestSMAssumeRole(t *testing.T) {
  407. k8sClient := clientfake.NewClientBuilder().Build()
  408. sts := &fakesm.AssumeRoler{
  409. AssumeRoleFunc: func(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
  410. // make sure the correct role is passed in
  411. assert.Equal(t, *input.RoleArn, "my-awesome-role")
  412. return &sts.AssumeRoleOutput{
  413. AssumedRoleUser: &sts.AssumedRoleUser{
  414. Arn: aws.String("1123132"),
  415. AssumedRoleId: aws.String("xxxxx"),
  416. },
  417. Credentials: &sts.Credentials{
  418. AccessKeyId: aws.String("3333"),
  419. SecretAccessKey: aws.String("4444"),
  420. Expiration: aws.Time(time.Now().Add(time.Hour)),
  421. SessionToken: aws.String("6666"),
  422. },
  423. }, nil
  424. },
  425. }
  426. sm := &SecretsManager{
  427. stsProvider: func(se *session.Session) stscreds.AssumeRoler {
  428. // check if the correct temporary credentials were used
  429. creds, err := se.Config.Credentials.Get()
  430. assert.Nil(t, err)
  431. assert.Equal(t, creds.AccessKeyID, "2222")
  432. assert.Equal(t, creds.SecretAccessKey, "1111")
  433. return sts
  434. },
  435. }
  436. os.Setenv("AWS_SECRET_ACCESS_KEY", "1111")
  437. os.Setenv("AWS_ACCESS_KEY_ID", "2222")
  438. defer os.Unsetenv("AWS_SECRET_ACCESS_KEY")
  439. defer os.Unsetenv("AWS_ACCESS_KEY_ID")
  440. smi, err := sm.New(context.Background(), &esv1alpha1.SecretStore{
  441. Spec: esv1alpha1.SecretStoreSpec{
  442. Provider: &esv1alpha1.SecretStoreProvider{
  443. // do assume role!
  444. AWSSM: &esv1alpha1.AWSSMProvider{
  445. Role: "my-awesome-role",
  446. },
  447. },
  448. },
  449. }, k8sClient, "example-ns")
  450. assert.Nil(t, err)
  451. assert.NotNil(t, smi)
  452. creds, err := sm.session.Config.Credentials.Get()
  453. assert.Nil(t, err)
  454. assert.Equal(t, creds.AccessKeyID, "3333")
  455. assert.Equal(t, creds.SecretAccessKey, "4444")
  456. }
  457. // test the sm<->aws interface
  458. // make sure correct values are passed and errors are handled accordingly.
  459. func TestGetSecret(t *testing.T) {
  460. fake := &fakesm.Client{}
  461. p := &SecretsManager{
  462. client: fake,
  463. }
  464. for i, row := range []struct {
  465. apiInput *awssm.GetSecretValueInput
  466. apiOutput *awssm.GetSecretValueOutput
  467. rr esv1alpha1.ExternalSecretDataRemoteRef
  468. apiErr error
  469. expectError string
  470. expectedSecret string
  471. }{
  472. {
  473. // good case: default version is set
  474. // key is passed in, output is sent back
  475. apiInput: &awssm.GetSecretValueInput{
  476. SecretId: aws.String("/baz"),
  477. VersionStage: aws.String("AWSCURRENT"),
  478. },
  479. rr: esv1alpha1.ExternalSecretDataRemoteRef{
  480. Key: "/baz",
  481. },
  482. apiOutput: &awssm.GetSecretValueOutput{
  483. SecretString: aws.String("RRRRR"),
  484. },
  485. apiErr: nil,
  486. expectError: "",
  487. expectedSecret: "RRRRR",
  488. },
  489. {
  490. // good case: extract property
  491. apiInput: &awssm.GetSecretValueInput{
  492. SecretId: aws.String("/baz"),
  493. VersionStage: aws.String("AWSCURRENT"),
  494. },
  495. rr: esv1alpha1.ExternalSecretDataRemoteRef{
  496. Key: "/baz",
  497. Property: "/shmoo",
  498. },
  499. apiOutput: &awssm.GetSecretValueOutput{
  500. SecretString: aws.String(`{"/shmoo": "bang"}`),
  501. },
  502. apiErr: nil,
  503. expectError: "",
  504. expectedSecret: "bang",
  505. },
  506. {
  507. // bad case: missing property
  508. apiInput: &awssm.GetSecretValueInput{
  509. SecretId: aws.String("/baz"),
  510. VersionStage: aws.String("AWSCURRENT"),
  511. },
  512. rr: esv1alpha1.ExternalSecretDataRemoteRef{
  513. Key: "/baz",
  514. Property: "DOES NOT EXIST",
  515. },
  516. apiOutput: &awssm.GetSecretValueOutput{
  517. SecretString: aws.String(`{"/shmoo": "bang"}`),
  518. },
  519. apiErr: nil,
  520. expectError: "has no property",
  521. expectedSecret: "",
  522. },
  523. {
  524. // bad case: extract property failure due to invalid json
  525. apiInput: &awssm.GetSecretValueInput{
  526. SecretId: aws.String("/baz"),
  527. VersionStage: aws.String("AWSCURRENT"),
  528. },
  529. rr: esv1alpha1.ExternalSecretDataRemoteRef{
  530. Key: "/baz",
  531. Property: "/shmoo",
  532. },
  533. apiOutput: &awssm.GetSecretValueOutput{
  534. SecretString: aws.String(`------`),
  535. },
  536. apiErr: nil,
  537. expectError: "unable to unmarshal secret",
  538. expectedSecret: "",
  539. },
  540. {
  541. // should pass version
  542. apiInput: &awssm.GetSecretValueInput{
  543. SecretId: aws.String("/foo/bar"),
  544. VersionStage: aws.String("1234"),
  545. },
  546. rr: esv1alpha1.ExternalSecretDataRemoteRef{
  547. Key: "/foo/bar",
  548. Version: "1234",
  549. },
  550. apiOutput: &awssm.GetSecretValueOutput{
  551. SecretString: aws.String("FOOBA!"),
  552. },
  553. apiErr: nil,
  554. expectError: "",
  555. expectedSecret: "FOOBA!",
  556. },
  557. {
  558. // should return err
  559. apiInput: &awssm.GetSecretValueInput{
  560. SecretId: aws.String("/foo/bar"),
  561. VersionStage: aws.String("AWSCURRENT"),
  562. },
  563. rr: esv1alpha1.ExternalSecretDataRemoteRef{
  564. Key: "/foo/bar",
  565. },
  566. apiOutput: &awssm.GetSecretValueOutput{},
  567. apiErr: fmt.Errorf("oh no"),
  568. expectError: "oh no",
  569. },
  570. } {
  571. fake.WithValue(row.apiInput, row.apiOutput, row.apiErr)
  572. out, err := p.GetSecret(context.Background(), row.rr)
  573. if !ErrorContains(err, row.expectError) {
  574. t.Errorf("[%d] unexpected error: %s, expected: '%s'", i, err.Error(), row.expectError)
  575. }
  576. if string(out) != row.expectedSecret {
  577. t.Errorf("[%d] unexpected secret: expected %s, got %s", i, row.expectedSecret, string(out))
  578. }
  579. }
  580. }
  581. func TestGetSecretMap(t *testing.T) {
  582. fake := &fakesm.Client{}
  583. p := &SecretsManager{
  584. client: fake,
  585. }
  586. for i, row := range []struct {
  587. apiInput *awssm.GetSecretValueInput
  588. apiOutput *awssm.GetSecretValueOutput
  589. rr esv1alpha1.ExternalSecretDataRemoteRef
  590. expectedData map[string]string
  591. apiErr error
  592. expectError string
  593. }{
  594. {
  595. // good case: default version & deserialization
  596. apiInput: &awssm.GetSecretValueInput{
  597. SecretId: aws.String("/baz"),
  598. VersionStage: aws.String("AWSCURRENT"),
  599. },
  600. apiOutput: &awssm.GetSecretValueOutput{
  601. SecretString: aws.String(`{"foo":"bar"}`),
  602. },
  603. rr: esv1alpha1.ExternalSecretDataRemoteRef{
  604. Key: "/baz",
  605. },
  606. expectedData: map[string]string{
  607. "foo": "bar",
  608. },
  609. apiErr: nil,
  610. expectError: "",
  611. },
  612. {
  613. // bad case: api error returned
  614. apiInput: &awssm.GetSecretValueInput{
  615. SecretId: aws.String("/baz"),
  616. VersionStage: aws.String("AWSCURRENT"),
  617. },
  618. apiOutput: &awssm.GetSecretValueOutput{
  619. SecretString: aws.String(`{"foo":"bar"}`),
  620. },
  621. rr: esv1alpha1.ExternalSecretDataRemoteRef{
  622. Key: "/baz",
  623. },
  624. expectedData: map[string]string{
  625. "foo": "bar",
  626. },
  627. apiErr: fmt.Errorf("some api err"),
  628. expectError: "some api err",
  629. },
  630. {
  631. // bad case: invalid json
  632. apiInput: &awssm.GetSecretValueInput{
  633. SecretId: aws.String("/baz"),
  634. VersionStage: aws.String("AWSCURRENT"),
  635. },
  636. apiOutput: &awssm.GetSecretValueOutput{
  637. SecretString: aws.String(`-----------------`),
  638. },
  639. rr: esv1alpha1.ExternalSecretDataRemoteRef{
  640. Key: "/baz",
  641. },
  642. expectedData: map[string]string{},
  643. apiErr: nil,
  644. expectError: "unable to unmarshal secret",
  645. },
  646. } {
  647. fake.WithValue(row.apiInput, row.apiOutput, row.apiErr)
  648. out, err := p.GetSecretMap(context.Background(), row.rr)
  649. if !ErrorContains(err, row.expectError) {
  650. t.Errorf("[%d] unexpected error: %s, expected: '%s'", i, err.Error(), row.expectError)
  651. }
  652. if cmp.Equal(out, row.expectedData) {
  653. t.Errorf("[%d] unexpected secret data: expected %#v, got %#v", i, row.expectedData, out)
  654. }
  655. }
  656. }
  657. func ErrorContains(out error, want string) bool {
  658. if out == nil {
  659. return want == ""
  660. }
  661. if want == "" {
  662. return false
  663. }
  664. return strings.Contains(out.Error(), want)
  665. }