Skip to content

Commit 3a27b24

Browse files
author
sbene
committed
feat: Enable multiple token caching and add option to disable caching completely
Signed-off-by: sbene <sebastien.bene@ubisoft.com>
1 parent 810f1fe commit 3a27b24

File tree

12 files changed

+187
-67
lines changed

12 files changed

+187
-67
lines changed

cmd/generate.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func NewGenerateCommand() *cobra.Command {
2121
const StdIn = "-"
2222
var configPath, secretName string
2323
var verboseOutput bool
24+
var disableCache bool
2425

2526
var command = &cobra.Command{
2627
Use: "generate <path>",
@@ -63,6 +64,7 @@ func NewGenerateCommand() *cobra.Command {
6364

6465
v := viper.New()
6566
viper.Set("verboseOutput", verboseOutput)
67+
viper.Set("disableCache", disableCache)
6668
cmdConfig, err := config.New(v, &config.Options{
6769
SecretName: secretName,
6870
ConfigPath: configPath,
@@ -116,5 +118,6 @@ func NewGenerateCommand() *cobra.Command {
116118
command.Flags().StringVarP(&configPath, "config-path", "c", "", "path to a file containing Vault configuration (YAML, JSON, envfile) to use")
117119
command.Flags().StringVarP(&secretName, "secret-name", "s", "", "name of a Kubernetes Secret in the argocd namespace containing Vault configuration data in the argocd namespace of your ArgoCD host (Only available when used in ArgoCD). The namespace can be overridden by using the format <namespace>:<name>")
118120
command.Flags().BoolVar(&verboseOutput, "verbose-sensitive-output", false, "enable verbose mode for detailed info to help with debugging. Includes sensitive data (credentials), logged to stderr")
121+
command.Flags().BoolVar(&disableCache, "disable-token-cache", false, "disable the automatic token cache feature that store tokens locally")
119122
return command
120123
}

cmd/generate_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package cmd
22

33
import (
44
"bytes"
5+
"fmt"
56
"io"
67
"os"
78
"strings"
89
"testing"
910

1011
"github.com/argoproj-labs/argocd-vault-plugin/pkg/helpers"
12+
"github.com/argoproj-labs/argocd-vault-plugin/pkg/utils"
1113
"github.com/hashicorp/vault/api"
1214
"github.com/hashicorp/vault/vault"
1315
)
@@ -250,6 +252,54 @@ func TestMain(t *testing.T) {
250252
}
251253
})
252254

255+
t.Run("will not create cache if disabled", func(t *testing.T) {
256+
257+
// Purging token cache before launching this test
258+
err := utils.PurgeTokenCache()
259+
if err != nil {
260+
t.Fatalf("fail to purge tocken cache: %s", err.Error())
261+
}
262+
263+
// Starting the generate command with the --disable-token-cache flag
264+
args := []string{
265+
"../fixtures/input/nonempty",
266+
"--disable-token-cache",
267+
}
268+
cmd := NewGenerateCommand()
269+
270+
b := bytes.NewBufferString("")
271+
e := bytes.NewBufferString("")
272+
cmd.SetArgs(args)
273+
cmd.SetOut(b)
274+
cmd.SetErr(e)
275+
cmd.Execute()
276+
out, err := io.ReadAll(b) // Read buffer to bytes
277+
if err != nil {
278+
t.Fatal(err)
279+
}
280+
stderr, err := io.ReadAll(e) // Read buffer to bytes
281+
if err != nil {
282+
t.Fatal(err)
283+
}
284+
285+
buf, err := os.ReadFile("../fixtures/output/all.yaml")
286+
if err != nil {
287+
t.Fatal(err)
288+
}
289+
290+
// We first check that the command was successful to make sure it reached the token caching part
291+
expected := string(buf)
292+
if string(out) != expected {
293+
t.Fatalf("expected %s\n\nbut got\n\n%s\nerr: %s", expected, string(out), string(stderr))
294+
}
295+
296+
// No cache is expected
297+
_, err = utils.ReadExistingToken(fmt.Sprintf("approle_%s", roleid))
298+
if err == nil {
299+
t.Fatalf("expected no cache but found one")
300+
}
301+
})
302+
253303
os.Unsetenv("AVP_TYPE")
254304
os.Unsetenv("VAULT_ADDR")
255305
os.Unsetenv("AVP_AUTH_TYPE")

pkg/auth/vault/approle.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func NewAppRoleAuth(roleID, secretID, mountPath string) *AppRoleAuth {
3333

3434
// Authenticate authenticates with Vault using App Role and returns a token
3535
func (a *AppRoleAuth) Authenticate(vaultClient *api.Client) error {
36-
err := utils.LoginWithCachedToken(vaultClient)
36+
err := utils.LoginWithCachedToken(vaultClient, fmt.Sprintf("approle_%s", a.RoleID))
3737
if err != nil {
3838
utils.VerboseToStdErr("Hashicorp Vault cannot retrieve cached token: %v. Generating a new one", err)
3939
} else {
@@ -54,7 +54,7 @@ func (a *AppRoleAuth) Authenticate(vaultClient *api.Client) error {
5454
utils.VerboseToStdErr("Hashicorp Vault authentication response: %v", data)
5555

5656
// If we cannot write the Vault token, we'll just have to login next time. Nothing showstopping.
57-
err = utils.SetToken(vaultClient, data.Auth.ClientToken)
57+
err = utils.SetToken(vaultClient, fmt.Sprintf("approle_%s", a.RoleID), data.Auth.ClientToken)
5858
if err != nil {
5959
utils.VerboseToStdErr("Hashicorp Vault cannot cache token for future runs: %v", err)
6060
}

pkg/auth/vault/approle_test.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package vault_test
22

33
import (
44
"bytes"
5+
"fmt"
56
"testing"
67

78
"github.com/argoproj-labs/argocd-vault-plugin/pkg/auth/vault"
@@ -20,7 +21,7 @@ func TestAppRoleLogin(t *testing.T) {
2021
t.Fatalf("expected no errors but got: %s", err)
2122
}
2223

23-
cachedToken, err := utils.ReadExistingToken()
24+
cachedToken, err := utils.ReadExistingToken(fmt.Sprintf("approle_%s", roleID))
2425
if err != nil {
2526
t.Fatalf("expected cached vault token but got: %s", err)
2627
}
@@ -30,12 +31,33 @@ func TestAppRoleLogin(t *testing.T) {
3031
t.Fatalf("expected no errors but got: %s", err)
3132
}
3233

33-
newCachedToken, err := utils.ReadExistingToken()
34+
newCachedToken, err := utils.ReadExistingToken(fmt.Sprintf("approle_%s", roleID))
3435
if err != nil {
3536
t.Fatalf("expected cached vault token but got: %s", err)
3637
}
3738

3839
if bytes.Compare(cachedToken, newCachedToken) != 0 {
3940
t.Fatalf("expected same token %s but got %s", cachedToken, newCachedToken)
4041
}
42+
43+
// We create a new connection with a different approle and create a different cache
44+
secondCluster, secondRoleID, secondSecretID := helpers.CreateTestAppRoleVault(t)
45+
defer secondCluster.Cleanup()
46+
47+
secondAppRole := vault.NewAppRoleAuth(secondRoleID, secondSecretID, "")
48+
49+
err = secondAppRole.Authenticate(secondCluster.Cores[0].Client)
50+
if err != nil {
51+
t.Fatalf("expected no errors but got: %s", err)
52+
}
53+
54+
secondCachedToken, err := utils.ReadExistingToken(fmt.Sprintf("approle_%s", secondRoleID))
55+
if err != nil {
56+
t.Fatalf("expected cached vault token but got: %s", err)
57+
}
58+
59+
// Both cache should be different
60+
if bytes.Compare(cachedToken, secondCachedToken) == 0 {
61+
t.Fatalf("expected different tokens but got %s", secondCachedToken)
62+
}
4163
}

pkg/auth/vault/github.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func NewGithubAuth(token, mountPath string) *GithubAuth {
3232

3333
// Authenticate authenticates with Vault and returns a token
3434
func (g *GithubAuth) Authenticate(vaultClient *api.Client) error {
35-
err := utils.LoginWithCachedToken(vaultClient)
35+
err := utils.LoginWithCachedToken(vaultClient, "github")
3636
if err != nil {
3737
utils.VerboseToStdErr("Hashicorp Vault cannot retrieve cached token: %v. Generating a new one", err)
3838
} else {
@@ -52,7 +52,7 @@ func (g *GithubAuth) Authenticate(vaultClient *api.Client) error {
5252
utils.VerboseToStdErr("Hashicorp Vault authentication response: %v", data)
5353

5454
// If we cannot write the Vault token, we'll just have to login next time. Nothing showstopping.
55-
err = utils.SetToken(vaultClient, data.Auth.ClientToken)
55+
err = utils.SetToken(vaultClient, "github", data.Auth.ClientToken)
5656
if err != nil {
5757
utils.VerboseToStdErr("Hashicorp Vault cannot cache token for future runs: %v", err)
5858
}

pkg/auth/vault/github_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestGithubLogin(t *testing.T) {
2121
t.Fatalf("expected no errors but got: %s", err)
2222
}
2323

24-
cachedToken, err := utils.ReadExistingToken()
24+
cachedToken, err := utils.ReadExistingToken("github")
2525
if err != nil {
2626
t.Fatalf("expected cached vault token but got: %s", err)
2727
}
@@ -31,7 +31,7 @@ func TestGithubLogin(t *testing.T) {
3131
t.Fatalf("expected no errors but got: %s", err)
3232
}
3333

34-
newCachedToken, err := utils.ReadExistingToken()
34+
newCachedToken, err := utils.ReadExistingToken("github")
3535
if err != nil {
3636
t.Fatalf("expected cached vault token but got: %s", err)
3737
}

pkg/auth/vault/kubernetes.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func NewK8sAuth(role, mountPath, tokenPath string) *K8sAuth {
3939

4040
// Authenticate authenticates with Vault via K8s and returns a token
4141
func (k *K8sAuth) Authenticate(vaultClient *api.Client) error {
42-
err := utils.LoginWithCachedToken(vaultClient)
42+
err := utils.LoginWithCachedToken(vaultClient, "kubernetes")
4343
if err != nil {
4444
utils.VerboseToStdErr("Hashicorp Vault cannot retrieve cached token: %v. Generating a new one", err)
4545
} else {
@@ -70,7 +70,7 @@ func (k *K8sAuth) Authenticate(vaultClient *api.Client) error {
7070
utils.VerboseToStdErr("Hashicorp Vault authentication response: %v", data)
7171

7272
// If we cannot write the Vault token, we'll just have to login next time. Nothing showstopping.
73-
err = utils.SetToken(vaultClient, data.Auth.ClientToken)
73+
err = utils.SetToken(vaultClient, "kubernetes", data.Auth.ClientToken)
7474
if err != nil {
7575
utils.VerboseToStdErr("Hashicorp Vault cannot cache token for future runs: %v", err)
7676
}

pkg/auth/vault/kubernetes_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func TestKubernetesAuth(t *testing.T) {
5353
t.Fatalf("expected no errors but got: %s", err)
5454
}
5555

56-
cachedToken, err := utils.ReadExistingToken()
56+
cachedToken, err := utils.ReadExistingToken("kubernetes")
5757
if err != nil {
5858
t.Fatalf("expected cached vault token but got: %s", err)
5959
}
@@ -63,7 +63,7 @@ func TestKubernetesAuth(t *testing.T) {
6363
t.Fatalf("expected no errors but got: %s", err)
6464
}
6565

66-
newCachedToken, err := utils.ReadExistingToken()
66+
newCachedToken, err := utils.ReadExistingToken("kubernetes")
6767
if err != nil {
6868
t.Fatalf("expected cached vault token but got: %s", err)
6969
}

pkg/auth/vault/userpass.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func NewUserPassAuth(username, password, mountPath string) *UserPassAuth {
3333

3434
// Authenticate authenticates with Vault using userpass and returns a token
3535
func (a *UserPassAuth) Authenticate(vaultClient *api.Client) error {
36-
err := utils.LoginWithCachedToken(vaultClient)
36+
err := utils.LoginWithCachedToken(vaultClient, fmt.Sprintf("userpass_%s", a.Username))
3737
if err != nil {
3838
utils.VerboseToStdErr("Hashicorp Vault cannot retrieve cached token: %v. Generating a new one", err)
3939
} else {
@@ -53,7 +53,7 @@ func (a *UserPassAuth) Authenticate(vaultClient *api.Client) error {
5353
utils.VerboseToStdErr("Hashicorp Vault authentication response: %v", data)
5454

5555
// If we cannot write the Vault token, we'll just have to login next time. Nothing showstopping.
56-
if err = utils.SetToken(vaultClient, data.Auth.ClientToken); err != nil {
56+
if err = utils.SetToken(vaultClient, fmt.Sprintf("userpass_%s", a.Username), data.Auth.ClientToken); err != nil {
5757
utils.VerboseToStdErr("Hashicorp Vault cannot cache token for future runs: %v", err)
5858
}
5959

pkg/auth/vault/userpass_test.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package vault_test
22

33
import (
44
"bytes"
5+
"fmt"
56
"testing"
67

78
"github.com/argoproj-labs/argocd-vault-plugin/pkg/auth/vault"
@@ -19,7 +20,7 @@ func TestUserPassLogin(t *testing.T) {
1920
t.Fatalf("expected no errors but got: %s", err)
2021
}
2122

22-
cachedToken, err := utils.ReadExistingToken()
23+
cachedToken, err := utils.ReadExistingToken(fmt.Sprintf("userpass_%s", username))
2324
if err != nil {
2425
t.Fatalf("expected cached vault token but got: %s", err)
2526
}
@@ -29,12 +30,33 @@ func TestUserPassLogin(t *testing.T) {
2930
t.Fatalf("expected no errors but got: %s", err)
3031
}
3132

32-
newCachedToken, err := utils.ReadExistingToken()
33+
newCachedToken, err := utils.ReadExistingToken(fmt.Sprintf("userpass_%s", username))
3334
if err != nil {
3435
t.Fatalf("expected cached vault token but got: %s", err)
3536
}
3637

3738
if bytes.Compare(cachedToken, newCachedToken) != 0 {
3839
t.Fatalf("expected same token %s but got %s", cachedToken, newCachedToken)
3940
}
41+
42+
// We create a new connection with a different approle and create a different cache
43+
secondCluster, secondUsername, secondPassword := helpers.CreateTestUserPassVault(t)
44+
defer secondCluster.Cleanup()
45+
46+
secondUserpass := vault.NewUserPassAuth(secondUsername, secondPassword, "")
47+
48+
err = secondUserpass.Authenticate(secondCluster.Cores[0].Client)
49+
if err != nil {
50+
t.Fatalf("expected no errors but got: %s", err)
51+
}
52+
53+
secondCachedToken, err := utils.ReadExistingToken(fmt.Sprintf("userpass_%s", secondUsername))
54+
if err != nil {
55+
t.Fatalf("expected cached vault token but got: %s", err)
56+
}
57+
58+
// Both cache should be different
59+
if bytes.Compare(cachedToken, secondCachedToken) == 0 {
60+
t.Fatalf("expected different tokens but got %s", secondCachedToken)
61+
}
4062
}

0 commit comments

Comments
 (0)