oracle.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  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 oracle
  13. import (
  14. "bytes"
  15. "context"
  16. "encoding/base64"
  17. "encoding/json"
  18. "errors"
  19. "fmt"
  20. "os"
  21. "regexp"
  22. "sync"
  23. "time"
  24. "github.com/oracle/oci-go-sdk/v65/common"
  25. "github.com/oracle/oci-go-sdk/v65/common/auth"
  26. "github.com/oracle/oci-go-sdk/v65/keymanagement"
  27. "github.com/oracle/oci-go-sdk/v65/secrets"
  28. "github.com/oracle/oci-go-sdk/v65/vault"
  29. "github.com/tidwall/gjson"
  30. corev1 "k8s.io/api/core/v1"
  31. "k8s.io/client-go/kubernetes"
  32. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  33. ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
  34. "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
  35. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  36. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  37. "github.com/external-secrets/external-secrets/pkg/utils"
  38. "github.com/external-secrets/external-secrets/pkg/utils/resolvers"
  39. )
  40. const (
  41. errOracleClient = "cannot setup new oracle client: %w"
  42. errORACLECredSecretName = "invalid oracle SecretStore resource: missing oracle APIKey"
  43. errUninitalizedOracleProvider = "provider oracle is not initialized"
  44. errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
  45. errMissingPK = "missing PrivateKey"
  46. errMissingUser = "missing User ID"
  47. errMissingTenancy = "missing Tenancy ID"
  48. errMissingRegion = "missing Region"
  49. errMissingFingerprint = "missing Fingerprint"
  50. errMissingVault = "missing Vault"
  51. errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
  52. errMissingKey = "missing Key in secret: %s"
  53. errUnexpectedContent = "unexpected secret bundle content"
  54. )
  55. // https://github.com/external-secrets/external-secrets/issues/644
  56. var _ esv1beta1.SecretsClient = &VaultManagementService{}
  57. var _ esv1beta1.Provider = &VaultManagementService{}
  58. type VaultManagementService struct {
  59. Client VMInterface
  60. KmsVaultClient KmsVCInterface
  61. VaultClient VaultInterface
  62. vault string
  63. compartment string
  64. encryptionKey string
  65. workloadIdentityMutex sync.Mutex
  66. }
  67. type VMInterface interface {
  68. GetSecretBundleByName(ctx context.Context, request secrets.GetSecretBundleByNameRequest) (secrets.GetSecretBundleByNameResponse, error)
  69. }
  70. type KmsVCInterface interface {
  71. GetVault(ctx context.Context, request keymanagement.GetVaultRequest) (response keymanagement.GetVaultResponse, err error)
  72. }
  73. type VaultInterface interface {
  74. ListSecrets(ctx context.Context, request vault.ListSecretsRequest) (response vault.ListSecretsResponse, err error)
  75. CreateSecret(ctx context.Context, request vault.CreateSecretRequest) (response vault.CreateSecretResponse, err error)
  76. UpdateSecret(ctx context.Context, request vault.UpdateSecretRequest) (response vault.UpdateSecretResponse, err error)
  77. ScheduleSecretDeletion(ctx context.Context, request vault.ScheduleSecretDeletionRequest) (response vault.ScheduleSecretDeletionResponse, err error)
  78. }
  79. const (
  80. SecretNotFound = iota
  81. SecretExists
  82. SecretAPIError
  83. )
  84. func (vms *VaultManagementService) PushSecret(ctx context.Context, secret *corev1.Secret, data esv1beta1.PushSecretData) error {
  85. if vms.encryptionKey == "" {
  86. return errors.New("SecretStore must reference encryption key")
  87. }
  88. value := secret.Data[data.GetSecretKey()]
  89. if data.GetSecretKey() == "" {
  90. secretData := map[string]string{}
  91. for k, v := range secret.Data {
  92. secretData[k] = string(v)
  93. }
  94. jsonSecret, err := json.Marshal(secretData)
  95. if err != nil {
  96. return fmt.Errorf("unable to create json %v from value: %v", value, secretData)
  97. }
  98. value = jsonSecret
  99. }
  100. secretName := data.GetRemoteKey()
  101. encodedValue := base64.StdEncoding.EncodeToString(value)
  102. sec, action, err := vms.getSecretBundleWithCode(ctx, secretName)
  103. switch action {
  104. case SecretNotFound:
  105. _, err = vms.VaultClient.CreateSecret(ctx, vault.CreateSecretRequest{
  106. CreateSecretDetails: vault.CreateSecretDetails{
  107. CompartmentId: &vms.compartment,
  108. KeyId: &vms.encryptionKey,
  109. SecretContent: vault.Base64SecretContentDetails{
  110. Content: &encodedValue,
  111. },
  112. SecretName: &secretName,
  113. VaultId: &vms.vault,
  114. },
  115. })
  116. return sanitizeOCISDKErr(err)
  117. case SecretExists:
  118. payload, err := decodeBundle(sec)
  119. if err != nil {
  120. return err
  121. }
  122. if bytes.Equal(payload, value) {
  123. return nil
  124. }
  125. _, err = vms.VaultClient.UpdateSecret(ctx, vault.UpdateSecretRequest{
  126. SecretId: sec.SecretId,
  127. UpdateSecretDetails: vault.UpdateSecretDetails{
  128. SecretContent: vault.Base64SecretContentDetails{
  129. Content: &encodedValue,
  130. },
  131. },
  132. })
  133. return sanitizeOCISDKErr(err)
  134. default:
  135. return sanitizeOCISDKErr(err)
  136. }
  137. }
  138. func (vms *VaultManagementService) DeleteSecret(ctx context.Context, remoteRef esv1beta1.PushSecretRemoteRef) error {
  139. secretName := remoteRef.GetRemoteKey()
  140. resp, action, err := vms.getSecretBundleWithCode(ctx, secretName)
  141. switch action {
  142. case SecretNotFound:
  143. return nil
  144. case SecretExists:
  145. if resp.TimeOfDeletion != nil {
  146. return nil
  147. }
  148. _, err = vms.VaultClient.ScheduleSecretDeletion(ctx, vault.ScheduleSecretDeletionRequest{
  149. SecretId: resp.SecretId,
  150. })
  151. return sanitizeOCISDKErr(err)
  152. default:
  153. return sanitizeOCISDKErr(err)
  154. }
  155. }
  156. func (vms *VaultManagementService) SecretExists(_ context.Context, _ esv1beta1.PushSecretRemoteRef) (bool, error) {
  157. return false, errors.New("not implemented")
  158. }
  159. func (vms *VaultManagementService) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  160. var page *string
  161. var summaries []vault.SecretSummary
  162. for {
  163. resp, err := vms.VaultClient.ListSecrets(ctx, vault.ListSecretsRequest{
  164. CompartmentId: &vms.compartment,
  165. Page: page,
  166. VaultId: &vms.vault,
  167. })
  168. if err != nil {
  169. return nil, sanitizeOCISDKErr(err)
  170. }
  171. summaries = append(summaries, resp.Items...)
  172. if page = resp.OpcNextPage; resp.OpcNextPage == nil {
  173. break
  174. }
  175. }
  176. return vms.filteredSummaryResult(ctx, summaries, ref)
  177. }
  178. func (vms *VaultManagementService) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  179. if utils.IsNil(vms.Client) {
  180. return nil, errors.New(errUninitalizedOracleProvider)
  181. }
  182. sec, err := vms.Client.GetSecretBundleByName(ctx, secrets.GetSecretBundleByNameRequest{
  183. VaultId: &vms.vault,
  184. SecretName: &ref.Key,
  185. Stage: secrets.GetSecretBundleByNameStageEnum(ref.Version),
  186. })
  187. if err != nil {
  188. return nil, sanitizeOCISDKErr(err)
  189. }
  190. payload, err := decodeBundle(sec)
  191. if err != nil {
  192. return nil, err
  193. }
  194. if ref.Property == "" {
  195. return payload, nil
  196. }
  197. val := gjson.Get(string(payload), ref.Property)
  198. if !val.Exists() {
  199. return nil, fmt.Errorf(errMissingKey, ref.Key)
  200. }
  201. return []byte(val.String()), nil
  202. }
  203. func decodeBundle(sec secrets.GetSecretBundleByNameResponse) ([]byte, error) {
  204. bt, ok := sec.SecretBundleContent.(secrets.Base64SecretBundleContentDetails)
  205. if !ok {
  206. return nil, errors.New(errUnexpectedContent)
  207. }
  208. payload, err := base64.StdEncoding.DecodeString(*bt.Content)
  209. if err != nil {
  210. return nil, err
  211. }
  212. return payload, nil
  213. }
  214. func (vms *VaultManagementService) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  215. data, err := vms.GetSecret(ctx, ref)
  216. if err != nil {
  217. return nil, sanitizeOCISDKErr(err)
  218. }
  219. kv := make(map[string]string)
  220. err = json.Unmarshal(data, &kv)
  221. if err != nil {
  222. return nil, fmt.Errorf(errJSONSecretUnmarshal, err)
  223. }
  224. secretData := make(map[string][]byte)
  225. for k, v := range kv {
  226. secretData[k] = []byte(v)
  227. }
  228. return secretData, nil
  229. }
  230. // Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
  231. func (vms *VaultManagementService) Capabilities() esv1beta1.SecretStoreCapabilities {
  232. return esv1beta1.SecretStoreReadOnly
  233. }
  234. func (vms *VaultManagementService) Convert(_ esv1beta1.GenericStore) (kclient.Object, error) {
  235. return nil, nil
  236. }
  237. func (vms *VaultManagementService) ApplyReferent(spec kclient.Object, _ esmeta.ReferentCallOrigin, _ string) (kclient.Object, error) {
  238. return spec, nil
  239. }
  240. func (vms *VaultManagementService) NewClientFromObj(_ context.Context, _ kclient.Object, _ kclient.Client, _ string) (esv1beta1.SecretsClient, error) {
  241. return nil, fmt.Errorf("not implemented")
  242. }
  243. // NewClient constructs a new secrets client based on the provided store.
  244. func (vms *VaultManagementService) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  245. storeSpec := store.GetSpec()
  246. oracleSpec := storeSpec.Provider.Oracle
  247. if oracleSpec.Vault == "" {
  248. return nil, errors.New(errMissingVault)
  249. }
  250. if oracleSpec.Region == "" {
  251. return nil, errors.New(errMissingRegion)
  252. }
  253. var (
  254. err error
  255. configurationProvider common.ConfigurationProvider
  256. )
  257. if oracleSpec.PrincipalType == esv1beta1.WorkloadPrincipal {
  258. configurationProvider, err = vms.getWorkloadIdentityProvider(store, oracleSpec.ServiceAccountRef, oracleSpec.Region, namespace)
  259. } else if oracleSpec.PrincipalType == esv1beta1.InstancePrincipal || oracleSpec.Auth == nil {
  260. configurationProvider, err = auth.InstancePrincipalConfigurationProvider()
  261. } else {
  262. configurationProvider, err = getUserAuthConfigurationProvider(ctx, kube, oracleSpec, namespace, store.GetObjectKind().GroupVersionKind().Kind, oracleSpec.Region)
  263. }
  264. if err != nil {
  265. return nil, fmt.Errorf(errOracleClient, err)
  266. }
  267. secretManagementService, err := secrets.NewSecretsClientWithConfigurationProvider(configurationProvider)
  268. if err != nil {
  269. return nil, fmt.Errorf(errOracleClient, err)
  270. }
  271. secretManagementService.SetRegion(oracleSpec.Region)
  272. kmsVaultClient, err := keymanagement.NewKmsVaultClientWithConfigurationProvider(configurationProvider)
  273. if err != nil {
  274. return nil, fmt.Errorf(errOracleClient, err)
  275. }
  276. kmsVaultClient.SetRegion(oracleSpec.Region)
  277. vaultClient, err := vault.NewVaultsClientWithConfigurationProvider(configurationProvider)
  278. if err != nil {
  279. return nil, fmt.Errorf(errOracleClient, err)
  280. }
  281. vaultClient.SetRegion(oracleSpec.Region)
  282. if storeSpec.RetrySettings != nil {
  283. opts := []common.RetryPolicyOption{common.WithShouldRetryOperation(common.DefaultShouldRetryOperation)}
  284. if mr := storeSpec.RetrySettings.MaxRetries; mr != nil {
  285. opts = append(opts, common.WithMaximumNumberAttempts(uint(*mr)))
  286. }
  287. if ri := storeSpec.RetrySettings.RetryInterval; ri != nil {
  288. i, err := time.ParseDuration(*storeSpec.RetrySettings.RetryInterval)
  289. if err != nil {
  290. return nil, fmt.Errorf(errOracleClient, err)
  291. }
  292. opts = append(opts, common.WithFixedBackoff(i))
  293. }
  294. customRetryPolicy := common.NewRetryPolicyWithOptions(opts...)
  295. secretManagementService.SetCustomClientConfiguration(common.CustomClientConfiguration{
  296. RetryPolicy: &customRetryPolicy,
  297. })
  298. kmsVaultClient.SetCustomClientConfiguration(common.CustomClientConfiguration{
  299. RetryPolicy: &customRetryPolicy,
  300. })
  301. vaultClient.SetCustomClientConfiguration(common.CustomClientConfiguration{
  302. RetryPolicy: &customRetryPolicy,
  303. })
  304. }
  305. return &VaultManagementService{
  306. Client: secretManagementService,
  307. KmsVaultClient: kmsVaultClient,
  308. VaultClient: vaultClient,
  309. vault: oracleSpec.Vault,
  310. compartment: oracleSpec.Compartment,
  311. encryptionKey: oracleSpec.EncryptionKey,
  312. }, nil
  313. }
  314. func (vms *VaultManagementService) getSecretBundleWithCode(ctx context.Context, secretName string) (secrets.GetSecretBundleByNameResponse, int, error) {
  315. // Try to look up the secret, which will determine if we should create or update the secret.
  316. resp, err := vms.Client.GetSecretBundleByName(ctx, secrets.GetSecretBundleByNameRequest{
  317. SecretName: &secretName,
  318. VaultId: &vms.vault,
  319. })
  320. // Get a PushSecret action depending on the ListSecrets response.
  321. action := getSecretBundleCode(err)
  322. return resp, action, err
  323. }
  324. func getSecretBundleCode(err error) int {
  325. if err != nil {
  326. // If we got a 404 service error, try to create the secret.
  327. if serviceErr, ok := err.(common.ServiceError); ok && serviceErr.GetHTTPStatusCode() == 404 {
  328. return SecretNotFound
  329. }
  330. return SecretAPIError
  331. }
  332. // Otherwise, update the existing secret.
  333. return SecretExists
  334. }
  335. func (vms *VaultManagementService) filteredSummaryResult(ctx context.Context, secretSummaries []vault.SecretSummary, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  336. secretMap := map[string][]byte{}
  337. for _, summary := range secretSummaries {
  338. matches, err := matchesRef(summary, ref)
  339. if err != nil {
  340. return nil, err
  341. }
  342. if !matches || summary.TimeOfDeletion != nil {
  343. continue
  344. }
  345. secret, err := vms.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{
  346. Key: *summary.SecretName,
  347. })
  348. if err != nil {
  349. return nil, err
  350. }
  351. secretMap[*summary.SecretName] = secret
  352. }
  353. return secretMap, nil
  354. }
  355. func matchesRef(secretSummary vault.SecretSummary, ref esv1beta1.ExternalSecretFind) (bool, error) {
  356. if ref.Name != nil {
  357. matchString, err := regexp.MatchString(ref.Name.RegExp, *secretSummary.SecretName)
  358. if err != nil {
  359. return false, err
  360. }
  361. return matchString, nil
  362. }
  363. for k, v := range ref.Tags {
  364. if val, ok := secretSummary.FreeformTags[k]; ok {
  365. if val == v {
  366. return true, nil
  367. }
  368. }
  369. }
  370. return false, nil
  371. }
  372. func getSecretData(ctx context.Context, kube kclient.Client, namespace, storeKind string, secretRef esmeta.SecretKeySelector) (string, error) {
  373. if secretRef.Name == "" {
  374. return "", errors.New(errORACLECredSecretName)
  375. }
  376. secret, err := resolvers.SecretKeyRef(
  377. ctx,
  378. kube,
  379. storeKind,
  380. namespace,
  381. &secretRef,
  382. )
  383. if err != nil {
  384. return "", fmt.Errorf(errFetchSAKSecret, err)
  385. }
  386. return secret, nil
  387. }
  388. func getUserAuthConfigurationProvider(ctx context.Context, kube kclient.Client, store *esv1beta1.OracleProvider, namespace, storeKind, region string) (common.ConfigurationProvider, error) {
  389. privateKey, err := getSecretData(ctx, kube, namespace, storeKind, store.Auth.SecretRef.PrivateKey)
  390. if err != nil {
  391. return nil, err
  392. }
  393. if privateKey == "" {
  394. return nil, errors.New(errMissingPK)
  395. }
  396. fingerprint, err := getSecretData(ctx, kube, namespace, storeKind, store.Auth.SecretRef.Fingerprint)
  397. if err != nil {
  398. return nil, err
  399. }
  400. if fingerprint == "" {
  401. return nil, errors.New(errMissingFingerprint)
  402. }
  403. if store.Auth.User == "" {
  404. return nil, errors.New(errMissingUser)
  405. }
  406. if store.Auth.Tenancy == "" {
  407. return nil, errors.New(errMissingTenancy)
  408. }
  409. return common.NewRawConfigurationProvider(store.Auth.Tenancy, store.Auth.User, region, fingerprint, privateKey, nil), nil
  410. }
  411. func (vms *VaultManagementService) Close(_ context.Context) error {
  412. return nil
  413. }
  414. func (vms *VaultManagementService) Validate() (esv1beta1.ValidationResult, error) {
  415. _, err := vms.KmsVaultClient.GetVault(
  416. context.Background(), keymanagement.GetVaultRequest{
  417. VaultId: &vms.vault,
  418. },
  419. )
  420. if err != nil {
  421. failure, ok := common.IsServiceError(err)
  422. if ok {
  423. code := failure.GetCode()
  424. switch code {
  425. case "NotAuthenticated":
  426. return esv1beta1.ValidationResultError, sanitizeOCISDKErr(err)
  427. case "NotAuthorizedOrNotFound":
  428. // User authentication was successful, but user might not have a permission like:
  429. //
  430. // Allow group external_secrets to read vaults in tenancy
  431. //
  432. // Which is fine, because to read secrets we only need:
  433. //
  434. // Allow group external_secrets to read secret-family in tenancy
  435. //
  436. // But we can't test for this permission without knowing the name of a secret
  437. return esv1beta1.ValidationResultUnknown, sanitizeOCISDKErr(err)
  438. default:
  439. return esv1beta1.ValidationResultError, sanitizeOCISDKErr(err)
  440. }
  441. } else {
  442. return esv1beta1.ValidationResultError, err
  443. }
  444. }
  445. return esv1beta1.ValidationResultReady, nil
  446. }
  447. func (vms *VaultManagementService) ValidateStore(store esv1beta1.GenericStore) (admission.Warnings, error) {
  448. storeSpec := store.GetSpec()
  449. oracleSpec := storeSpec.Provider.Oracle
  450. vault := oracleSpec.Vault
  451. if vault == "" {
  452. return nil, errors.New("vault cannot be empty")
  453. }
  454. region := oracleSpec.Region
  455. if region == "" {
  456. return nil, errors.New("region cannot be empty")
  457. }
  458. auth := oracleSpec.Auth
  459. if auth == nil {
  460. return nil, nil
  461. }
  462. user := oracleSpec.Auth.User
  463. if user == "" {
  464. return nil, errors.New("user cannot be empty")
  465. }
  466. tenant := oracleSpec.Auth.Tenancy
  467. if tenant == "" {
  468. return nil, errors.New("tenant cannot be empty")
  469. }
  470. privateKey := oracleSpec.Auth.SecretRef.PrivateKey
  471. if privateKey.Name == "" {
  472. return nil, errors.New("privateKey.name cannot be empty")
  473. }
  474. if privateKey.Key == "" {
  475. return nil, errors.New("privateKey.key cannot be empty")
  476. }
  477. err := utils.ValidateSecretSelector(store, privateKey)
  478. if err != nil {
  479. return nil, err
  480. }
  481. fingerprint := oracleSpec.Auth.SecretRef.Fingerprint
  482. if fingerprint.Name == "" {
  483. return nil, errors.New("fingerprint.name cannot be empty")
  484. }
  485. if fingerprint.Key == "" {
  486. return nil, errors.New("fingerprint.key cannot be empty")
  487. }
  488. err = utils.ValidateSecretSelector(store, fingerprint)
  489. if err != nil {
  490. return nil, err
  491. }
  492. if oracleSpec.ServiceAccountRef != nil {
  493. if err := utils.ValidateReferentServiceAccountSelector(store, *oracleSpec.ServiceAccountRef); err != nil {
  494. return nil, fmt.Errorf("invalid ServiceAccountRef: %w", err)
  495. }
  496. }
  497. return nil, nil
  498. }
  499. func (vms *VaultManagementService) getWorkloadIdentityProvider(store esv1beta1.GenericStore, serviceAcccountRef *esmeta.ServiceAccountSelector, region, namespace string) (configurationProvider common.ConfigurationProvider, err error) {
  500. defer func() {
  501. if uerr := os.Unsetenv(auth.ResourcePrincipalVersionEnvVar); uerr != nil {
  502. err = errors.Join(err, fmt.Errorf("unable to set OCI SDK environment variable %s: %w", auth.ResourcePrincipalRegionEnvVar, uerr))
  503. }
  504. if uerr := os.Unsetenv(auth.ResourcePrincipalRegionEnvVar); uerr != nil {
  505. err = errors.Join(err, fmt.Errorf("unabled to unset OCI SDK environment variable %s: %w", auth.ResourcePrincipalVersionEnvVar, uerr))
  506. }
  507. vms.workloadIdentityMutex.Unlock()
  508. }()
  509. vms.workloadIdentityMutex.Lock()
  510. // OCI SDK requires specific environment variables for workload identity.
  511. if err := os.Setenv(auth.ResourcePrincipalVersionEnvVar, auth.ResourcePrincipalVersion2_2); err != nil {
  512. return nil, fmt.Errorf("unable to set OCI SDK environment variable %s: %w", auth.ResourcePrincipalVersionEnvVar, err)
  513. }
  514. if err := os.Setenv(auth.ResourcePrincipalRegionEnvVar, region); err != nil {
  515. return nil, fmt.Errorf("unable to set OCI SDK environment variable %s: %w", auth.ResourcePrincipalRegionEnvVar, err)
  516. }
  517. // If no service account is specified, use the pod service account to create the Workload Identity provider.
  518. if serviceAcccountRef == nil {
  519. return auth.OkeWorkloadIdentityConfigurationProvider()
  520. }
  521. // Ensure the service account ref is being used appropriately, so arbitrary tokens are not minted by the provider.
  522. if err = utils.ValidateServiceAccountSelector(store, *serviceAcccountRef); err != nil {
  523. return nil, fmt.Errorf("invalid ServiceAccountRef: %w", err)
  524. }
  525. cfg, err := ctrlcfg.GetConfig()
  526. if err != nil {
  527. return nil, err
  528. }
  529. clientset, err := kubernetes.NewForConfig(cfg)
  530. if err != nil {
  531. return nil, err
  532. }
  533. tokenProvider := NewTokenProvider(clientset, serviceAcccountRef, namespace)
  534. return auth.OkeWorkloadIdentityConfigurationProviderWithServiceAccountTokenProvider(tokenProvider)
  535. }
  536. func sanitizeOCISDKErr(err error) error {
  537. if err == nil {
  538. return nil
  539. }
  540. // If we have a ServiceError from the OCI SDK, strip only the message from the verbose error
  541. if serviceError, ok := err.(common.ServiceErrorRichInfo); ok {
  542. return fmt.Errorf("%s service failed to %s, HTTP status code %d: %s", serviceError.GetTargetService(), serviceError.GetOperationName(), serviceError.GetHTTPStatusCode(), serviceError.GetMessage())
  543. }
  544. return err
  545. }
  546. func init() {
  547. esv1beta1.Register(&VaultManagementService{}, &esv1beta1.SecretStoreProvider{
  548. Oracle: &esv1beta1.OracleProvider{},
  549. })
  550. }