provider.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  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 beyondtrust provides a Password Safe secrets provider for External Secrets Operator.
  14. package beyondtrust
  15. import (
  16. "context"
  17. "encoding/json"
  18. "errors"
  19. "fmt"
  20. "net/url"
  21. "strings"
  22. "time"
  23. auth "github.com/BeyondTrust/go-client-library-passwordsafe/api/authentication"
  24. "github.com/BeyondTrust/go-client-library-passwordsafe/api/entities"
  25. "github.com/BeyondTrust/go-client-library-passwordsafe/api/logging"
  26. managedaccount "github.com/BeyondTrust/go-client-library-passwordsafe/api/managed_account"
  27. "github.com/BeyondTrust/go-client-library-passwordsafe/api/secrets"
  28. "github.com/BeyondTrust/go-client-library-passwordsafe/api/utils"
  29. "github.com/cenkalti/backoff/v4"
  30. v1 "k8s.io/api/core/v1"
  31. ctrl "sigs.k8s.io/controller-runtime"
  32. "sigs.k8s.io/controller-runtime/pkg/client"
  33. "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
  34. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  35. esutils "github.com/external-secrets/external-secrets/runtime/esutils"
  36. "github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
  37. )
  38. const (
  39. errNilStore = "nil store found"
  40. errMissingStoreSpec = "store is missing spec"
  41. errMissingProvider = "storeSpec is missing provider"
  42. errInvalidProvider = "invalid provider spec. Missing field in store %s"
  43. errInvalidHostURL = "invalid host URL"
  44. errNoSuchKeyFmt = "no such key in secret: %q"
  45. errInvalidRetrievalPath = "invalid retrieval path. Provide one path, separator and name"
  46. errNotImplemented = "not implemented"
  47. usernameFieldName = "username"
  48. folderNameFieldName = "folder_name"
  49. fileNameFieldName = "file_name"
  50. titleFieldName = "title"
  51. descriptionFieldName = "description"
  52. ownerIDFieldName = "owner_id"
  53. groupIDFieldName = "group_id"
  54. ownerTypeFieldName = "owner_type"
  55. secretTypeFieldName = "secret_type"
  56. secretTypeCredential = "CREDENTIAL"
  57. )
  58. var (
  59. errSecretRefAndValueConflict = errors.New("cannot specify both secret reference and value")
  60. errMissingSecretName = errors.New("must specify a secret name")
  61. errMissingSecretKey = errors.New("must specify a secret key")
  62. // ESOLogger is the logger instance for the Beyondtrust provider.
  63. ESOLogger = ctrl.Log.WithName("provider").WithName("beyondtrust")
  64. maxFileSecretSizeBytes = 5000000
  65. )
  66. // Provider is a Password Safe secrets provider implementing NewClient and ValidateStore for the esv1.Provider interface.
  67. type Provider struct {
  68. apiURL string
  69. retrievaltype string
  70. decrypt bool
  71. authenticate auth.AuthenticationObj
  72. log logging.LogrLogger
  73. separator string
  74. }
  75. // AuthenticatorInput is used to pass parameters to the getAuthenticator function.
  76. type AuthenticatorInput struct {
  77. Config *esv1.BeyondtrustProvider
  78. HTTPClientObj utils.HttpClientObj
  79. BackoffDefinition *backoff.ExponentialBackOff
  80. APIURL string
  81. APIVersion string
  82. ClientID string
  83. ClientSecret string
  84. APIKey string
  85. Logger *logging.LogrLogger
  86. RetryMaxElapsedTimeMinutes int
  87. }
  88. // Capabilities implements v1beta1.Provider.
  89. func (*Provider) Capabilities() esv1.SecretStoreCapabilities {
  90. return esv1.SecretStoreReadWrite
  91. }
  92. // Close implements v1beta1.SecretsClient.
  93. func (*Provider) Close(_ context.Context) error {
  94. return nil
  95. }
  96. // DeleteSecret implements v1beta1.SecretsClient.
  97. func (*Provider) DeleteSecret(_ context.Context, _ esv1.PushSecretRemoteRef) error {
  98. return errors.New(errNotImplemented)
  99. }
  100. // GetSecretMap implements v1beta1.SecretsClient.
  101. func (*Provider) GetSecretMap(_ context.Context, _ esv1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  102. return make(map[string][]byte), errors.New(errNotImplemented)
  103. }
  104. // Validate implements v1beta1.SecretsClient.
  105. func (p *Provider) Validate() (esv1.ValidationResult, error) {
  106. timeout := 15 * time.Second
  107. clientURL := p.apiURL
  108. if err := esutils.NetworkValidate(clientURL, timeout); err != nil {
  109. ESOLogger.Error(err, "Network Validate", "clientURL:", clientURL)
  110. return esv1.ValidationResultError, err
  111. }
  112. return esv1.ValidationResultReady, nil
  113. }
  114. // SecretExists checks if a secret exists in the provider.
  115. func (p *Provider) SecretExists(_ context.Context, pushSecretRef esv1.PushSecretRemoteRef) (bool, error) {
  116. logger := logging.NewLogrLogger(&ESOLogger)
  117. secretObj, err := secrets.NewSecretObj(p.authenticate, logger, maxFileSecretSizeBytes, false)
  118. if err != nil {
  119. return false, err
  120. }
  121. _, err = secretObj.SearchSecretByTitleFlow(pushSecretRef.GetRemoteKey())
  122. if err == nil {
  123. return true, nil
  124. }
  125. return false, nil
  126. }
  127. // NewClient this is where we initialize the SecretClient and return it for the controller to use.
  128. func (p *Provider) NewClient(ctx context.Context, store esv1.GenericStore, kube client.Client, namespace string) (esv1.SecretsClient, error) {
  129. config := store.GetSpec().Provider.Beyondtrust
  130. logger := logging.NewLogrLogger(&ESOLogger)
  131. storeKind := store.GetKind()
  132. clientID, clientSecret, apiKey, err := loadCredentialsFromConfig(ctx, config, kube, namespace, storeKind)
  133. if err != nil {
  134. return nil, fmt.Errorf("error loading credentials: %w", err)
  135. }
  136. certificate, certificateKey, err := loadCertificateFromConfig(ctx, config, kube, namespace, storeKind)
  137. if err != nil {
  138. return nil, fmt.Errorf("error loading certificate: %w", err)
  139. }
  140. clientTimeOutInSeconds, separator, retryMaxElapsedTimeMinutes := getConfigValues(config)
  141. backoffDefinition := getBackoffDefinition(retryMaxElapsedTimeMinutes)
  142. params := utils.ValidationParams{
  143. ApiKey: apiKey,
  144. ClientID: clientID,
  145. ClientSecret: clientSecret,
  146. ApiUrl: &config.Server.APIURL,
  147. ApiVersion: config.Server.APIVersion,
  148. ClientTimeOutInSeconds: clientTimeOutInSeconds,
  149. Separator: &separator,
  150. VerifyCa: config.Server.VerifyCA,
  151. Logger: logger,
  152. Certificate: certificate,
  153. CertificateKey: certificateKey,
  154. RetryMaxElapsedTimeMinutes: &retryMaxElapsedTimeMinutes,
  155. MaxFileSecretSizeBytes: &maxFileSecretSizeBytes,
  156. }
  157. if err := validateInputs(params); err != nil {
  158. return nil, fmt.Errorf("error in Inputs: %w", err)
  159. }
  160. httpClient, err := utils.GetHttpClient(clientTimeOutInSeconds, config.Server.VerifyCA, certificate, certificateKey, logger)
  161. if err != nil {
  162. return nil, fmt.Errorf("error creating HTTP client: %w", err)
  163. }
  164. authenticatorInput := AuthenticatorInput{
  165. Config: config,
  166. HTTPClientObj: *httpClient,
  167. BackoffDefinition: backoffDefinition,
  168. APIURL: config.Server.APIURL,
  169. APIVersion: config.Server.APIVersion,
  170. ClientID: clientID,
  171. ClientSecret: clientSecret,
  172. APIKey: apiKey,
  173. Logger: logger,
  174. RetryMaxElapsedTimeMinutes: retryMaxElapsedTimeMinutes,
  175. }
  176. authenticate, err := getAuthenticator(authenticatorInput)
  177. if err != nil {
  178. return nil, fmt.Errorf("error authenticating: %w", err)
  179. }
  180. return &Provider{
  181. apiURL: config.Server.APIURL,
  182. retrievaltype: config.Server.RetrievalType,
  183. authenticate: *authenticate,
  184. log: *logger,
  185. separator: separator,
  186. decrypt: config.Server.Decrypt,
  187. }, nil
  188. }
  189. func loadCredentialsFromConfig(ctx context.Context, config *esv1.BeyondtrustProvider, kube client.Client, namespace, storeKind string) (string, string, string, error) {
  190. if config.Auth.APIKey != nil {
  191. apiKey, err := loadConfigSecret(ctx, config.Auth.APIKey, kube, namespace, storeKind)
  192. return "", "", apiKey, err
  193. }
  194. clientID, err := loadConfigSecret(ctx, config.Auth.ClientID, kube, namespace, storeKind)
  195. if err != nil {
  196. return "", "", "", fmt.Errorf("error loading clientID: %w", err)
  197. }
  198. clientSecret, err := loadConfigSecret(ctx, config.Auth.ClientSecret, kube, namespace, storeKind)
  199. if err != nil {
  200. return "", "", "", fmt.Errorf("error loading clientSecret: %w", err)
  201. }
  202. return clientID, clientSecret, "", nil
  203. }
  204. func loadCertificateFromConfig(ctx context.Context, config *esv1.BeyondtrustProvider, kube client.Client, namespace, storeKind string) (string, string, error) {
  205. if config.Auth.Certificate == nil || config.Auth.CertificateKey == nil {
  206. return "", "", nil
  207. }
  208. certificate, err := loadConfigSecret(ctx, config.Auth.Certificate, kube, namespace, storeKind)
  209. if err != nil {
  210. return "", "", fmt.Errorf("error loading Certificate: %w", err)
  211. }
  212. certificateKey, err := loadConfigSecret(ctx, config.Auth.CertificateKey, kube, namespace, storeKind)
  213. if err != nil {
  214. return "", "", fmt.Errorf("error loading Certificate Key: %w", err)
  215. }
  216. return certificate, certificateKey, nil
  217. }
  218. func getConfigValues(config *esv1.BeyondtrustProvider) (int, string, int) {
  219. clientTimeOutInSeconds := 45
  220. separator := "/"
  221. retryMaxElapsedTimeMinutes := 15
  222. if config.Server.ClientTimeOutSeconds != 0 {
  223. clientTimeOutInSeconds = config.Server.ClientTimeOutSeconds
  224. }
  225. if config.Server.Separator != "" {
  226. separator = config.Server.Separator
  227. }
  228. return clientTimeOutInSeconds, separator, retryMaxElapsedTimeMinutes
  229. }
  230. func getBackoffDefinition(retryMaxElapsedTimeMinutes int) *backoff.ExponentialBackOff {
  231. backoffDefinition := backoff.NewExponentialBackOff()
  232. backoffDefinition.InitialInterval = 1 * time.Second
  233. backoffDefinition.MaxElapsedTime = time.Duration(retryMaxElapsedTimeMinutes) * time.Minute
  234. backoffDefinition.RandomizationFactor = 0.5
  235. return backoffDefinition
  236. }
  237. func validateInputs(params utils.ValidationParams) error {
  238. return utils.ValidateInputs(params)
  239. }
  240. func getAuthenticator(input AuthenticatorInput) (*auth.AuthenticationObj, error) {
  241. parametersObj := auth.AuthenticationParametersObj{
  242. HTTPClient: input.HTTPClientObj,
  243. BackoffDefinition: input.BackoffDefinition,
  244. EndpointURL: input.APIURL,
  245. APIVersion: input.APIVersion,
  246. ApiKey: input.APIKey,
  247. Logger: input.Logger,
  248. RetryMaxElapsedTimeSeconds: input.RetryMaxElapsedTimeMinutes,
  249. }
  250. if input.Config.Auth.APIKey != nil {
  251. parametersObj.ApiKey = input.APIKey
  252. return auth.AuthenticateUsingApiKey(parametersObj)
  253. }
  254. parametersObj.ClientID = input.ClientID
  255. parametersObj.ClientSecret = input.ClientSecret
  256. return auth.Authenticate(parametersObj)
  257. }
  258. func loadConfigSecret(ctx context.Context, ref *esv1.BeyondTrustProviderSecretRef, kube client.Client, defaultNamespace, storeKind string) (string, error) {
  259. if ref.SecretRef == nil {
  260. return ref.Value, nil
  261. }
  262. if err := validateSecretRef(ref); err != nil {
  263. return "", err
  264. }
  265. return resolvers.SecretKeyRef(ctx, kube, storeKind, defaultNamespace, ref.SecretRef)
  266. }
  267. func validateSecretRef(ref *esv1.BeyondTrustProviderSecretRef) error {
  268. if ref.SecretRef != nil {
  269. if ref.Value != "" {
  270. return errSecretRefAndValueConflict
  271. }
  272. if ref.SecretRef.Name == "" {
  273. return errMissingSecretName
  274. }
  275. if ref.SecretRef.Key == "" {
  276. return errMissingSecretKey
  277. }
  278. }
  279. return nil
  280. }
  281. // GetAllSecrets retrieves all secrets from Beyondtrust.
  282. func (p *Provider) GetAllSecrets(_ context.Context, _ esv1.ExternalSecretFind) (map[string][]byte, error) {
  283. return nil, errors.New("GetAllSecrets not implemented")
  284. }
  285. // GetSecret reads the secret from the Password Safe server and returns it. The controller uses the value here to
  286. // create the Kubernetes secret.
  287. func (p *Provider) GetSecret(_ context.Context, ref esv1.ExternalSecretDataRemoteRef) ([]byte, error) {
  288. managedAccountType := !strings.EqualFold(p.retrievaltype, "SECRET")
  289. retrievalPaths := utils.ValidatePaths([]string{ref.Key}, managedAccountType, p.separator, &p.log)
  290. if len(retrievalPaths) != 1 {
  291. return nil, errors.New(errInvalidRetrievalPath)
  292. }
  293. retrievalPath := retrievalPaths[0]
  294. _, err := p.authenticate.GetPasswordSafeAuthentication()
  295. if err != nil {
  296. return nil, fmt.Errorf("error getting authentication: %w", err)
  297. }
  298. managedFetch := func() (string, error) {
  299. ESOLogger.Info("retrieve managed account value", "retrievalPath:", retrievalPath)
  300. manageAccountObj, _ := managedaccount.NewManagedAccountObj(p.authenticate, &p.log)
  301. return manageAccountObj.GetSecret(retrievalPath, p.separator)
  302. }
  303. unmanagedFetch := func() (string, error) {
  304. ESOLogger.Info("retrieve secrets safe value", "retrievalPath:", retrievalPath)
  305. secretObj, _ := secrets.NewSecretObj(p.authenticate, &p.log, maxFileSecretSizeBytes, p.decrypt)
  306. return secretObj.GetSecret(retrievalPath, p.separator)
  307. }
  308. fetch := unmanagedFetch
  309. if managedAccountType {
  310. fetch = managedFetch
  311. }
  312. returnSecret, err := fetch()
  313. if err != nil {
  314. if serr := p.authenticate.SignOut(); serr != nil {
  315. return nil, errors.Join(err, serr)
  316. }
  317. return nil, fmt.Errorf("error getting secret/managed account: %w", err)
  318. }
  319. return []byte(returnSecret), nil
  320. }
  321. // ValidateStore validates the store configuration to prevent unexpected errors.
  322. func (p *Provider) ValidateStore(store esv1.GenericStore) (admission.Warnings, error) {
  323. if store == nil {
  324. return nil, errors.New(errNilStore)
  325. }
  326. spec := store.GetSpec()
  327. if spec == nil {
  328. return nil, errors.New(errMissingStoreSpec)
  329. }
  330. if spec.Provider == nil {
  331. return nil, errors.New(errMissingProvider)
  332. }
  333. provider := spec.Provider.Beyondtrust
  334. if provider == nil {
  335. return nil, fmt.Errorf(errInvalidProvider, store.GetObjectMeta().String())
  336. }
  337. apiURL, err := url.Parse(provider.Server.APIURL)
  338. if err != nil {
  339. return nil, errors.New(errInvalidHostURL)
  340. }
  341. if provider.Auth.ClientID.SecretRef != nil {
  342. return nil, err
  343. }
  344. if provider.Auth.ClientSecret.SecretRef != nil {
  345. return nil, err
  346. }
  347. if apiURL.Host == "" {
  348. return nil, errors.New(errInvalidHostURL)
  349. }
  350. return nil, nil
  351. }
  352. // NewProvider creates a new Provider instance.
  353. func NewProvider() esv1.Provider {
  354. return &Provider{}
  355. }
  356. // ProviderSpec returns the provider specification for registration.
  357. func ProviderSpec() *esv1.SecretStoreProvider {
  358. return &esv1.SecretStoreProvider{
  359. Beyondtrust: &esv1.BeyondtrustProvider{},
  360. }
  361. }
  362. // MaintenanceStatus returns the maintenance status of the provider.
  363. func MaintenanceStatus() esv1.MaintenanceStatus {
  364. return esv1.MaintenanceStatusMaintained
  365. }
  366. // PushSecret implements v1beta1.SecretsClient.
  367. func (p *Provider) PushSecret(_ context.Context, secret *v1.Secret, psd esv1.PushSecretData) error {
  368. ESOLogger.Info("Pushing secret to BeyondTrust Password Safe")
  369. value, err := esutils.ExtractSecretData(psd, secret)
  370. if err != nil {
  371. return fmt.Errorf("extract secret data failed: %w", err)
  372. }
  373. secretValue := string(value)
  374. metadata := psd.GetMetadata()
  375. data, err := json.Marshal(metadata)
  376. if err != nil {
  377. return fmt.Errorf("Error getting metadata: %w", err)
  378. }
  379. var metaDataObject map[string]interface{}
  380. err = json.Unmarshal(data, &metaDataObject)
  381. if err != nil {
  382. return fmt.Errorf("Error in parameters: %w", err)
  383. }
  384. signAppinResponse, err := p.authenticate.GetPasswordSafeAuthentication()
  385. if err != nil {
  386. return fmt.Errorf("Error in authentication: %w", err)
  387. }
  388. err = p.CreateSecret(secretValue, metaDataObject, signAppinResponse)
  389. if err != nil {
  390. return fmt.Errorf("Error in creating the secret: %w", err)
  391. }
  392. return nil
  393. }
  394. // CreateSecret creates a secret in BeyondTrust Password Safe.
  395. func (p *Provider) CreateSecret(secret string, data map[string]interface{}, signAppinResponse entities.SignAppinResponse) error {
  396. logger := logging.NewLogrLogger(&ESOLogger)
  397. secretObj, err := secrets.NewSecretObj(p.authenticate, logger, maxFileSecretSizeBytes, false)
  398. if err != nil {
  399. return err
  400. }
  401. username := utils.GetStringField(data, usernameFieldName, "")
  402. folderName := utils.GetStringField(data, folderNameFieldName, "")
  403. fileName := utils.GetStringField(data, fileNameFieldName, "")
  404. title := utils.GetStringField(data, titleFieldName, "")
  405. description := utils.GetStringField(data, descriptionFieldName, "")
  406. ownerID := utils.GetIntField(data, ownerIDFieldName, 0)
  407. groupID := utils.GetIntField(data, groupIDFieldName, 0)
  408. ownerType := utils.GetStringField(data, ownerTypeFieldName, "")
  409. secretType := utils.GetStringField(data, secretTypeFieldName, secretTypeCredential)
  410. var notes string
  411. var urls []entities.UrlDetails
  412. var ownerDetailsOwnerID []entities.OwnerDetailsOwnerId
  413. var ownerDetailsGroupID []entities.OwnerDetailsGroupId
  414. _, ok := data["notes"]
  415. if ok {
  416. notes = data["notes"].(string)
  417. }
  418. _, ok = data["urls"]
  419. if ok {
  420. urls = utils.GetUrlsDetailsList(data)
  421. }
  422. ownerDetailsOwnerID = utils.GetOwnerDetailsOwnerIdList(data, signAppinResponse)
  423. ownerDetailsGroupID = utils.GetOwnerDetailsGroupIdList(data, groupID, signAppinResponse)
  424. secretDetailsConfig := entities.SecretDetailsBaseConfig{
  425. Title: title,
  426. Description: description,
  427. Urls: urls,
  428. Notes: notes,
  429. }
  430. var configMap map[string]interface{}
  431. switch strings.ToUpper(secretType) {
  432. case "CREDENTIAL":
  433. secretCredentialDetailsConfig30 := entities.SecretCredentialDetailsConfig30{
  434. SecretDetailsBaseConfig: secretDetailsConfig,
  435. Username: username,
  436. Password: secret,
  437. OwnerId: ownerID,
  438. OwnerType: ownerType,
  439. Owners: ownerDetailsOwnerID,
  440. }
  441. secretCredentialDetailsConfig31 := entities.SecretCredentialDetailsConfig31{
  442. SecretDetailsBaseConfig: secretDetailsConfig,
  443. Username: username,
  444. Password: secret,
  445. Owners: ownerDetailsGroupID,
  446. }
  447. configMap = map[string]interface{}{
  448. "3.0": secretCredentialDetailsConfig30,
  449. "3.1": secretCredentialDetailsConfig31,
  450. }
  451. case "FILE":
  452. secretFileDetailsConfig30 := entities.SecretFileDetailsConfig30{
  453. SecretDetailsBaseConfig: secretDetailsConfig,
  454. FileContent: secret,
  455. FileName: fileName,
  456. OwnerId: ownerID,
  457. OwnerType: ownerType,
  458. Owners: ownerDetailsOwnerID,
  459. }
  460. secretFileDetailsConfig31 := entities.SecretFileDetailsConfig31{
  461. SecretDetailsBaseConfig: secretDetailsConfig,
  462. FileContent: secret,
  463. FileName: fileName,
  464. Owners: ownerDetailsGroupID,
  465. }
  466. configMap = map[string]interface{}{
  467. "3.0": secretFileDetailsConfig30,
  468. "3.1": secretFileDetailsConfig31,
  469. }
  470. case "TEXT":
  471. secretTextDetailsConfig30 := entities.SecretTextDetailsConfig30{
  472. SecretDetailsBaseConfig: secretDetailsConfig,
  473. Text: secret,
  474. OwnerId: ownerID,
  475. OwnerType: ownerType,
  476. Owners: ownerDetailsOwnerID,
  477. }
  478. secretTextDetailsConfig31 := entities.SecretTextDetailsConfig31{
  479. SecretDetailsBaseConfig: secretDetailsConfig,
  480. Text: secret,
  481. Owners: ownerDetailsGroupID,
  482. }
  483. configMap = map[string]interface{}{
  484. "3.0": secretTextDetailsConfig30,
  485. "3.1": secretTextDetailsConfig31,
  486. }
  487. default:
  488. return fmt.Errorf("Unknown secret type")
  489. }
  490. secretDetails, exists := configMap[p.authenticate.ApiVersion]
  491. if !exists {
  492. return fmt.Errorf("unsupported API version: %v", &p.authenticate.ApiVersion)
  493. }
  494. _, err = secretObj.CreateSecretFlow(folderName, secretDetails)
  495. if err != nil {
  496. return err
  497. }
  498. ESOLogger.Info("Secret pushed to BeyondTrust Password Safe")
  499. return nil
  500. }