provider.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package infisical
  14. import (
  15. "context"
  16. "errors"
  17. "fmt"
  18. infisicalSdk "github.com/infisical/go-sdk"
  19. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  20. "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
  21. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  22. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  23. "github.com/external-secrets/external-secrets/providers/v1/infisical/constants"
  24. "github.com/external-secrets/external-secrets/runtime/esutils"
  25. "github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
  26. "github.com/external-secrets/external-secrets/runtime/metrics"
  27. )
  28. const (
  29. machineIdentityLoginViaUniversalAuth = "MachineIdentityLoginViaUniversalAuth"
  30. machineIdentityLoginViaAzureAuth = "MachineIdentityLoginViaAzureAuth"
  31. machineIdentityLoginViaGCPIDTokenAuth = "MachineIdentityLoginViaGcpIdTokenAuth"
  32. machineIdentityLoginViaGcpServiceAccountAuth = "MachineIdentityLoginViaGcpServiceAccountAuth"
  33. machineIdentityLoginViaJwtAuth = "MachineIdentityLoginViaJwtAuth"
  34. machineIdentityLoginViaLdapAuth = "MachineIdentityLoginViaLdapAuth"
  35. machineIdentityLoginViaOciAuth = "MachineIdentityLoginViaOciAuth"
  36. machineIdentityLoginViaKubernetesAuth = "MachineIdentityLoginViaKubernetesAuth"
  37. machineIdentityLoginViaAwsAuth = "MachineIdentityLoginViaAwsAuth"
  38. machineIdentityLoginViaTokenAuth = "MachineIdentityLoginViaTokenAuth"
  39. revokeAccessToken = "RevokeAccessToken"
  40. )
  41. const errSecretDataFormat = "failed to get secret data identityId %w"
  42. // Provider implements the Infisical external secrets provider.
  43. type Provider struct {
  44. cancelSdkClient context.CancelFunc
  45. sdkClient infisicalSdk.InfisicalClientInterface
  46. apiScope *ClientScope
  47. authMethod string
  48. }
  49. // ClientScope represents the scope configuration for an Infisical client.
  50. type ClientScope struct {
  51. EnvironmentSlug string
  52. ProjectSlug string
  53. Recursive bool
  54. SecretPath string
  55. ExpandSecretReferences bool
  56. }
  57. // https://github.com/external-secrets/external-secrets/issues/644
  58. var _ esv1.SecretsClient = &Provider{}
  59. var _ esv1.Provider = &Provider{}
  60. // Capabilities returns the provider's supported capabilities.
  61. func (p *Provider) Capabilities() esv1.SecretStoreCapabilities {
  62. return esv1.SecretStoreReadOnly
  63. }
  64. func performUniversalAuthLogin(
  65. ctx context.Context,
  66. store esv1.GenericStore,
  67. infisicalSpec *esv1.InfisicalProvider,
  68. sdkClient infisicalSdk.InfisicalClientInterface,
  69. kube kclient.Client,
  70. namespace string,
  71. ) error {
  72. universalAuthCredentials := infisicalSpec.Auth.UniversalAuthCredentials
  73. clientID, err := GetStoreSecretData(ctx, store, kube, namespace, universalAuthCredentials.ClientID)
  74. if err != nil {
  75. return err
  76. }
  77. clientSecret, err := GetStoreSecretData(ctx, store, kube, namespace, universalAuthCredentials.ClientSecret)
  78. if err != nil {
  79. return err
  80. }
  81. _, err = sdkClient.Auth().UniversalAuthLogin(clientID, clientSecret)
  82. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaUniversalAuth, err)
  83. if err != nil {
  84. return fmt.Errorf("failed to authenticate via universal auth %w", err)
  85. }
  86. return nil
  87. }
  88. func performAzureAuthLogin(
  89. ctx context.Context,
  90. store esv1.GenericStore,
  91. infisicalSpec *esv1.InfisicalProvider,
  92. sdkClient infisicalSdk.InfisicalClientInterface,
  93. kube kclient.Client,
  94. namespace string,
  95. ) error {
  96. azureAuthCredentials := infisicalSpec.Auth.AzureAuthCredentials
  97. identityID, err := GetStoreSecretData(ctx, store, kube, namespace, azureAuthCredentials.IdentityID)
  98. if err != nil {
  99. return fmt.Errorf("failed to get secret data id %w", err)
  100. }
  101. resource := ""
  102. if azureAuthCredentials.Resource.Name != "" {
  103. resource, err = GetStoreSecretData(ctx, store, kube, namespace, azureAuthCredentials.Resource)
  104. if err != nil {
  105. return fmt.Errorf("failed to get secret data resource %w", err)
  106. }
  107. }
  108. _, err = sdkClient.Auth().AzureAuthLogin(identityID, resource)
  109. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaAzureAuth, err)
  110. if err != nil {
  111. return fmt.Errorf("failed to authenticate via azure auth %w", err)
  112. }
  113. return nil
  114. }
  115. func performGcpIDTokenAuthLogin(
  116. ctx context.Context,
  117. store esv1.GenericStore,
  118. infisicalSpec *esv1.InfisicalProvider,
  119. sdkClient infisicalSdk.InfisicalClientInterface,
  120. kube kclient.Client,
  121. namespace string,
  122. ) error {
  123. gcpIDTokenAuthCredentials := infisicalSpec.Auth.GcpIDTokenAuthCredentials
  124. identityID, err := GetStoreSecretData(ctx, store, kube, namespace, gcpIDTokenAuthCredentials.IdentityID)
  125. if err != nil {
  126. return fmt.Errorf(errSecretDataFormat, err)
  127. }
  128. _, err = sdkClient.Auth().GcpIdTokenAuthLogin(identityID)
  129. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaGCPIDTokenAuth, err)
  130. if err != nil {
  131. return fmt.Errorf("failed to authenticate via gcp id token auth %w", err)
  132. }
  133. return nil
  134. }
  135. func performGcpIamAuthLogin(
  136. ctx context.Context,
  137. store esv1.GenericStore,
  138. infisicalSpec *esv1.InfisicalProvider,
  139. sdkClient infisicalSdk.InfisicalClientInterface,
  140. kube kclient.Client,
  141. namespace string,
  142. ) error {
  143. gcpIamAuthCredentials := infisicalSpec.Auth.GcpIamAuthCredentials
  144. identityID, err := GetStoreSecretData(ctx, store, kube, namespace, gcpIamAuthCredentials.IdentityID)
  145. if err != nil {
  146. return fmt.Errorf(errSecretDataFormat, err)
  147. }
  148. serviceAccountKeyFilePath, err := GetStoreSecretData(ctx, store, kube, namespace, gcpIamAuthCredentials.ServiceAccountKeyFilePath)
  149. if err != nil {
  150. return fmt.Errorf("failed to get secret data serviceAccountKeyFilePath %w", err)
  151. }
  152. _, err = sdkClient.Auth().GcpIamAuthLogin(identityID, serviceAccountKeyFilePath)
  153. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaGcpServiceAccountAuth, err)
  154. if err != nil {
  155. return fmt.Errorf("failed to authenticate via gcp iam auth %w", err)
  156. }
  157. return nil
  158. }
  159. func performJwtAuthLogin(
  160. ctx context.Context,
  161. store esv1.GenericStore,
  162. infisicalSpec *esv1.InfisicalProvider,
  163. sdkClient infisicalSdk.InfisicalClientInterface,
  164. kube kclient.Client,
  165. namespace string,
  166. ) error {
  167. jwtAuthCredentials := infisicalSpec.Auth.JwtAuthCredentials
  168. identityID, err := GetStoreSecretData(ctx, store, kube, namespace, jwtAuthCredentials.IdentityID)
  169. if err != nil {
  170. return fmt.Errorf(errSecretDataFormat, err)
  171. }
  172. jwt, err := GetStoreSecretData(ctx, store, kube, namespace, jwtAuthCredentials.JWT)
  173. if err != nil {
  174. return fmt.Errorf("failed to get secret data jwt %w", err)
  175. }
  176. _, err = sdkClient.Auth().JwtAuthLogin(identityID, jwt)
  177. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaJwtAuth, err)
  178. if err != nil {
  179. return fmt.Errorf("failed to authenticate via jwt auth %w", err)
  180. }
  181. return nil
  182. }
  183. func performLdapAuthLogin(
  184. ctx context.Context,
  185. store esv1.GenericStore,
  186. infisicalSpec *esv1.InfisicalProvider,
  187. sdkClient infisicalSdk.InfisicalClientInterface,
  188. kube kclient.Client,
  189. namespace string,
  190. ) error {
  191. ldapAuthCredentials := infisicalSpec.Auth.LdapAuthCredentials
  192. identityID, err := GetStoreSecretData(ctx, store, kube, namespace, ldapAuthCredentials.IdentityID)
  193. if err != nil {
  194. return fmt.Errorf(errSecretDataFormat, err)
  195. }
  196. ldapPassword, err := GetStoreSecretData(ctx, store, kube, namespace, ldapAuthCredentials.LDAPPassword)
  197. if err != nil {
  198. return fmt.Errorf("failed to get secret data ldapPassword %w", err)
  199. }
  200. ldapUsername, err := GetStoreSecretData(ctx, store, kube, namespace, ldapAuthCredentials.LDAPUsername)
  201. if err != nil {
  202. return fmt.Errorf("failed to get secret data ldapUsername %w", err)
  203. }
  204. _, err = sdkClient.Auth().LdapAuthLogin(identityID, ldapPassword, ldapUsername)
  205. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaLdapAuth, err)
  206. if err != nil {
  207. return fmt.Errorf("failed to authenticate via ldap auth %w", err)
  208. }
  209. return nil
  210. }
  211. func performOciAuthLogin(
  212. ctx context.Context,
  213. store esv1.GenericStore,
  214. infisicalSpec *esv1.InfisicalProvider,
  215. sdkClient infisicalSdk.InfisicalClientInterface,
  216. kube kclient.Client,
  217. namespace string,
  218. ) error {
  219. ociAuthCredentials := infisicalSpec.Auth.OciAuthCredentials
  220. identityID, err := GetStoreSecretData(ctx, store, kube, namespace, ociAuthCredentials.IdentityID)
  221. if err != nil {
  222. return fmt.Errorf(errSecretDataFormat, err)
  223. }
  224. privateKey, err := GetStoreSecretData(ctx, store, kube, namespace, ociAuthCredentials.PrivateKey)
  225. if err != nil {
  226. return fmt.Errorf("failed to get secret data privateKey %w", err)
  227. }
  228. var privateKeyPassphrase *string
  229. if ociAuthCredentials.PrivateKeyPassphrase.Name != "" {
  230. passphrase, err := GetStoreSecretData(ctx, store, kube, namespace, ociAuthCredentials.PrivateKeyPassphrase)
  231. if err != nil {
  232. return fmt.Errorf("failed to get secret data privateKeyPassphrase %w", err)
  233. }
  234. privateKeyPassphrase = &passphrase
  235. }
  236. fingerprint, err := GetStoreSecretData(ctx, store, kube, namespace, ociAuthCredentials.Fingerprint)
  237. if err != nil {
  238. return fmt.Errorf("failed to get secret data fingerprint %w", err)
  239. }
  240. userID, err := GetStoreSecretData(ctx, store, kube, namespace, ociAuthCredentials.UserID)
  241. if err != nil {
  242. return fmt.Errorf("failed to get secret data userId %w", err)
  243. }
  244. tenancyID, err := GetStoreSecretData(ctx, store, kube, namespace, ociAuthCredentials.TenancyID)
  245. if err != nil {
  246. return fmt.Errorf("failed to get secret data tenancyId %w", err)
  247. }
  248. region, err := GetStoreSecretData(ctx, store, kube, namespace, ociAuthCredentials.Region)
  249. if err != nil {
  250. return fmt.Errorf("failed to get secret data region %w", err)
  251. }
  252. _, err = sdkClient.Auth().OciAuthLogin(infisicalSdk.OciAuthLoginOptions{
  253. IdentityID: identityID,
  254. PrivateKey: privateKey,
  255. Passphrase: privateKeyPassphrase,
  256. Fingerprint: fingerprint,
  257. UserID: userID,
  258. TenancyID: tenancyID,
  259. Region: region,
  260. })
  261. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaOciAuth, err)
  262. if err != nil {
  263. return fmt.Errorf("failed to authenticate via oci auth %w", err)
  264. }
  265. return nil
  266. }
  267. func performKubernetesAuthLogin(
  268. ctx context.Context,
  269. store esv1.GenericStore,
  270. infisicalSpec *esv1.InfisicalProvider,
  271. sdkClient infisicalSdk.InfisicalClientInterface,
  272. kube kclient.Client,
  273. namespace string,
  274. ) error {
  275. kubernetesAuthCredentials := infisicalSpec.Auth.KubernetesAuthCredentials
  276. identityID, err := GetStoreSecretData(ctx, store, kube, namespace, kubernetesAuthCredentials.IdentityID)
  277. if err != nil {
  278. return fmt.Errorf(errSecretDataFormat, err)
  279. }
  280. serviceAccountTokenPath := ""
  281. if kubernetesAuthCredentials.ServiceAccountTokenPath.Name != "" {
  282. serviceAccountTokenPath, err = GetStoreSecretData(ctx, store, kube, namespace, kubernetesAuthCredentials.ServiceAccountTokenPath)
  283. if err != nil {
  284. return fmt.Errorf("failed to get secret data serviceAccountTokenPath %w", err)
  285. }
  286. }
  287. _, err = sdkClient.Auth().KubernetesAuthLogin(identityID, serviceAccountTokenPath)
  288. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaKubernetesAuth, err)
  289. if err != nil {
  290. return fmt.Errorf("failed to authenticate via kubernetes auth %w", err)
  291. }
  292. return nil
  293. }
  294. func performAwsAuthLogin(
  295. ctx context.Context,
  296. store esv1.GenericStore,
  297. infisicalSpec *esv1.InfisicalProvider,
  298. sdkClient infisicalSdk.InfisicalClientInterface,
  299. kube kclient.Client,
  300. namespace string,
  301. ) error {
  302. awsAuthCredentials := infisicalSpec.Auth.AwsAuthCredentials
  303. identityID, err := GetStoreSecretData(ctx, store, kube, namespace, awsAuthCredentials.IdentityID)
  304. if err != nil {
  305. return fmt.Errorf(errSecretDataFormat, err)
  306. }
  307. _, err = sdkClient.Auth().AwsIamAuthLogin(identityID)
  308. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaAwsAuth, err)
  309. if err != nil {
  310. return fmt.Errorf("failed to authenticate via aws auth %w", err)
  311. }
  312. return nil
  313. }
  314. func performTokenAuthLogin(
  315. ctx context.Context,
  316. store esv1.GenericStore,
  317. infisicalSpec *esv1.InfisicalProvider,
  318. sdkClient infisicalSdk.InfisicalClientInterface,
  319. kube kclient.Client,
  320. namespace string,
  321. ) error {
  322. tokenAuthCredentials := infisicalSpec.Auth.TokenAuthCredentials
  323. accessToken, err := GetStoreSecretData(ctx, store, kube, namespace, tokenAuthCredentials.AccessToken)
  324. if err != nil {
  325. return fmt.Errorf(errSecretDataFormat, err)
  326. }
  327. sdkClient.Auth().SetAccessToken(accessToken)
  328. metrics.ObserveAPICall(constants.ProviderName, machineIdentityLoginViaTokenAuth, err)
  329. return nil
  330. }
  331. // NewClient creates a new Infisical client.
  332. func (p *Provider) NewClient(ctx context.Context, store esv1.GenericStore, kube kclient.Client, namespace string) (esv1.SecretsClient, error) {
  333. storeSpec := store.GetSpec()
  334. if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.Infisical == nil {
  335. return nil, errors.New("invalid infisical store")
  336. }
  337. infisicalSpec := storeSpec.Provider.Infisical
  338. // Fetch CA certificate if configured
  339. var caCertificate string
  340. if len(infisicalSpec.CABundle) > 0 || infisicalSpec.CAProvider != nil {
  341. caCert, err := esutils.FetchCACertFromSource(ctx, esutils.CreateCertOpts{
  342. CABundle: infisicalSpec.CABundle,
  343. CAProvider: infisicalSpec.CAProvider,
  344. StoreKind: store.GetObjectKind().GroupVersionKind().Kind,
  345. Namespace: namespace,
  346. Client: kube,
  347. })
  348. if err != nil {
  349. return nil, fmt.Errorf("failed to get CA certificate: %w", err)
  350. }
  351. if caCert != nil {
  352. caCertificate = string(caCert)
  353. }
  354. }
  355. ctx, cancelSdkClient := context.WithCancel(ctx)
  356. sdkClient := infisicalSdk.NewInfisicalClient(ctx, infisicalSdk.Config{
  357. SiteUrl: infisicalSpec.HostAPI,
  358. CaCertificate: caCertificate,
  359. })
  360. secretPath := infisicalSpec.SecretsScope.SecretsPath
  361. if secretPath == "" {
  362. secretPath = "/"
  363. }
  364. var loginFn func(ctx context.Context, store esv1.GenericStore, infisicalSpec *esv1.InfisicalProvider, sdkClient infisicalSdk.InfisicalClientInterface, kube kclient.Client, namespace string) error
  365. var authMethod string
  366. switch {
  367. case infisicalSpec.Auth.UniversalAuthCredentials != nil:
  368. loginFn = performUniversalAuthLogin
  369. authMethod = machineIdentityLoginViaUniversalAuth
  370. case infisicalSpec.Auth.AzureAuthCredentials != nil:
  371. loginFn = performAzureAuthLogin
  372. authMethod = machineIdentityLoginViaAzureAuth
  373. case infisicalSpec.Auth.GcpIDTokenAuthCredentials != nil:
  374. loginFn = performGcpIDTokenAuthLogin
  375. authMethod = machineIdentityLoginViaGCPIDTokenAuth
  376. case infisicalSpec.Auth.GcpIamAuthCredentials != nil:
  377. loginFn = performGcpIamAuthLogin
  378. authMethod = machineIdentityLoginViaGcpServiceAccountAuth
  379. case infisicalSpec.Auth.JwtAuthCredentials != nil:
  380. loginFn = performJwtAuthLogin
  381. authMethod = machineIdentityLoginViaJwtAuth
  382. case infisicalSpec.Auth.LdapAuthCredentials != nil:
  383. loginFn = performLdapAuthLogin
  384. authMethod = machineIdentityLoginViaLdapAuth
  385. case infisicalSpec.Auth.OciAuthCredentials != nil:
  386. loginFn = performOciAuthLogin
  387. authMethod = machineIdentityLoginViaOciAuth
  388. case infisicalSpec.Auth.KubernetesAuthCredentials != nil:
  389. loginFn = performKubernetesAuthLogin
  390. authMethod = machineIdentityLoginViaKubernetesAuth
  391. case infisicalSpec.Auth.AwsAuthCredentials != nil:
  392. loginFn = performAwsAuthLogin
  393. authMethod = machineIdentityLoginViaAwsAuth
  394. case infisicalSpec.Auth.TokenAuthCredentials != nil:
  395. loginFn = performTokenAuthLogin
  396. authMethod = machineIdentityLoginViaTokenAuth
  397. default:
  398. cancelSdkClient()
  399. return nil, errors.New("authentication method not found")
  400. }
  401. if err := loginFn(ctx, store, infisicalSpec, sdkClient, kube, namespace); err != nil {
  402. cancelSdkClient()
  403. return nil, err
  404. }
  405. return &Provider{
  406. cancelSdkClient: cancelSdkClient,
  407. sdkClient: sdkClient,
  408. apiScope: &ClientScope{
  409. EnvironmentSlug: infisicalSpec.SecretsScope.EnvironmentSlug,
  410. ProjectSlug: infisicalSpec.SecretsScope.ProjectSlug,
  411. Recursive: infisicalSpec.SecretsScope.Recursive,
  412. SecretPath: secretPath,
  413. ExpandSecretReferences: infisicalSpec.SecretsScope.ExpandSecretReferences,
  414. },
  415. authMethod: authMethod,
  416. }, nil
  417. }
  418. // Close releases any resources used by the provider.
  419. func (p *Provider) Close(_ context.Context) error {
  420. p.cancelSdkClient()
  421. // Don't revoke token if token auth was used
  422. if p.authMethod == machineIdentityLoginViaTokenAuth {
  423. return nil
  424. }
  425. err := p.sdkClient.Auth().RevokeAccessToken()
  426. metrics.ObserveAPICall(constants.ProviderName, revokeAccessToken, err)
  427. return err
  428. }
  429. // GetStoreSecretData retrieves secret data from a Kubernetes secret using the provided reference.
  430. // It handles namespace resolution and returns the secret value as a string.
  431. func GetStoreSecretData(ctx context.Context, store esv1.GenericStore, kube kclient.Client, namespace string, secret esmeta.SecretKeySelector) (string, error) {
  432. secretRef := esmeta.SecretKeySelector{
  433. Name: secret.Name,
  434. Key: secret.Key,
  435. }
  436. if secret.Namespace != nil {
  437. secretRef.Namespace = secret.Namespace
  438. }
  439. secretData, err := resolvers.SecretKeyRef(ctx, kube, store.GetObjectKind().GroupVersionKind().Kind, namespace, &secretRef)
  440. if err != nil {
  441. return "", err
  442. }
  443. return secretData, nil
  444. }
  445. // ValidateStore validates the Infisical SecretStore configuration.
  446. // It checks for required fields and valid authentication settings.
  447. func (p *Provider) ValidateStore(store esv1.GenericStore) (admission.Warnings, error) {
  448. storeSpec := store.GetSpec()
  449. infisicalStoreSpec := storeSpec.Provider.Infisical
  450. if infisicalStoreSpec == nil {
  451. return nil, errors.New("invalid infisical store")
  452. }
  453. if err := validateSecretsScope(infisicalStoreSpec); err != nil {
  454. return nil, err
  455. }
  456. if err := validateCAProvider(store, infisicalStoreSpec); err != nil {
  457. return nil, err
  458. }
  459. if err := validateUniversalAuth(store, infisicalStoreSpec); err != nil {
  460. return nil, err
  461. }
  462. return nil, nil
  463. }
  464. func validateSecretsScope(spec *esv1.InfisicalProvider) error {
  465. if spec.SecretsScope.EnvironmentSlug == "" || spec.SecretsScope.ProjectSlug == "" {
  466. return errors.New("secretsScope.projectSlug and secretsScope.environmentSlug cannot be empty")
  467. }
  468. return nil
  469. }
  470. func validateCAProvider(store esv1.GenericStore, spec *esv1.InfisicalProvider) error {
  471. if spec.CAProvider == nil {
  472. return nil
  473. }
  474. storeKind := store.GetObjectKind().GroupVersionKind().Kind
  475. if storeKind == esv1.ClusterSecretStoreKind && spec.CAProvider.Namespace == nil {
  476. return errors.New("caProvider.namespace is required for ClusterSecretStore")
  477. }
  478. if storeKind == esv1.SecretStoreKind && spec.CAProvider.Namespace != nil {
  479. return errors.New("caProvider.namespace must be empty with SecretStore")
  480. }
  481. return nil
  482. }
  483. func validateUniversalAuth(store esv1.GenericStore, spec *esv1.InfisicalProvider) error {
  484. if spec.Auth.UniversalAuthCredentials == nil {
  485. return nil
  486. }
  487. uaCredential := spec.Auth.UniversalAuthCredentials
  488. if err := esutils.ValidateReferentSecretSelector(store, uaCredential.ClientID); err != nil {
  489. return err
  490. }
  491. if err := esutils.ValidateReferentSecretSelector(store, uaCredential.ClientSecret); err != nil {
  492. return err
  493. }
  494. if uaCredential.ClientID.Key == "" || uaCredential.ClientSecret.Key == "" {
  495. return errors.New("universalAuthCredentials.clientId and universalAuthCredentials.clientSecret cannot be empty")
  496. }
  497. return nil
  498. }
  499. // NewProvider creates a new Provider instance.
  500. func NewProvider() esv1.Provider {
  501. return &Provider{}
  502. }
  503. // ProviderSpec returns the provider specification for registration.
  504. func ProviderSpec() *esv1.SecretStoreProvider {
  505. return &esv1.SecretStoreProvider{
  506. Infisical: &esv1.InfisicalProvider{},
  507. }
  508. }
  509. // MaintenanceStatus returns the maintenance status of the provider.
  510. func MaintenanceStatus() esv1.MaintenanceStatus {
  511. return esv1.MaintenanceStatusMaintained
  512. }