Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using secretRef for hashicorpVault auth #6143

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Here is an overview of all new **experimental** features:

### Improvements

- TODO ([#XXX](https://github.com/kedacore/keda/issues/XXX))
- **Hashicorp Vault**: Allow using secretRef for hashicorpVault auth ([#6026](https://github.com/kedacore/keda/issues/6026))

### Fixes

Expand Down
7 changes: 6 additions & 1 deletion apis/keda/v1alpha1/triggerauthentication_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,12 @@ type Credential struct {
Token string `json:"token,omitempty"`

// +optional
ServiceAccount string `json:"serviceAccount,omitempty"`
ServiceAccount string `json:"serviceAccount,omitempty"`
TokenSecret *HashicorpVaultTokenSecret `json:"tokenSecret,omitempty"`
}

type HashicorpVaultTokenSecret struct {
ValueFrom ValueFromSecret `json:"valueFrom"`
}

// VaultAuthentication contains the list of Hashicorp Vault authentication methods
Expand Down
20 changes: 20 additions & 0 deletions config/crd/bases/keda.sh_clustertriggerauthentications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,26 @@ spec:
type: string
token:
type: string
tokenSecret:
properties:
valueFrom:
properties:
secretKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
- name
type: object
required:
- secretKeyRef
type: object
required:
- valueFrom
type: object
type: object
mount:
type: string
Expand Down
20 changes: 20 additions & 0 deletions config/crd/bases/keda.sh_triggerauthentications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,26 @@ spec:
type: string
token:
type: string
tokenSecret:
properties:
valueFrom:
properties:
secretKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
- name
type: object
required:
- secretKeyRef
type: object
required:
- valueFrom
type: object
type: object
mount:
type: string
Expand Down
29 changes: 18 additions & 11 deletions pkg/scaling/resolver/hashicorpvault_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package resolver

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand All @@ -25,6 +26,8 @@ import (

"github.com/go-logr/logr"
vaultapi "github.com/hashicorp/vault/api"
corev1listers "k8s.io/client-go/listers/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1"
)
Expand All @@ -44,32 +47,32 @@ func NewHashicorpVaultHandler(v *kedav1alpha1.HashiCorpVault) *HashicorpVaultHan
}

// Initialize the Vault client
func (vh *HashicorpVaultHandler) Initialize(logger logr.Logger) error {
func (vh *HashicorpVaultHandler) Initialize(ctx context.Context, client client.Client, logger logr.Logger, triggerNamespace string, secretLister corev1listers.SecretLister) error {
config := vaultapi.DefaultConfig()
client, err := vaultapi.NewClient(config)
vaultClient, err := vaultapi.NewClient(config)
if err != nil {
return err
}

err = client.SetAddress(vh.vault.Address)
err = vaultClient.SetAddress(vh.vault.Address)
if err != nil {
return err
}

if len(vh.vault.Namespace) > 0 {
client.SetNamespace(vh.vault.Namespace)
vaultClient.SetNamespace(vh.vault.Namespace)
}

token, err := vh.token(client)
token, err := vh.token(ctx, client, vaultClient, logger, triggerNamespace, secretLister)
if err != nil {
return err
}

if len(token) > 0 {
client.SetToken(token)
vaultClient.SetToken(token)
}

lookup, err := client.Auth().Token().LookupSelf()
lookup, err := vaultClient.Auth().Token().LookupSelf()
// If token is not valid so get out of here early
if err != nil {
return err
Expand All @@ -80,21 +83,25 @@ func (vh *HashicorpVaultHandler) Initialize(logger logr.Logger) error {
go vh.renewToken(logger)
}

vh.client = client
vh.client = vaultClient

return nil
}

// token Extract a vault token from the Authentication method
func (vh *HashicorpVaultHandler) token(client *vaultapi.Client) (string, error) {
func (vh *HashicorpVaultHandler) token(ctx context.Context, client client.Client, vaultClient *vaultapi.Client, logger logr.Logger, triggerNamespace string, secretLister corev1listers.SecretLister) (string, error) {
var token string

switch vh.vault.Authentication {
case kedav1alpha1.VaultAuthenticationToken:
// Got token from VAULT_TOKEN env variable
switch {
case len(client.Token()) > 0:
case len(vaultClient.Token()) > 0:
break
case vh.vault.Credential.TokenSecret != nil:
tokenSecretName := vh.vault.Credential.TokenSecret.ValueFrom.SecretKeyRef.Name
tokenSecretKey := vh.vault.Credential.TokenSecret.ValueFrom.SecretKeyRef.Key
token = resolveAuthSecret(ctx, client, logger, tokenSecretName, triggerNamespace, tokenSecretKey, secretLister)
case len(vh.vault.Credential.Token) > 0:
token = vh.vault.Credential.Token
default:
Expand Down Expand Up @@ -127,7 +134,7 @@ func (vh *HashicorpVaultHandler) token(client *vaultapi.Client) (string, error)
}

data := map[string]interface{}{"jwt": string(jwt), "role": vh.vault.Role}
secret, err := client.Logical().Write(fmt.Sprintf("auth/%s/login", vh.vault.Mount), data)
secret, err := vaultClient.Logical().Write(fmt.Sprintf("auth/%s/login", vh.vault.Mount), data)
if err != nil {
return token, err
}
Expand Down
45 changes: 35 additions & 10 deletions pkg/scaling/resolver/hashicorpvault_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package resolver

import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -182,15 +183,15 @@ func TestHashicorpVaultHandler_getSecretValue_specify_secret_type(t *testing.T)
},
}
vaultHandler := NewHashicorpVaultHandler(&vault)
err := vaultHandler.Initialize(logf.Log.WithName("test"))
err := vaultHandler.Initialize(context.TODO(), nil, logf.Log.WithName("test"), "", nil)
defer vaultHandler.Stop()
assert.Nil(t, err)
secrets := []kedav1alpha1.VaultSecret{{
Parameter: "test",
Path: "kv_v2/data/keda",
Key: "test",
}}
assert.Equalf(t, kedav1alpha1.VaultSecretTypeGeneric, secrets[0].Type, "Expected secret to not have a vlue")
assert.Equalf(t, kedav1alpha1.VaultSecretTypeGeneric, secrets[0].Type, "Expected secret to not have a value")
secrets, _ = vaultHandler.ResolveSecrets(secrets)
assert.Len(t, secrets, 1, "Supposed to get back one secret")
secret := secrets[0]
Expand All @@ -201,7 +202,7 @@ func TestHashicorpVaultHandler_getSecretValue_specify_secret_type(t *testing.T)
Path: "kv/keda",
Key: "test",
}}
assert.Equalf(t, kedav1alpha1.VaultSecretTypeGeneric, secrets[0].Type, "Expected secret to not have a vlue")
assert.Equalf(t, kedav1alpha1.VaultSecretTypeGeneric, secrets[0].Type, "Expected secret to not have a value")
secrets, _ = vaultHandler.ResolveSecrets(secrets)
assert.Len(t, secrets, 1, "Supposed to get back one secret")
secret = secrets[0]
Expand Down Expand Up @@ -322,7 +323,7 @@ func TestHashicorpVaultHandler_ResolveSecret(t *testing.T) {
},
}
vaultHandler := NewHashicorpVaultHandler(&vault)
err := vaultHandler.Initialize(logf.Log.WithName("test"))
err := vaultHandler.Initialize(context.TODO(), nil, logf.Log.WithName("test"), "", nil)
defer vaultHandler.Stop()
assert.Nil(t, err)

Expand Down Expand Up @@ -358,7 +359,7 @@ func TestHashicorpVaultHandler_ResolveSecret_UsingRootToken(t *testing.T) {
},
}
vaultHandler := NewHashicorpVaultHandler(&vault)
err := vaultHandler.Initialize(logf.Log.WithName("test"))
err := vaultHandler.Initialize(context.TODO(), nil, logf.Log.WithName("test"), "", nil)
defer vaultHandler.Stop()
assert.Nil(t, err)

Expand Down Expand Up @@ -395,7 +396,7 @@ func TestHashicorpVaultHandler_DefaultKubernetesVaultRole(t *testing.T) {
}

vaultHandler := NewHashicorpVaultHandler(&vault)
err := vaultHandler.Initialize(logf.Log.WithName("test"))
err := vaultHandler.Initialize(context.TODO(), nil, logf.Log.WithName("test"), "", nil)
defer vaultHandler.Stop()
assert.Errorf(t, err, "open %s : no such file or directory", defaultServiceAccountPath)
assert.Equal(t, vaultHandler.vault.Credential.ServiceAccount, defaultServiceAccountPath)
Expand All @@ -413,7 +414,7 @@ func TestHashicorpVaultHandler_ResolveSecrets_SameCertAndKey(t *testing.T) {
},
}
vaultHandler := NewHashicorpVaultHandler(&vault)
err := vaultHandler.Initialize(logf.Log.WithName("test"))
err := vaultHandler.Initialize(context.TODO(), nil, logf.Log.WithName("test"), "", nil)
defer vaultHandler.Stop()
assert.Nil(t, err)
secrets := []kedav1alpha1.VaultSecret{{
Expand Down Expand Up @@ -481,7 +482,7 @@ func TestHashicorpVaultHandler_fetchSecret(t *testing.T) {
},
}
vaultHandler := NewHashicorpVaultHandler(&vault)
err := vaultHandler.Initialize(logf.Log.WithName("test"))
err := vaultHandler.Initialize(context.TODO(), nil, logf.Log.WithName("test"), "", nil)
defer vaultHandler.Stop()
assert.Nil(t, err)

Expand Down Expand Up @@ -537,7 +538,7 @@ func TestHashicorpVaultHandler_Initialize(t *testing.T) {
Namespace: testData.namespace,
}
vaultHandler := NewHashicorpVaultHandler(&vault)
err := vaultHandler.Initialize(logf.Log.WithName("test"))
err := vaultHandler.Initialize(context.TODO(), nil, logf.Log.WithName("test"), "", nil)
defer vaultHandler.Stop()
assert.Nil(t, err)

Expand Down Expand Up @@ -616,7 +617,7 @@ func TestHashicorpVaultHandler_Token_VaultTokenAuth(t *testing.T) {
config := vaultapi.DefaultConfig()
client, err := vaultapi.NewClient(config)
assert.Nil(t, err)
token, err := vaultHandler.token(client)
token, err := vaultHandler.token(context.TODO(), nil, client, logf.Log.WithName("test"), "", nil)
if testData.isError {
assert.Equalf(t, vaultHandler.vault.Credential.ServiceAccount, testData.credential.ServiceAccount, "test %s: expected %s but found %s", testData.name, "random/path", vaultHandler.vault.Credential.ServiceAccount)
assert.NotNilf(t, err, "test %s: expected error but got success, testData - %+v", testData.name, testData)
Expand All @@ -627,3 +628,27 @@ func TestHashicorpVaultHandler_Token_VaultTokenAuth(t *testing.T) {
}()
}
}

func TestHashicorpVaultHandler_Initialize_with_SecretRef(t *testing.T) {
server := mockVault(t, false)
defer server.Close()

vault := kedav1alpha1.HashiCorpVault{
Address: server.URL,
Authentication: kedav1alpha1.VaultAuthenticationToken,
Credential: &kedav1alpha1.Credential{
TokenSecret: &kedav1alpha1.HashicorpVaultTokenSecret{
ValueFrom: kedav1alpha1.ValueFromSecret{
SecretKeyRef: kedav1alpha1.SecretKeyRef{
Name: "my-secret",
Key: "my-key",
},
},
},
},
}
vaultHandler := NewHashicorpVaultHandler(&vault)
err := vaultHandler.Initialize(context.TODO(), nil, logf.Log.WithName("test"), "", nil)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider to use well-defined context

Ignore this finding from context-todo.

defer vaultHandler.Stop()
assert.Nil(t, err)
}
2 changes: 1 addition & 1 deletion pkg/scaling/resolver/scale_resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ func resolveAuthRef(ctx context.Context, client client.Client, logger logr.Logge
}
if triggerAuthSpec.HashiCorpVault != nil && len(triggerAuthSpec.HashiCorpVault.Secrets) > 0 {
vault := NewHashicorpVaultHandler(triggerAuthSpec.HashiCorpVault)
err := vault.Initialize(logger)
err := vault.Initialize(ctx, client, logger, triggerNamespace, secretsLister)
defer vault.Stop()
if err != nil {
logger.Error(err, "error authenticating to Vault", "triggerAuthRef.Name", triggerAuthRef.Name)
Expand Down
Loading
Loading