conjur.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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 addon
  13. import (
  14. "crypto/rand"
  15. "encoding/base64"
  16. "fmt"
  17. "strings"
  18. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  19. // nolint
  20. ginkgo "github.com/onsi/ginkgo/v2"
  21. "github.com/cyberark/conjur-api-go/conjurapi"
  22. "github.com/cyberark/conjur-api-go/conjurapi/authn"
  23. "github.com/external-secrets/external-secrets-e2e/framework/util"
  24. )
  25. type Conjur struct {
  26. chart *HelmChart
  27. dataKey string
  28. Namespace string
  29. PodName string
  30. ConjurClient *conjurapi.Client
  31. ConjurURL string
  32. AdminApiKey string
  33. ConjurServerCA []byte
  34. }
  35. func NewConjur(namespace string) *Conjur {
  36. repo := "conjur-" + namespace
  37. dataKey := generateConjurDataKey()
  38. return &Conjur{
  39. dataKey: dataKey,
  40. chart: &HelmChart{
  41. Namespace: namespace,
  42. ReleaseName: fmt.Sprintf("conjur-%s", namespace), // avoid cluster role collision
  43. Chart: fmt.Sprintf("%s/conjur-oss", repo),
  44. ChartVersion: "2.0.7",
  45. Repo: ChartRepo{
  46. Name: repo,
  47. URL: "https://cyberark.github.io/helm-charts",
  48. },
  49. Values: []string{"/k8s/conjur.values.yaml"},
  50. Vars: []StringTuple{
  51. {
  52. Key: "dataKey",
  53. Value: dataKey,
  54. },
  55. },
  56. },
  57. Namespace: namespace,
  58. }
  59. }
  60. func (l *Conjur) Install() error {
  61. ginkgo.By("Installing conjur in " + l.Namespace)
  62. err := l.chart.Install()
  63. if err != nil {
  64. return err
  65. }
  66. err = l.initConjur()
  67. if err != nil {
  68. return err
  69. }
  70. err = l.configureConjur()
  71. if err != nil {
  72. return err
  73. }
  74. return nil
  75. }
  76. func (l *Conjur) initConjur() error {
  77. ginkgo.By("Waiting for conjur pods to be running")
  78. pl, err := util.WaitForPodsRunning(l.chart.config.KubeClientSet, 1, l.Namespace, metav1.ListOptions{
  79. LabelSelector: "app=conjur-oss",
  80. })
  81. if err != nil {
  82. return fmt.Errorf("error waiting for conjur to be running: %w", err)
  83. }
  84. l.PodName = pl.Items[0].Name
  85. ginkgo.By("Initializing conjur")
  86. // Get the auto generated certificates from the K8s secrets
  87. caCertSecret, err := util.GetKubeSecret(l.chart.config.KubeClientSet, l.Namespace, fmt.Sprintf("%s-conjur-ssl-ca-cert", l.chart.ReleaseName))
  88. if err != nil {
  89. return fmt.Errorf("error getting conjur ca cert: %w", err)
  90. }
  91. l.ConjurServerCA = caCertSecret.Data["tls.crt"]
  92. // Create "default" account
  93. _, err = util.ExecCmdWithContainer(
  94. l.chart.config.KubeClientSet,
  95. l.chart.config.KubeConfig,
  96. l.PodName, "conjur-oss", l.Namespace, "conjurctl account create default")
  97. if err != nil {
  98. return fmt.Errorf("error initializing conjur: %w", err)
  99. }
  100. // Retrieve the admin API key
  101. apiKey, err := util.ExecCmdWithContainer(
  102. l.chart.config.KubeClientSet,
  103. l.chart.config.KubeConfig,
  104. l.PodName, "conjur-oss", l.Namespace, "conjurctl role retrieve-key default:user:admin")
  105. if err != nil {
  106. return fmt.Errorf("error fetching admin API key: %w", err)
  107. }
  108. // TODO: ExecCmdWithContainer includes the StdErr output with a warning about config directory.
  109. // Therefore we need to split the output and only use the first line.
  110. l.AdminApiKey = strings.Split(apiKey, "\n")[0]
  111. l.ConjurURL = fmt.Sprintf("https://conjur-%s-conjur-oss.%s.svc.cluster.local", l.Namespace, l.Namespace)
  112. cfg := conjurapi.Config{
  113. Account: "default",
  114. ApplianceURL: l.ConjurURL,
  115. SSLCert: string(l.ConjurServerCA),
  116. }
  117. l.ConjurClient, err = conjurapi.NewClientFromKey(cfg, authn.LoginPair{
  118. Login: "admin",
  119. APIKey: l.AdminApiKey,
  120. })
  121. if err != nil {
  122. return fmt.Errorf("unable to create conjur client: %w", err)
  123. }
  124. return nil
  125. }
  126. func (l *Conjur) configureConjur() error {
  127. ginkgo.By("configuring conjur")
  128. // TODO: This will be used for the JWT tests
  129. return nil
  130. }
  131. func (l *Conjur) Logs() error {
  132. return l.chart.Logs()
  133. }
  134. func (l *Conjur) Uninstall() error {
  135. return l.chart.Uninstall()
  136. }
  137. func (l *Conjur) Setup(cfg *Config) error {
  138. return l.chart.Setup(cfg)
  139. }
  140. func generateConjurDataKey() string {
  141. // Generate a 32 byte cryptographically secure random string.
  142. // Normally this is done by running `conjurctl data-key generate`
  143. // but for test purposes we can generate it programmatically.
  144. b := make([]byte, 32)
  145. _, err := rand.Read(b)
  146. if err != nil {
  147. panic(fmt.Errorf("unable to generate random string: %w", err))
  148. }
  149. // Encode the bytes as a base64 string
  150. return base64.StdEncoding.EncodeToString(b)
  151. }