secretsmanager.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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. "bytes"
  15. "context"
  16. "encoding/json"
  17. "errors"
  18. "fmt"
  19. "math/big"
  20. "strings"
  21. "github.com/aws/aws-sdk-go/aws"
  22. "github.com/aws/aws-sdk-go/aws/awserr"
  23. "github.com/aws/aws-sdk-go/aws/request"
  24. "github.com/aws/aws-sdk-go/aws/session"
  25. awssm "github.com/aws/aws-sdk-go/service/secretsmanager"
  26. "github.com/google/uuid"
  27. "github.com/tidwall/gjson"
  28. "github.com/tidwall/sjson"
  29. corev1 "k8s.io/api/core/v1"
  30. utilpointer "k8s.io/utils/ptr"
  31. ctrl "sigs.k8s.io/controller-runtime"
  32. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  33. "github.com/external-secrets/external-secrets/pkg/constants"
  34. "github.com/external-secrets/external-secrets/pkg/find"
  35. "github.com/external-secrets/external-secrets/pkg/metrics"
  36. "github.com/external-secrets/external-secrets/pkg/provider/aws/util"
  37. "github.com/external-secrets/external-secrets/pkg/utils"
  38. )
  39. // Declares metadata information for pushing secrets to AWS Secret Store.
  40. const (
  41. SecretPushFormatKey = "secretPushFormat"
  42. SecretPushFormatString = "string"
  43. SecretPushFormatBinary = "binary"
  44. )
  45. // https://github.com/external-secrets/external-secrets/issues/644
  46. var _ esv1beta1.SecretsClient = &SecretsManager{}
  47. // SecretsManager is a provider for AWS SecretsManager.
  48. type SecretsManager struct {
  49. sess *session.Session
  50. client SMInterface
  51. referentAuth bool
  52. cache map[string]*awssm.GetSecretValueOutput
  53. config *esv1beta1.SecretsManager
  54. }
  55. // SMInterface is a subset of the smiface api.
  56. // see: https://docs.aws.amazon.com/sdk-for-go/api/service/secretsmanager/secretsmanageriface/
  57. type SMInterface interface {
  58. BatchGetSecretValueWithContext(aws.Context, *awssm.BatchGetSecretValueInput, ...request.Option) (*awssm.BatchGetSecretValueOutput, error)
  59. ListSecrets(*awssm.ListSecretsInput) (*awssm.ListSecretsOutput, error)
  60. GetSecretValue(*awssm.GetSecretValueInput) (*awssm.GetSecretValueOutput, error)
  61. CreateSecretWithContext(aws.Context, *awssm.CreateSecretInput, ...request.Option) (*awssm.CreateSecretOutput, error)
  62. GetSecretValueWithContext(aws.Context, *awssm.GetSecretValueInput, ...request.Option) (*awssm.GetSecretValueOutput, error)
  63. PutSecretValueWithContext(aws.Context, *awssm.PutSecretValueInput, ...request.Option) (*awssm.PutSecretValueOutput, error)
  64. DescribeSecretWithContext(aws.Context, *awssm.DescribeSecretInput, ...request.Option) (*awssm.DescribeSecretOutput, error)
  65. DeleteSecretWithContext(ctx aws.Context, input *awssm.DeleteSecretInput, opts ...request.Option) (*awssm.DeleteSecretOutput, error)
  66. }
  67. const (
  68. errUnexpectedFindOperator = "unexpected find operator"
  69. managedBy = "managed-by"
  70. externalSecrets = "external-secrets"
  71. initialVersion = "00000000-0000-0000-0000-000000000001"
  72. )
  73. var log = ctrl.Log.WithName("provider").WithName("aws").WithName("secretsmanager")
  74. // New creates a new SecretsManager client.
  75. func New(sess *session.Session, cfg *aws.Config, secretsManagerCfg *esv1beta1.SecretsManager, referentAuth bool) (*SecretsManager, error) {
  76. return &SecretsManager{
  77. sess: sess,
  78. client: awssm.New(sess, cfg),
  79. referentAuth: referentAuth,
  80. cache: make(map[string]*awssm.GetSecretValueOutput),
  81. config: secretsManagerCfg,
  82. }, nil
  83. }
  84. func (sm *SecretsManager) fetch(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (*awssm.GetSecretValueOutput, error) {
  85. ver := "AWSCURRENT"
  86. valueFrom := "SECRET"
  87. if ref.Version != "" {
  88. ver = ref.Version
  89. }
  90. if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
  91. valueFrom = "TAG"
  92. }
  93. log.Info("fetching secret value", "key", ref.Key, "version", ver, "value", valueFrom)
  94. cacheKey := fmt.Sprintf("%s#%s#%s", ref.Key, ver, valueFrom)
  95. if secretOut, found := sm.cache[cacheKey]; found {
  96. log.Info("found secret in cache", "key", ref.Key, "version", ver)
  97. return secretOut, nil
  98. }
  99. secretOut, err := sm.constructSecretValue(ctx, ref, ver)
  100. if err != nil {
  101. return nil, err
  102. }
  103. sm.cache[cacheKey] = secretOut
  104. return secretOut, nil
  105. }
  106. func (sm *SecretsManager) DeleteSecret(ctx context.Context, remoteRef esv1beta1.PushSecretRemoteRef) error {
  107. secretName := remoteRef.GetRemoteKey()
  108. secretValue := awssm.GetSecretValueInput{
  109. SecretId: &secretName,
  110. }
  111. secretInput := awssm.DescribeSecretInput{
  112. SecretId: &secretName,
  113. }
  114. awsSecret, err := sm.client.GetSecretValueWithContext(ctx, &secretValue)
  115. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMGetSecretValue, err)
  116. var aerr awserr.Error
  117. if err != nil {
  118. if ok := errors.As(err, &aerr); !ok {
  119. return err
  120. }
  121. if aerr.Code() == awssm.ErrCodeResourceNotFoundException {
  122. return nil
  123. }
  124. return err
  125. }
  126. data, err := sm.client.DescribeSecretWithContext(ctx, &secretInput)
  127. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMDescribeSecret, err)
  128. if err != nil {
  129. return err
  130. }
  131. if !isManagedByESO(data) {
  132. return nil
  133. }
  134. deleteInput := &awssm.DeleteSecretInput{
  135. SecretId: awsSecret.ARN,
  136. }
  137. if sm.config != nil && sm.config.ForceDeleteWithoutRecovery {
  138. deleteInput.ForceDeleteWithoutRecovery = &sm.config.ForceDeleteWithoutRecovery
  139. }
  140. if sm.config != nil && sm.config.RecoveryWindowInDays > 0 {
  141. deleteInput.RecoveryWindowInDays = &sm.config.RecoveryWindowInDays
  142. }
  143. err = util.ValidateDeleteSecretInput(*deleteInput)
  144. if err != nil {
  145. return err
  146. }
  147. _, err = sm.client.DeleteSecretWithContext(ctx, deleteInput)
  148. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMDeleteSecret, err)
  149. return err
  150. }
  151. func (sm *SecretsManager) SecretExists(ctx context.Context, pushSecretRef esv1beta1.PushSecretRemoteRef) (bool, error) {
  152. secretName := pushSecretRef.GetRemoteKey()
  153. secretValue := awssm.GetSecretValueInput{
  154. SecretId: &secretName,
  155. }
  156. _, err := sm.client.GetSecretValueWithContext(ctx, &secretValue)
  157. if err != nil {
  158. return sm.handleSecretError(err)
  159. }
  160. return true, nil
  161. }
  162. func (sm *SecretsManager) handleSecretError(err error) (bool, error) {
  163. var aerr awserr.Error
  164. if ok := errors.As(err, &aerr); !ok {
  165. return false, err
  166. }
  167. if aerr.Code() == awssm.ErrCodeResourceNotFoundException {
  168. return false, nil
  169. }
  170. return false, err
  171. }
  172. func (sm *SecretsManager) PushSecret(ctx context.Context, secret *corev1.Secret, psd esv1beta1.PushSecretData) error {
  173. value, err := utils.ExtractSecretData(psd, secret)
  174. if err != nil {
  175. return fmt.Errorf("failed to extract secret data: %w", err)
  176. }
  177. secretName := psd.GetRemoteKey()
  178. secretValue := awssm.GetSecretValueInput{
  179. SecretId: &secretName,
  180. }
  181. secretInput := awssm.DescribeSecretInput{
  182. SecretId: &secretName,
  183. }
  184. awsSecret, err := sm.client.GetSecretValueWithContext(ctx, &secretValue)
  185. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMGetSecretValue, err)
  186. if psd.GetProperty() != "" {
  187. currentSecret := sm.retrievePayload(awsSecret)
  188. if currentSecret != "" && !gjson.Valid(currentSecret) {
  189. return errors.New("PushSecret for aws secrets manager with a pushSecretData property requires a json secret")
  190. }
  191. value, _ = sjson.SetBytes([]byte(currentSecret), psd.GetProperty(), value)
  192. }
  193. var aerr awserr.Error
  194. if err != nil {
  195. if ok := errors.As(err, &aerr); !ok {
  196. return err
  197. }
  198. if aerr.Code() == awssm.ErrCodeResourceNotFoundException {
  199. return sm.createSecretWithContext(ctx, secretName, psd, value)
  200. }
  201. return err
  202. }
  203. return sm.putSecretValueWithContext(ctx, secretInput, awsSecret, psd, value)
  204. }
  205. func padOrTrim(b []byte) []byte {
  206. l := len(b)
  207. size := 16
  208. if l == size {
  209. return b
  210. }
  211. if l > size {
  212. return b[l-size:]
  213. }
  214. tmp := make([]byte, size)
  215. copy(tmp[size-l:], b)
  216. return tmp
  217. }
  218. func bumpVersionNumber(id *string) (*string, error) {
  219. if id == nil {
  220. output := initialVersion
  221. return &output, nil
  222. }
  223. n := new(big.Int)
  224. oldVersion, ok := n.SetString(strings.ReplaceAll(*id, "-", ""), 16)
  225. if !ok {
  226. return nil, fmt.Errorf("expected secret version in AWS SSM to be a UUID but got '%s'", *id)
  227. }
  228. newVersionRaw := oldVersion.Add(oldVersion, big.NewInt(1)).Bytes()
  229. newVersion, err := uuid.FromBytes(padOrTrim(newVersionRaw))
  230. if err != nil {
  231. return nil, err
  232. }
  233. s := newVersion.String()
  234. return &s, nil
  235. }
  236. func isManagedByESO(data *awssm.DescribeSecretOutput) bool {
  237. managedBy := managedBy
  238. externalSecrets := externalSecrets
  239. for _, tag := range data.Tags {
  240. if *tag.Key == managedBy && *tag.Value == externalSecrets {
  241. return true
  242. }
  243. }
  244. return false
  245. }
  246. // GetAllSecrets syncs multiple secrets from aws provider into a single Kubernetes Secret.
  247. func (sm *SecretsManager) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  248. if ref.Name != nil {
  249. return sm.findByName(ctx, ref)
  250. }
  251. if len(ref.Tags) > 0 {
  252. return sm.findByTags(ctx, ref)
  253. }
  254. return nil, errors.New(errUnexpectedFindOperator)
  255. }
  256. func (sm *SecretsManager) findByName(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  257. matcher, err := find.New(*ref.Name)
  258. if err != nil {
  259. return nil, err
  260. }
  261. filters := make([]*awssm.Filter, 0)
  262. if ref.Path != nil {
  263. filters = append(filters, &awssm.Filter{
  264. Key: utilpointer.To(awssm.FilterNameStringTypeName),
  265. Values: []*string{
  266. ref.Path,
  267. },
  268. })
  269. return sm.fetchWithBatch(ctx, filters, matcher)
  270. }
  271. data := make(map[string][]byte)
  272. var nextToken *string
  273. for {
  274. // I put this into the for loop on purpose.
  275. log.V(0).Info("using ListSecret to fetch all secrets; this is a costly operations, please use batching by defining a _path_")
  276. it, err := sm.client.ListSecrets(&awssm.ListSecretsInput{
  277. Filters: filters,
  278. NextToken: nextToken,
  279. })
  280. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMListSecrets, err)
  281. if err != nil {
  282. return nil, err
  283. }
  284. log.V(1).Info("aws sm findByName found", "secrets", len(it.SecretList))
  285. for _, secret := range it.SecretList {
  286. if !matcher.MatchName(*secret.Name) {
  287. continue
  288. }
  289. log.V(1).Info("aws sm findByName matches", "name", *secret.Name)
  290. if err := sm.fetchAndSet(ctx, data, *secret.Name); err != nil {
  291. return nil, err
  292. }
  293. }
  294. nextToken = it.NextToken
  295. if nextToken == nil {
  296. break
  297. }
  298. }
  299. return data, nil
  300. }
  301. func (sm *SecretsManager) findByTags(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  302. filters := make([]*awssm.Filter, 0)
  303. for k, v := range ref.Tags {
  304. filters = append(filters, &awssm.Filter{
  305. Key: utilpointer.To(awssm.FilterNameStringTypeTagKey),
  306. Values: []*string{
  307. utilpointer.To(k),
  308. },
  309. }, &awssm.Filter{
  310. Key: utilpointer.To(awssm.FilterNameStringTypeTagValue),
  311. Values: []*string{
  312. utilpointer.To(v),
  313. },
  314. })
  315. }
  316. if ref.Path != nil {
  317. filters = append(filters, &awssm.Filter{
  318. Key: utilpointer.To(awssm.FilterNameStringTypeName),
  319. Values: []*string{
  320. ref.Path,
  321. },
  322. })
  323. }
  324. return sm.fetchWithBatch(ctx, filters, nil)
  325. }
  326. func (sm *SecretsManager) fetchAndSet(ctx context.Context, data map[string][]byte, name string) error {
  327. sec, err := sm.fetch(ctx, esv1beta1.ExternalSecretDataRemoteRef{
  328. Key: name,
  329. })
  330. if err != nil {
  331. return err
  332. }
  333. if sec.SecretString != nil {
  334. data[name] = []byte(*sec.SecretString)
  335. }
  336. if sec.SecretBinary != nil {
  337. data[name] = sec.SecretBinary
  338. }
  339. return nil
  340. }
  341. // GetSecret returns a single secret from the provider.
  342. func (sm *SecretsManager) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  343. secretOut, err := sm.fetch(ctx, ref)
  344. if errors.Is(err, esv1beta1.NoSecretErr) {
  345. return nil, err
  346. }
  347. if err != nil {
  348. return nil, util.SanitizeErr(err)
  349. }
  350. if ref.Property == "" {
  351. if secretOut.SecretString != nil {
  352. return []byte(*secretOut.SecretString), nil
  353. }
  354. if secretOut.SecretBinary != nil {
  355. return secretOut.SecretBinary, nil
  356. }
  357. return nil, fmt.Errorf("invalid secret received. no secret string nor binary for key: %s", ref.Key)
  358. }
  359. val := sm.mapSecretToGjson(secretOut, ref.Property)
  360. if !val.Exists() {
  361. return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
  362. }
  363. return []byte(val.String()), nil
  364. }
  365. func (sm *SecretsManager) mapSecretToGjson(secretOut *awssm.GetSecretValueOutput, property string) gjson.Result {
  366. payload := sm.retrievePayload(secretOut)
  367. refProperty := sm.escapeDotsIfRequired(property, payload)
  368. val := gjson.Get(payload, refProperty)
  369. return val
  370. }
  371. func (sm *SecretsManager) retrievePayload(secretOut *awssm.GetSecretValueOutput) string {
  372. var payload string
  373. if secretOut.SecretString != nil {
  374. payload = *secretOut.SecretString
  375. }
  376. if secretOut.SecretBinary != nil {
  377. payload = string(secretOut.SecretBinary)
  378. }
  379. return payload
  380. }
  381. func (sm *SecretsManager) escapeDotsIfRequired(currentRefProperty, payload string) string {
  382. // We need to search if a given key with a . exists before using gjson operations.
  383. idx := strings.Index(currentRefProperty, ".")
  384. refProperty := currentRefProperty
  385. if idx > -1 {
  386. refProperty = strings.ReplaceAll(currentRefProperty, ".", "\\.")
  387. val := gjson.Get(payload, refProperty)
  388. if !val.Exists() {
  389. refProperty = currentRefProperty
  390. }
  391. }
  392. return refProperty
  393. }
  394. // GetSecretMap returns multiple k/v pairs from the provider.
  395. func (sm *SecretsManager) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  396. log.Info("fetching secret map", "key", ref.Key)
  397. data, err := sm.GetSecret(ctx, ref)
  398. if err != nil {
  399. return nil, err
  400. }
  401. kv := make(map[string]json.RawMessage)
  402. err = json.Unmarshal(data, &kv)
  403. if err != nil {
  404. return nil, fmt.Errorf("unable to unmarshal secret %s: %w", ref.Key, err)
  405. }
  406. secretData := make(map[string][]byte)
  407. for k, v := range kv {
  408. var strVal string
  409. err = json.Unmarshal(v, &strVal)
  410. if err == nil {
  411. secretData[k] = []byte(strVal)
  412. } else {
  413. secretData[k] = v
  414. }
  415. }
  416. return secretData, nil
  417. }
  418. func (sm *SecretsManager) Close(_ context.Context) error {
  419. return nil
  420. }
  421. func (sm *SecretsManager) Validate() (esv1beta1.ValidationResult, error) {
  422. // skip validation stack because it depends on the namespace
  423. // of the ExternalSecret
  424. if sm.referentAuth {
  425. return esv1beta1.ValidationResultUnknown, nil
  426. }
  427. _, err := sm.sess.Config.Credentials.Get()
  428. if err != nil {
  429. return esv1beta1.ValidationResultError, util.SanitizeErr(err)
  430. }
  431. return esv1beta1.ValidationResultReady, nil
  432. }
  433. func (sm *SecretsManager) Capabilities() esv1beta1.SecretStoreCapabilities {
  434. return esv1beta1.SecretStoreReadWrite
  435. }
  436. func (sm *SecretsManager) createSecretWithContext(ctx context.Context, secretName string, psd esv1beta1.PushSecretData, value []byte) error {
  437. secretPushFormat, err := utils.FetchValueFromMetadata(SecretPushFormatKey, psd.GetMetadata(), SecretPushFormatBinary)
  438. if err != nil {
  439. return fmt.Errorf("failed to parse metadata: %w", err)
  440. }
  441. input := &awssm.CreateSecretInput{
  442. Name: &secretName,
  443. SecretBinary: value,
  444. Tags: []*awssm.Tag{
  445. {
  446. Key: utilpointer.To(managedBy),
  447. Value: utilpointer.To(externalSecrets),
  448. },
  449. },
  450. ClientRequestToken: utilpointer.To(initialVersion),
  451. }
  452. if secretPushFormat == SecretPushFormatString {
  453. input.SetSecretBinary(nil).SetSecretString(string(value))
  454. }
  455. _, err = sm.client.CreateSecretWithContext(ctx, input)
  456. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMCreateSecret, err)
  457. return err
  458. }
  459. func (sm *SecretsManager) putSecretValueWithContext(ctx context.Context, secretInput awssm.DescribeSecretInput, awsSecret *awssm.GetSecretValueOutput, psd esv1beta1.PushSecretData, value []byte) error {
  460. data, err := sm.client.DescribeSecretWithContext(ctx, &secretInput)
  461. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMDescribeSecret, err)
  462. if err != nil {
  463. return err
  464. }
  465. if !isManagedByESO(data) {
  466. return errors.New("secret not managed by external-secrets")
  467. }
  468. if awsSecret != nil && bytes.Equal(awsSecret.SecretBinary, value) || utils.CompareStringAndByteSlices(awsSecret.SecretString, value) {
  469. return nil
  470. }
  471. newVersionNumber, err := bumpVersionNumber(awsSecret.VersionId)
  472. if err != nil {
  473. return err
  474. }
  475. input := &awssm.PutSecretValueInput{
  476. SecretId: awsSecret.ARN,
  477. SecretBinary: value,
  478. ClientRequestToken: newVersionNumber,
  479. }
  480. secretPushFormat, err := utils.FetchValueFromMetadata(SecretPushFormatKey, psd.GetMetadata(), SecretPushFormatBinary)
  481. if err != nil {
  482. return fmt.Errorf("failed to parse metadata: %w", err)
  483. }
  484. if secretPushFormat == SecretPushFormatString {
  485. input.SetSecretBinary(nil).SetSecretString(string(value))
  486. }
  487. _, err = sm.client.PutSecretValueWithContext(ctx, input)
  488. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMPutSecretValue, err)
  489. return err
  490. }
  491. func (sm *SecretsManager) fetchWithBatch(ctx context.Context, filters []*awssm.Filter, matcher *find.Matcher) (map[string][]byte, error) {
  492. data := make(map[string][]byte)
  493. var nextToken *string
  494. for {
  495. it, err := sm.client.BatchGetSecretValueWithContext(ctx, &awssm.BatchGetSecretValueInput{
  496. Filters: filters,
  497. NextToken: nextToken,
  498. })
  499. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMBatchGetSecretValue, err)
  500. if err != nil {
  501. return nil, err
  502. }
  503. log.V(1).Info("aws sm findByName found", "secrets", len(it.SecretValues))
  504. for _, secret := range it.SecretValues {
  505. if matcher != nil && !matcher.MatchName(*secret.Name) {
  506. continue
  507. }
  508. log.V(1).Info("aws sm findByName matches", "name", *secret.Name)
  509. sm.setSecretValues(secret, data)
  510. }
  511. nextToken = it.NextToken
  512. if nextToken == nil {
  513. break
  514. }
  515. }
  516. return data, nil
  517. }
  518. func (sm *SecretsManager) setSecretValues(secret *awssm.SecretValueEntry, data map[string][]byte) {
  519. if secret.SecretString != nil {
  520. data[*secret.Name] = []byte(*secret.SecretString)
  521. }
  522. if secret.SecretBinary != nil {
  523. data[*secret.Name] = secret.SecretBinary
  524. }
  525. }
  526. func (sm *SecretsManager) constructSecretValue(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef, ver string) (*awssm.GetSecretValueOutput, error) {
  527. if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
  528. describeSecretInput := &awssm.DescribeSecretInput{
  529. SecretId: &ref.Key,
  530. }
  531. descOutput, err := sm.client.DescribeSecretWithContext(ctx, describeSecretInput)
  532. if err != nil {
  533. return nil, err
  534. }
  535. log.Info("found metadata secret", "key", ref.Key, "output", descOutput)
  536. jsonTags, err := util.SecretTagsToJSONString(descOutput.Tags)
  537. if err != nil {
  538. return nil, err
  539. }
  540. return &awssm.GetSecretValueOutput{
  541. ARN: descOutput.ARN,
  542. CreatedDate: descOutput.CreatedDate,
  543. Name: descOutput.Name,
  544. SecretString: &jsonTags,
  545. VersionId: &ver,
  546. }, nil
  547. }
  548. var getSecretValueInput *awssm.GetSecretValueInput
  549. if strings.HasPrefix(ver, "uuid/") {
  550. versionID := strings.TrimPrefix(ver, "uuid/")
  551. getSecretValueInput = &awssm.GetSecretValueInput{
  552. SecretId: &ref.Key,
  553. VersionId: &versionID,
  554. }
  555. } else {
  556. getSecretValueInput = &awssm.GetSecretValueInput{
  557. SecretId: &ref.Key,
  558. VersionStage: &ver,
  559. }
  560. }
  561. secretOut, err := sm.client.GetSecretValue(getSecretValueInput)
  562. metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMGetSecretValue, err)
  563. var (
  564. nf *awssm.ResourceNotFoundException
  565. ie *awssm.InvalidRequestException
  566. )
  567. if errors.As(err, &nf) {
  568. return nil, esv1beta1.NoSecretErr
  569. }
  570. if errors.As(err, &ie) && strings.Contains(ie.Error(), "was marked for deletion") {
  571. return nil, esv1beta1.NoSecretErr
  572. }
  573. return secretOut, err
  574. }