Browse Source

Conjur E2E Tests for API Key Authentication (#3120)

Signed-off-by: Shlomo Heigh <shlomo.heigh@cyberark.com>
Shlomo Zalman Heigh 2 years ago
parent
commit
8922003ab9

+ 179 - 0
e2e/framework/addon/conjur.go

@@ -0,0 +1,179 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package addon
+
+import (
+	"crypto/rand"
+	"encoding/base64"
+	"fmt"
+	"strings"
+
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	// nolint
+	ginkgo "github.com/onsi/ginkgo/v2"
+
+	"github.com/cyberark/conjur-api-go/conjurapi"
+	"github.com/cyberark/conjur-api-go/conjurapi/authn"
+	"github.com/external-secrets/external-secrets-e2e/framework/util"
+)
+
+type Conjur struct {
+	chart        *HelmChart
+	dataKey      string
+	Namespace    string
+	PodName      string
+	ConjurClient *conjurapi.Client
+	ConjurURL    string
+
+	AdminApiKey    string
+	ConjurServerCA []byte
+}
+
+func NewConjur(namespace string) *Conjur {
+	repo := "conjur-" + namespace
+	dataKey := generateConjurDataKey()
+
+	return &Conjur{
+		dataKey: dataKey,
+		chart: &HelmChart{
+			Namespace:    namespace,
+			ReleaseName:  fmt.Sprintf("conjur-%s", namespace), // avoid cluster role collision
+			Chart:        fmt.Sprintf("%s/conjur-oss", repo),
+			ChartVersion: "2.0.7",
+			Repo: ChartRepo{
+				Name: repo,
+				URL:  "https://cyberark.github.io/helm-charts",
+			},
+			Values: []string{"/k8s/conjur.values.yaml"},
+			Vars: []StringTuple{
+				{
+					Key:   "dataKey",
+					Value: dataKey,
+				},
+			},
+		},
+		Namespace: namespace,
+	}
+}
+
+func (l *Conjur) Install() error {
+	ginkgo.By("Installing conjur in " + l.Namespace)
+	err := l.chart.Install()
+	if err != nil {
+		return err
+	}
+
+	err = l.initConjur()
+	if err != nil {
+		return err
+	}
+
+	err = l.configureConjur()
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (l *Conjur) initConjur() error {
+	ginkgo.By("Waiting for conjur pods to be running")
+	pl, err := util.WaitForPodsRunning(l.chart.config.KubeClientSet, 1, l.Namespace, metav1.ListOptions{
+		LabelSelector: "app=conjur-oss",
+	})
+	if err != nil {
+		return fmt.Errorf("error waiting for conjur to be running: %w", err)
+	}
+	l.PodName = pl.Items[0].Name
+
+	ginkgo.By("Initializing conjur")
+	// Get the auto generated certificates from the K8s secrets
+	caCertSecret, err := util.GetKubeSecret(l.chart.config.KubeClientSet, l.Namespace, fmt.Sprintf("%s-conjur-ssl-ca-cert", l.chart.ReleaseName))
+	if err != nil {
+		return fmt.Errorf("error getting conjur ca cert: %w", err)
+	}
+	l.ConjurServerCA = caCertSecret.Data["tls.crt"]
+
+	// Create "default" account
+	_, err = util.ExecCmdWithContainer(
+		l.chart.config.KubeClientSet,
+		l.chart.config.KubeConfig,
+		l.PodName, "conjur-oss", l.Namespace, "conjurctl account create default")
+	if err != nil {
+		return fmt.Errorf("error initializing conjur: %w", err)
+	}
+
+	// Retrieve the admin API key
+	apiKey, err := util.ExecCmdWithContainer(
+		l.chart.config.KubeClientSet,
+		l.chart.config.KubeConfig,
+		l.PodName, "conjur-oss", l.Namespace, "conjurctl role retrieve-key default:user:admin")
+	if err != nil {
+		return fmt.Errorf("error fetching admin API key: %w", err)
+	}
+
+	// TODO: ExecCmdWithContainer includes the StdErr output with a warning about config directory.
+	// Therefore we need to split the output and only use the first line.
+	l.AdminApiKey = strings.Split(apiKey, "\n")[0]
+
+	l.ConjurURL = fmt.Sprintf("https://conjur-%s-conjur-oss.%s.svc.cluster.local", l.Namespace, l.Namespace)
+	cfg := conjurapi.Config{
+		Account:      "default",
+		ApplianceURL: l.ConjurURL,
+		SSLCert:      string(l.ConjurServerCA),
+	}
+
+	l.ConjurClient, err = conjurapi.NewClientFromKey(cfg, authn.LoginPair{
+		Login:  "admin",
+		APIKey: l.AdminApiKey,
+	})
+	if err != nil {
+		return fmt.Errorf("unable to create conjur client: %w", err)
+	}
+
+	return nil
+}
+
+func (l *Conjur) configureConjur() error {
+	ginkgo.By("configuring conjur")
+	// TODO: This will be used for the JWT tests
+	return nil
+}
+
+func (l *Conjur) Logs() error {
+	return l.chart.Logs()
+}
+
+func (l *Conjur) Uninstall() error {
+	return l.chart.Uninstall()
+}
+
+func (l *Conjur) Setup(cfg *Config) error {
+	return l.chart.Setup(cfg)
+}
+
+func generateConjurDataKey() string {
+	// Generate a 32 byte cryptographically secure random string.
+	// Normally this is done by running `conjurctl data-key generate`
+	// but for test purposes we can generate it programmatically.
+	b := make([]byte, 32)
+	_, err := rand.Read(b)
+	if err != nil {
+		panic(fmt.Errorf("unable to generate random string: %w", err))
+	}
+
+	// Encode the bytes as a base64 string
+	return base64.StdEncoding.EncodeToString(b)
+}

+ 21 - 5
e2e/framework/util/util.go

@@ -100,6 +100,17 @@ func namespaceNotExist(c kubernetes.Interface, namespace string) wait.ConditionF
 // ExecCmd exec command on specific pod and wait the command's output.
 func ExecCmd(client kubernetes.Interface, config *restclient.Config, podName, namespace string,
 	command string) (string, error) {
+	return execCmd(client, config, podName, "", namespace, command)
+}
+
+// ExecCmdWithContainer exec command on specific container in a specific pod and wait the command's output.
+func ExecCmdWithContainer(client kubernetes.Interface, config *restclient.Config, podName, containerName, namespace string,
+	command string) (string, error) {
+	return execCmd(client, config, podName, containerName, namespace, command)
+}
+
+func execCmd(client kubernetes.Interface, config *restclient.Config, podName, containerName, namespace string,
+	command string) (string, error) {
 	cmd := []string{
 		"sh",
 		"-c",
@@ -109,11 +120,12 @@ func ExecCmd(client kubernetes.Interface, config *restclient.Config, podName, na
 	req := client.CoreV1().RESTClient().Post().Resource("pods").Name(podName).
 		Namespace(namespace).SubResource("exec")
 	option := &v1.PodExecOptions{
-		Command: cmd,
-		Stdin:   false,
-		Stdout:  true,
-		Stderr:  true,
-		TTY:     false,
+		Command:   cmd,
+		Container: containerName,
+		Stdin:     false,
+		Stdout:    true,
+		Stderr:    true,
+		TTY:       false,
 	}
 	req.VersionedParams(
 		option,
@@ -251,6 +263,10 @@ func GetKubeSA(baseName string, kubeClientSet kubernetes.Interface, ns string) (
 	return kubeClientSet.CoreV1().ServiceAccounts(ns).Get(context.TODO(), baseName, metav1.GetOptions{})
 }
 
+func GetKubeSecret(client kubernetes.Interface, namespace, secretName string) (*v1.Secret, error) {
+	return client.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
+}
+
 // NewConfig loads and returns the kubernetes credentials from the environment.
 // KUBECONFIG env var takes precedence and falls back to in-cluster config.
 func NewConfig() (*restclient.Config, *kubernetes.Clientset, crclient.Client) {

+ 7 - 0
e2e/go.mod

@@ -47,6 +47,7 @@ require (
 	github.com/akeylesslabs/akeyless-go/v3 v3.6.1
 	github.com/aliyun/alibaba-cloud-sdk-go v1.62.271
 	github.com/aws/aws-sdk-go v1.50.20
+	github.com/cyberark/conjur-api-go v0.11.1
 	github.com/external-secrets/external-secrets v0.0.0
 	github.com/fluxcd/helm-controller/api v0.37.2
 	github.com/fluxcd/pkg/apis/meta v1.2.0
@@ -89,9 +90,12 @@ require (
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver/v3 v3.2.1 // indirect
 	github.com/Masterminds/sprig/v3 v3.2.3 // indirect
+	github.com/alessio/shellescape v1.4.2 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
 	github.com/cenkalti/backoff/v3 v3.2.2 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
+	github.com/danieljoos/wincred v1.2.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
@@ -109,6 +113,7 @@ require (
 	github.com/go-openapi/swag v0.22.9 // indirect
 	github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
 	github.com/goccy/go-json v0.10.2 // indirect
+	github.com/godbus/dbus/v5 v5.1.0 // indirect
 	github.com/gofrs/flock v0.8.1 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
@@ -163,6 +168,7 @@ require (
 	github.com/ryanuber/go-glob v1.0.0 // indirect
 	github.com/segmentio/asm v1.2.0 // indirect
 	github.com/shopspring/decimal v1.3.1 // indirect
+	github.com/sirupsen/logrus v1.9.3 // indirect
 	github.com/sony/gobreaker v0.5.0 // indirect
 	github.com/spf13/cast v1.6.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
@@ -170,6 +176,7 @@ require (
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.1 // indirect
 	github.com/tidwall/sjson v1.2.5 // indirect
+	github.com/zalando/go-keyring v0.2.3 // indirect
 	go.opencensus.io v0.24.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 // indirect

+ 15 - 0
e2e/go.sum

@@ -105,6 +105,8 @@ github.com/akeylesslabs/akeyless-go-cloud-id v0.3.5 h1:ly0WKARATneFzwBlTZ2lUyjtL
 github.com/akeylesslabs/akeyless-go-cloud-id v0.3.5/go.mod h1:W6DMNwPyIE3jpXDaJOvCKUT/kHPZrpl/BGiIVUILbMk=
 github.com/akeylesslabs/akeyless-go/v3 v3.6.1 h1:vMlVecRhOW/cKY7Pksxgd03as9fC2LciJC3Ky6pJoI0=
 github.com/akeylesslabs/akeyless-go/v3 v3.6.1/go.mod h1:xcSXQWFRzKupIPCFRd9/mFYW0lHnDnWVvMD/pQ0x7sU=
+github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4uEoM0=
+github.com/alessio/shellescape v1.4.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
 github.com/aliyun/alibaba-cloud-sdk-go v1.62.271 h1:0QmSDMovuCyUbYp70MZHoTi/GYnHb/wYEIIBqoVsCjs=
 github.com/aliyun/alibaba-cloud-sdk-go v1.62.271/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
@@ -114,6 +116,8 @@ github.com/aws/aws-sdk-go v1.50.20 h1:xfAnSDVf/azIWTVQXQODp89bubvCS85r70O3nuQ4dn
 github.com/aws/aws-sdk-go v1.50.20/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
+github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
 github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
 github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -128,6 +132,10 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
 github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cyberark/conjur-api-go v0.11.1 h1:vjaMkw0geJsA+ikMM6UDLg4VLFQWKo/B0i9IWlOQ1f0=
+github.com/cyberark/conjur-api-go v0.11.1/go.mod h1:n1p46Hj9l8wkZjM17cVYdfcatyPboWyioLGlC0QszCs=
+github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs=
+github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -195,6 +203,8 @@ github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
 github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
 github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -429,6 +439,8 @@ github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr
 github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
 github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
 github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -473,6 +485,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms=
+github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -672,6 +686,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

+ 5 - 0
e2e/k8s/conjur.values.yaml

@@ -0,0 +1,5 @@
+authenticators: authn,authn-jwt/eso-tests
+logLevel: "debug"
+service:
+  external:
+    enabled: false # For KinD, use NotePort rather than LoadBalancer

+ 53 - 0
e2e/suites/provider/cases/conjur/conjur.go

@@ -0,0 +1,53 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+limitations under the License.
+*/
+package conjur
+
+import (
+	// nolint
+	. "github.com/onsi/ginkgo/v2"
+
+	"github.com/external-secrets/external-secrets-e2e/framework"
+	"github.com/external-secrets/external-secrets-e2e/suites/provider/cases/common"
+)
+
+const (
+	withTokenAuth = "with apikey auth"
+	withJWTK8s    = "with jwt k8s provider"
+)
+
+var _ = Describe("[conjur]", Label("conjur"), func() {
+	f := framework.New("eso-conjur")
+	prov := newConjurProvider(f)
+
+	DescribeTable("sync secrets",
+		framework.TableFuncWithExternalSecret(f, prov),
+		// uses token auth
+		framework.Compose(withTokenAuth, f, common.SimpleDataSync, useApiKeyAuth),
+		framework.Compose(withTokenAuth, f, common.SyncWithoutTargetName, useApiKeyAuth),
+		framework.Compose(withTokenAuth, f, common.JSONDataFromSync, useApiKeyAuth),
+		framework.Compose(withTokenAuth, f, common.JSONDataFromRewrite, useApiKeyAuth),
+		framework.Compose(withTokenAuth, f, common.SyncV1Alpha1, useApiKeyAuth),
+
+		// // use jwt k8s provider
+		// framework.Compose(withJWTK8s, f, common.JSONDataFromSync, useJWTK8sProvider),
+		// framework.Compose(withJWTK8s, f, common.JSONDataFromRewrite, useJWTK8sProvider),
+	)
+})
+
+func useApiKeyAuth(tc *framework.TestCase) {
+	tc.ExternalSecret.Spec.SecretStoreRef.Name = tc.Framework.Namespace.Name
+}
+
+// func useJWTK8sProvider(tc *framework.TestCase) {
+// 	tc.ExternalSecret.Spec.SecretStoreRef.Name = jwtK8sProviderName
+// }

+ 156 - 0
e2e/suites/provider/cases/conjur/provider.go

@@ -0,0 +1,156 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package conjur
+
+import (
+	"context"
+	"encoding/base64"
+	"strings"
+
+	//nolint
+	. "github.com/onsi/ginkgo/v2"
+
+	//nolint
+	. "github.com/onsi/gomega"
+	v1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"github.com/cyberark/conjur-api-go/conjurapi"
+	"github.com/external-secrets/external-secrets-e2e/framework"
+	"github.com/external-secrets/external-secrets-e2e/framework/addon"
+	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+)
+
+type conjurProvider struct {
+	url       string
+	client    *conjurapi.Client
+	framework *framework.Framework
+}
+
+const (
+	apiKeyAuthProviderName = "api-key-auth-provider"
+	jwtK8sProviderName     = "jwt-k8s-provider"
+)
+
+func newConjurProvider(f *framework.Framework) *conjurProvider {
+	prov := &conjurProvider{
+		framework: f,
+	}
+	BeforeEach(prov.BeforeEach)
+	return prov
+}
+
+func (s *conjurProvider) CreateSecret(key string, val framework.SecretEntry) {
+	// Generate a policy file for the secret key
+	policy := "- !variable " + key
+	_, err := s.client.LoadPolicy(conjurapi.PolicyModePost, "root", strings.NewReader(policy))
+	Expect(err).ToNot(HaveOccurred())
+
+	// Add the secret value
+	err = s.client.AddSecret(key, val.Value)
+	Expect(err).ToNot(HaveOccurred())
+}
+
+func (s *conjurProvider) DeleteSecret(key string) {
+	policy := `- !delete
+  record: !variable ` + key
+	_, err := s.client.LoadPolicy(conjurapi.PolicyModePatch, "root", strings.NewReader(policy))
+
+	Expect(err).ToNot(HaveOccurred())
+}
+
+func (s *conjurProvider) BeforeEach() {
+	ns := s.framework.Namespace.Name
+	c := addon.NewConjur(ns)
+	s.framework.Install(c)
+	s.client = c.ConjurClient
+	s.url = c.ConjurURL
+
+	s.CreateApiKeyStore(c, ns)
+	// s.CreateJWTK8sStore(c, ns)
+}
+
+func makeStore(name, ns string, c *addon.Conjur) *esv1beta1.SecretStore {
+	return &esv1beta1.SecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      name,
+			Namespace: ns,
+		},
+		Spec: esv1beta1.SecretStoreSpec{
+			Provider: &esv1beta1.SecretStoreProvider{
+				Conjur: &esv1beta1.ConjurProvider{
+					URL:      c.ConjurURL,
+					CABundle: base64.StdEncoding.EncodeToString(c.ConjurServerCA),
+				},
+			},
+		},
+	}
+}
+
+func (s *conjurProvider) CreateApiKeyStore(c *addon.Conjur, ns string) {
+	By("creating a conjur secret")
+	conjurCreds := &v1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			// Name:      apiKeyAuthProviderName,
+			Name:      ns,
+			Namespace: ns,
+		},
+		Data: map[string][]byte{
+			"apikey":   []byte(c.AdminApiKey),
+			"username": []byte("admin"),
+		},
+	}
+	err := s.framework.CRClient.Create(context.Background(), conjurCreds)
+	Expect(err).ToNot(HaveOccurred())
+
+	By("creating an secret store for conjur")
+	// secretStore := makeStore(apiKeyAuthProviderName, ns, c)
+	secretStore := makeStore(ns, ns, c)
+	secretStore.Spec.Provider.Conjur.Auth = esv1beta1.ConjurAuth{
+		APIKey: &esv1beta1.ConjurAPIKey{
+			Account: "default",
+			UserRef: &esmeta.SecretKeySelector{
+				// Name: apiKeyAuthProviderName,
+				Name: ns,
+				Key:  "username",
+			},
+			APIKeyRef: &esmeta.SecretKeySelector{
+				// Name: apiKeyAuthProviderName,
+				Name: ns,
+				Key:  "apikey",
+			},
+		},
+	}
+	err = s.framework.CRClient.Create(context.Background(), secretStore)
+	Expect(err).ToNot(HaveOccurred())
+}
+
+// func (s conjurProvider) CreateJWTK8sStore(c *addon.Conjur, ns string) {
+// 	secretStore := makeStore(jwtK8sProviderName, ns, c)
+// 	secretStore.Spec.Provider.Conjur.Auth = esv1beta1.ConjurAuth{
+// 		Jwt: &esv1beta1.ConjurJWT{
+// 			Account:   "default",
+// 			ServiceID: "eso-tests",
+// 			ServiceAccountRef: &esmeta.ServiceAccountSelector{
+// 				Name: "default",
+// 				Audiences: []string{
+// 					c.ConjurURL,
+// 				},
+// 			},
+// 		},
+// 	}
+// 	err := s.framework.CRClient.Create(context.Background(), secretStore)
+// 	Expect(err).ToNot(HaveOccurred())
+// }

+ 1 - 0
e2e/suites/provider/cases/import.go

@@ -26,4 +26,5 @@ import (
 	_ "github.com/external-secrets/external-secrets-e2e/suites/provider/cases/scaleway"
 	_ "github.com/external-secrets/external-secrets-e2e/suites/provider/cases/template"
 	_ "github.com/external-secrets/external-secrets-e2e/suites/provider/cases/vault"
+	_ "github.com/external-secrets/external-secrets-e2e/suites/provider/cases/conjur"
 )