| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739 |
- /*
- Copyright © The ESO Authors
- 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
- https://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 openbao_test
- import (
- "crypto/x509"
- "encoding/json"
- "fmt"
- "net/http"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "strings"
- "sync/atomic"
- "testing"
- "time"
- "github.com/go-viper/mapstructure/v2"
- "gopkg.in/dnaeon/go-vcr.v4/pkg/cassette"
- "gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "sigs.k8s.io/controller-runtime/pkg/client"
- clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
- esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
- esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
- "github.com/external-secrets/external-secrets/providers/v1/openbao"
- "github.com/external-secrets/external-secrets/providers/v1/openbao/internal/auth"
- . "github.com/onsi/gomega"
- )
- const recordDir = "testdata/http"
- const fakeToken = "s.fakeTOKEN123"
- var (
- requestIdReg = regexp.MustCompile(`id":"[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"`)
- timeReg = regexp.MustCompile(`_time":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+Z"`)
- namedAccessorReg = regexp.MustCompile(`accessor":"([a-z]+)_[0-9a-f]+"`)
- accessorReg = regexp.MustCompile(`accessor":"([A-Za-z0-9]+)"`)
- tokenReg = regexp.MustCompile(`client_token":"s\.([A-Za-z0-9]+)"`)
- )
- func getRecorder(t *testing.T) *recorder.Recorder {
- // this hook makes the "git diff" of a rerecord smaller by removing unneeded metadata
- cleanupHook := recorder.WithHook(func(i *cassette.Interaction) error {
- delete(i.Response.Headers, "Date")
- i.Response.Duration = 0
- i.Response.Body = requestIdReg.ReplaceAllString(i.Response.Body, `id":"00000000-0000-0000-0000-000000000000"`)
- i.Response.Body = timeReg.ReplaceAllString(i.Response.Body, `_time":"2099-09-09T09:09:09.09Z"`)
- i.Response.Body = namedAccessorReg.ReplaceAllString(i.Response.Body, `accessor":"${1}_01234567"`)
- i.Response.Body = accessorReg.ReplaceAllString(i.Response.Body, `accessor":"AbCdEfGHiJk123"`)
- i.Response.Body = tokenReg.ReplaceAllString(i.Response.Body, `client_token":"`+fakeToken+`"`)
- token := i.Request.Headers.Get("X-Vault-Token")
- if token != "" && token != "root" {
- i.Request.Headers.Set("X-Vault-Token", fakeToken)
- }
- var body map[string]any
- err := json.Unmarshal([]byte(i.Response.Body), &body)
- if err != nil {
- return err
- }
- indentedBody, err := json.MarshalIndent(body, "", " ")
- if err != nil {
- return err
- }
- i.Response.Body = string(indentedBody)
- return nil
- }, recorder.BeforeSaveHook)
- r, err := recorder.New(filepath.Join(recordDir, strings.ReplaceAll(t.Name(), "/", "_")), cleanupHook)
- Expect(err).NotTo(HaveOccurred())
- t.Cleanup(func() {
- if err := r.Stop(); err != nil {
- t.Log(err)
- }
- })
- return r
- }
- func makeValidSecretStoreWithVersion(v esv1.OpenBaoKVStoreVersion) *esv1.SecretStore {
- path := "secret"
- if v == esv1.OpenBaoKVStoreV1 {
- path = "secret_v1"
- }
- return &esv1.SecretStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "openbao-store",
- Namespace: "default",
- },
- Spec: esv1.SecretStoreSpec{
- Provider: &esv1.SecretStoreProvider{
- OpenBao: &esv1.OpenBaoProvider{
- Server: "http://localhost:8200",
- Path: &path,
- Version: v,
- Auth: &esv1.OpenBaoAuth{
- TokenSecretRef: &esmeta.SecretKeySelector{
- Name: "bao-token",
- Key: "token",
- },
- },
- },
- },
- },
- }
- }
- func TestMain(m *testing.M) {
- record := os.Getenv("ESO_PROVIDER_OPENBAO_RERECORD") == "true"
- if record {
- bao := exec.Command("bao", "server", "-dev", "-dev-root-token-id=root")
- bao.Stderr = os.Stderr
- bao.Stdout = os.Stdin
- err := bao.Start()
- if err != nil {
- panic(err)
- }
- defer func() {
- err := bao.Process.Signal(os.Interrupt)
- if err != nil {
- panic(err)
- }
- err = bao.Wait()
- if err != nil {
- panic(err)
- }
- }()
- err = os.RemoveAll(recordDir)
- if err != nil {
- panic(err)
- }
- time.Sleep(time.Second)
- initBao := exec.Command("./testdata/init-bao.sh")
- initBao.Stderr = os.Stderr
- initBao.Stdout = os.Stdin
- err = initBao.Run()
- if err != nil {
- panic(err)
- }
- fmt.Println("started bao, running test")
- }
- m.Run()
- }
- func TestProvider_NewClient_TokenNotFound(t *testing.T) {
- RegisterTestingT(t)
- kube := clientfake.NewClientBuilder().Build()
- provider := openbao.NewProvider()
- client, err := provider.NewClient(t.Context(), makeValidSecretStoreWithVersion(esv1.OpenBaoKVStoreV2), kube, "default")
- Expect(err).To(MatchError(ContainSubstring(`secrets "bao-token" not found`)))
- Expect(client).To(BeNil())
- }
- func TestProvider_KVv2(t *testing.T) {
- v := esv1.OpenBaoKVStoreV2
- t.Run("GetSecret_Property", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- Property: "bar",
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(data).To(BeEquivalentTo("bazz"))
- data, err = client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- Property: "does-not-exist",
- })
- Expect(err).To(MatchError(`cannot find secret data for key: "does-not-exist"`))
- Expect(data).To(BeNil())
- })
- t.Run("GetSecret_Versioned", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- Property: "bar",
- Version: "1",
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(data).To(BeEquivalentTo("old_bazz"))
- data, err = client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- Property: "bar",
- Version: "invalid",
- })
- Expect(err).To(MatchError(`invalid Ref.Version: strconv.Atoi: parsing "invalid": invalid syntax`))
- Expect(data).To(BeNil())
- })
- t.Run("GetSecret_Full", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(data).To(MatchJSON(`{
- "bar": "bazz",
- "lorem": "ipsum"
- }`))
- })
- t.Run("GetSecretMap", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- data, err := client.GetSecretMap(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(data).To(Equal(map[string][]byte{
- "bar": []byte("bazz"),
- "lorem": []byte("ipsum"),
- }))
- })
- t.Run("GetAllSecrets", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- allData, err := client.GetAllSecrets(t.Context(), esv1.ExternalSecretFind{
- Name: &esv1.FindName{
- RegExp: "fo+",
- },
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(allData).To(HaveLen(1))
- Expect(allData).To(HaveKeyWithValue("foo", MatchJSON(`{
- "bar": "bazz",
- "lorem": "ipsum"
- }`)))
- })
- t.Run("GetAllSecrets_NoMatch", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- allData, err := client.GetAllSecrets(t.Context(), esv1.ExternalSecretFind{
- Path: new("empty"),
- Name: &esv1.FindName{
- RegExp: "nomatch",
- },
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(allData).To(HaveLen(0))
- })
- }
- func TestProvider_KVv1(t *testing.T) {
- v := esv1.OpenBaoKVStoreV1
- t.Run("GetSecret_Property", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- Property: "bar",
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(data).To(BeEquivalentTo("bazz_v1"))
- })
- t.Run("GetSecret_Versioned", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- Property: "bar",
- Version: "1",
- })
- Expect(err).To(MatchError("OpenBao KVv1 secrets do not support versioning (use KVv2)"))
- Expect(data).To(BeNil())
- })
- t.Run("GetSecret_Full", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(data).To(MatchJSON(`{
- "bar": "bazz_v1",
- "lorem": "ipsum_v1"
- }`))
- })
- t.Run("GetAllSecrets", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- allData, err := client.GetAllSecrets(t.Context(), esv1.ExternalSecretFind{
- Name: &esv1.FindName{
- RegExp: "fo+",
- },
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(allData).To(HaveLen(1))
- Expect(allData).To(HaveKeyWithValue("foo", MatchJSON(`{
- "bar": "bazz_v1",
- "lorem": "ipsum_v1"
- }`)))
- })
- t.Run("GetAllSecrets_NoMatch", func(t *testing.T) {
- RegisterTestingT(t)
- client := setupClient(t, v)
- allData, err := client.GetAllSecrets(t.Context(), esv1.ExternalSecretFind{
- Path: new("empty"),
- Name: &esv1.FindName{
- RegExp: "nomatch",
- },
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(allData).To(HaveLen(0))
- })
- }
- func TestProvider_Auth(t *testing.T) {
- RegisterTestingT(t)
- kube := clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "shared-secret",
- Namespace: "default",
- },
- Data: map[string][]byte{
- "approle-id": []byte("dynamic-roleid"),
- "approle-secret": []byte("the-secret"),
- "userpass-password": []byte("the-password"),
- },
- }).Build()
- provider := openbao.NewProvider().(*openbao.Provider)
- cases := []struct {
- name string
- auth *esv1.OpenBaoAuth
- expectedCalls []string
- }{{
- name: "userpass",
- auth: &esv1.OpenBaoAuth{
- UserPass: &esv1.OpenBaoUserPassAuth{
- Path: "userpasspath",
- Username: "the-user",
- SecretRef: esmeta.SecretKeySelector{
- Name: "shared-secret",
- Key: "userpass-password",
- },
- },
- },
- expectedCalls: []string{`UserPass("the-user", "the-password", "userpasspath")`},
- }, {
- name: "approle static",
- auth: &esv1.OpenBaoAuth{
- AppRole: &esv1.OpenBaoAppRole{
- Path: "approlepath",
- RoleID: "static-roleid",
- SecretRef: esmeta.SecretKeySelector{
- Name: "shared-secret",
- Key: "approle-secret",
- },
- },
- },
- expectedCalls: []string{`AppRole("static-roleid", "the-secret", "approlepath")`},
- }, {
- name: "approle dynamic",
- auth: &esv1.OpenBaoAuth{
- AppRole: &esv1.OpenBaoAppRole{
- Path: "approlepath",
- RoleRef: &esmeta.SecretKeySelector{
- Name: "shared-secret",
- Key: "approle-id",
- },
- SecretRef: esmeta.SecretKeySelector{
- Name: "shared-secret",
- Key: "approle-secret",
- },
- },
- },
- expectedCalls: []string{`AppRole("dynamic-roleid", "the-secret", "approlepath")`},
- }}
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- RegisterTestingT(t)
- factory := &auth.MockFactory{}
- provider.AuthMethodFactory = factory
- store := makeValidSecretStoreWithVersion(esv1.OpenBaoKVStoreV2)
- store.Spec.Provider.OpenBao.Auth = tc.auth
- client, err := provider.NewClient(t.Context(), store, kube, "default")
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- t.Cleanup(func() {
- client.Close(t.Context())
- })
- Expect(factory.GetCalls()).To(Equal(tc.expectedCalls))
- })
- }
- }
- func TestProvider_Auth_UserPass(t *testing.T) {
- RegisterTestingT(t)
- kube, provider := setupProvider(t, &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "password-of-alice",
- Namespace: "default",
- },
- Data: map[string][]byte{
- "pw": []byte("bob4ever"),
- },
- })
- store := makeValidSecretStoreWithVersion(esv1.OpenBaoKVStoreV2)
- store.Spec.Provider.OpenBao.Auth = &esv1.OpenBaoAuth{
- UserPass: &esv1.OpenBaoUserPassAuth{
- Path: "customuserpasspath",
- Username: "alice",
- SecretRef: esmeta.SecretKeySelector{
- Name: "password-of-alice",
- Key: "pw",
- },
- },
- }
- client, err := provider.NewClient(t.Context(), store, kube, "default")
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- t.Cleanup(func() {
- client.Close(t.Context())
- })
- data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- Property: "bar",
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(data).To(BeEquivalentTo("bazz"))
- }
- func TestProvider_BaoNamespaces(t *testing.T) {
- v := esv1.OpenBaoKVStoreV2
- kube, provider := setupProvider(t, &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "auth",
- Namespace: "default",
- },
- Data: map[string][]byte{
- "token": []byte("root"),
- "password": []byte("bob4ever"),
- },
- })
- store := makeValidSecretStoreWithVersion(v)
- store.Spec.Provider.OpenBao.Namespace = new("my-namespace")
- store.Spec.Provider.OpenBao.Path = nil
- store.Spec.Provider.OpenBao.Auth.TokenSecretRef.Name = "auth"
- t.Run("WithToken", func(t *testing.T) {
- RegisterTestingT(t)
- client, err := provider.NewClient(t.Context(), store, kube, "default")
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- t.Cleanup(func() {
- client.Close(t.Context())
- })
- data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- Property: "namespaced-bar",
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(data).To(BeEquivalentTo("namespaced-bazz"))
- })
- store.Spec.Provider.OpenBao.Auth = &esv1.OpenBaoAuth{
- UserPass: &esv1.OpenBaoUserPassAuth{
- Path: "customuserpasspath",
- Username: "alice",
- SecretRef: esmeta.SecretKeySelector{
- Name: "auth",
- Key: "password",
- },
- },
- Namespace: new(""),
- }
- t.Run("WithUserPass", func(t *testing.T) {
- RegisterTestingT(t)
- client, err := provider.NewClient(t.Context(), store, kube, "default")
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- t.Cleanup(func() {
- client.Close(t.Context())
- })
- data, err := client.GetSecret(t.Context(), esv1.ExternalSecretDataRemoteRef{
- Key: "foo",
- Property: "namespaced-bar",
- })
- Expect(err).NotTo(HaveOccurred())
- Expect(data).To(BeEquivalentTo("namespaced-bazz"))
- })
- }
- func TestProvider_Validate(t *testing.T) {
- RegisterTestingT(t)
- kube, provider := setupProvider(t, &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bao-token",
- Namespace: "default",
- },
- Data: map[string][]byte{
- "token": []byte("root"),
- },
- })
- store := makeValidSecretStoreWithVersion(esv1.OpenBaoKVStoreV1)
- client, err := provider.NewClient(t.Context(), store, kube, "default")
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- Expect(client.Validate()).To(Equal(esv1.ValidationResultReady))
- // make version it invalid
- store.Spec.Provider.OpenBao.Version = esv1.OpenBaoKVStoreV2
- client, err = provider.NewClient(t.Context(), store, kube, "default")
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- result, err := client.Validate()
- Expect(err).To(MatchError("expected kv engine version 2 found version 1"))
- Expect(result).To(Equal(esv1.ValidationResultError))
- // make engine it invalid
- store.Spec.Provider.OpenBao.Path = new("sys")
- client, err = provider.NewClient(t.Context(), store, kube, "default")
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- result, err = client.Validate()
- Expect(err).To(MatchError(`expected mount type "kv" found "system"`))
- Expect(result).To(Equal(esv1.ValidationResultError))
- // make it a cluster store
- clusterStore := &esv1.ClusterSecretStore{}
- Expect(mapstructure.Decode(store, clusterStore)).NotTo(HaveOccurred())
- client, err = provider.NewClient(t.Context(), clusterStore, kube, "")
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- Expect(client.Validate()).To(Equal(esv1.ValidationResultUnknown))
- }
- var dummyCA = []byte(`-----BEGIN CERTIFICATE-----
- MIIBgDCCATKgAwIBAgIRAOzjpCdp42oW5MoccLpRXpAwBQYDK2VwMBIxEDAOBgNV
- BAMTB3Jvb3QtY2EwHhcNMjIwMjA5MTAyNTMxWhcNMzIwMjA3MTAyNTMxWjAaMRgw
- FgYDVQQDEw9pbnRlcm1lZGlhdGUtY2EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
- AATekdyX6cZe0Ajmme363TQoWnrQwXnARzeWEf4FRQE8BGWgf8z7wljjpb4M4S4f
- +CJAYYY/6x38UnlsxXEeBTofo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/
- BAgwBgEB/wIBADAdBgNVHQ4EFgQUIuDzQn9tkFs535jz5X3iXnEzbMQwHwYDVR0j
- BBgwFoAUa2fUac2OZ3pzE6EydVq7UvwiQa0wBQYDK2VwA0EA4gntaGs/3ME6q1y9
- gO4ntri2qwoC25l3q7q9BiFBmeBmvS6I1w9HCZHtB3JnVC/IYDTCYDNTbpGWEOjl
- aCKLCA==
- -----END CERTIFICATE-----`)
- func TestProvider_CustomCA(t *testing.T) {
- cases := []struct {
- name string
- spec esv1.OpenBaoProvider
- k8sObjects []client.Object
- expectedError string
- }{
- {
- name: "CABundle",
- spec: esv1.OpenBaoProvider{
- CABundle: dummyCA,
- },
- },
- {
- name: "CABundle_invalid",
- spec: esv1.OpenBaoProvider{
- CABundle: []byte("invalid"),
- },
- expectedError: "cannot set OpenBao CA certificate: failed to decode ca bundle: failed to parse the new certificate, not valid pem data",
- },
- {
- name: "CAProvider",
- spec: esv1.OpenBaoProvider{
- CAProvider: &esv1.CAProvider{
- Type: esv1.CAProviderTypeSecret,
- Name: "dummy-ca",
- Key: "ca.pem",
- },
- },
- k8sObjects: []client.Object{&corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "dummy-ca",
- Namespace: "default",
- },
- Data: map[string][]byte{
- "ca.pem": dummyCA,
- },
- }},
- },
- {
- name: "CAProvider_not_found",
- spec: esv1.OpenBaoProvider{
- CAProvider: &esv1.CAProvider{
- Type: esv1.CAProviderTypeSecret,
- Name: "dummy-ca",
- Key: "ca.pem",
- },
- },
- expectedError: `cannot set OpenBao CA certificate: failed to get cert from secret: failed to resolve secret key ref: cannot get Kubernetes secret "dummy-ca" from namespace "default": secrets "dummy-ca" not found`,
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- RegisterTestingT(t)
- kube := clientfake.NewClientBuilder().WithObjects(tc.k8sObjects...).Build()
- provider := openbao.NewProvider().(*openbao.Provider)
- originalFactory := provider.HTTPClientFactory
- var httpClient atomic.Pointer[http.Client]
- var factoryCallCount atomic.Int64
- provider.HTTPClientFactory = func() *http.Client {
- c := originalFactory()
- httpClient.Store(c)
- factoryCallCount.Add(1)
- return c
- }
- store := makeValidSecretStoreWithVersion(esv1.OpenBaoKVStoreV2)
- store.Spec.Provider.OpenBao = &tc.spec
- client, err := provider.NewClient(t.Context(), store, kube, "default")
- if tc.expectedError != "" {
- Expect(err).To(MatchError(tc.expectedError))
- Expect(client).To(BeNil())
- } else {
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- expectedPool := x509.NewCertPool()
- Expect(expectedPool.AppendCertsFromPEM(dummyCA)).To(BeTrue())
- Expect(factoryCallCount.Load()).To(BeEquivalentTo(1))
- transport := httpClient.Load().Transport
- Expect(transport).To(BeAssignableToTypeOf(&http.Transport{}))
- tls := transport.(*http.Transport).TLSClientConfig
- Expect(tls.RootCAs.Equal(expectedPool)).To(BeTrueBecause("root CAs should equal expected cert pool"))
- client.Close(t.Context())
- }
- })
- }
- }
- func setupClient(t *testing.T, v esv1.OpenBaoKVStoreVersion) esv1.SecretsClient {
- kube, provider := setupProvider(t, &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bao-token",
- Namespace: "default",
- },
- Data: map[string][]byte{
- "token": []byte("root"),
- },
- })
- client, err := provider.NewClient(t.Context(), makeValidSecretStoreWithVersion(v), kube, "default")
- Expect(err).NotTo(HaveOccurred())
- Expect(client).NotTo(BeNil())
- t.Cleanup(func() {
- client.Close(t.Context())
- })
- return client
- }
- func setupProvider(t *testing.T, objects ...client.Object) (client.WithWatch, *openbao.Provider) {
- r := getRecorder(t)
- kube := clientfake.NewClientBuilder().WithObjects(objects...).Build()
- provider := openbao.NewProvider().(*openbao.Provider)
- provider.HTTPClientFactory = r.GetDefaultClient
- return kube, provider
- }
|