mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 11:38:02 +00:00
Update Test_NoAutoAuthSelfHealing_BadPolicy (#26323)
This commit is contained in:
@@ -23,10 +23,7 @@ import (
|
|||||||
"github.com/hashicorp/vault/command/agentproxyshared/sink/file"
|
"github.com/hashicorp/vault/command/agentproxyshared/sink/file"
|
||||||
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
|
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
|
||||||
"github.com/hashicorp/vault/helper/testhelpers/minimal"
|
"github.com/hashicorp/vault/helper/testhelpers/minimal"
|
||||||
vaulthttp "github.com/hashicorp/vault/http"
|
|
||||||
"github.com/hashicorp/vault/sdk/helper/logging"
|
|
||||||
"github.com/hashicorp/vault/sdk/helper/pointerutil"
|
"github.com/hashicorp/vault/sdk/helper/pointerutil"
|
||||||
"github.com/hashicorp/vault/vault"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -64,9 +61,7 @@ func TestAutoAuthSelfHealing_TokenFileAuth_SinkOutput(t *testing.T) {
|
|||||||
serverClient := cluster.Cores[0].Client
|
serverClient := cluster.Cores[0].Client
|
||||||
|
|
||||||
// Create token
|
// Create token
|
||||||
secret, err := serverClient.Auth().Token().Create(&api.TokenCreateRequest{
|
secret, err := serverClient.Auth().Token().Create(&api.TokenCreateRequest{})
|
||||||
Policies: []string{"test-autoauth"},
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, secret)
|
require.NotNil(t, secret)
|
||||||
require.NotNil(t, secret.Auth)
|
require.NotNil(t, secret.Auth)
|
||||||
@@ -143,9 +138,14 @@ func TestAutoAuthSelfHealing_TokenFileAuth_SinkOutput(t *testing.T) {
|
|||||||
StaticSecretRenderInt: secretRenderInterval,
|
StaticSecretRenderInt: secretRenderInterval,
|
||||||
},
|
},
|
||||||
AutoAuth: &agentConfig.AutoAuth{
|
AutoAuth: &agentConfig.AutoAuth{
|
||||||
Sinks: []*agentConfig.Sink{{Type: "file", Config: map[string]interface{}{
|
Sinks: []*agentConfig.Sink{
|
||||||
"path": pathLookupSelf,
|
{
|
||||||
}}},
|
Type: "file",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"path": pathLookupSelf,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ExitAfterAuth: false,
|
ExitAfterAuth: false,
|
||||||
},
|
},
|
||||||
@@ -235,59 +235,59 @@ func TestAutoAuthSelfHealing_TokenFileAuth_SinkOutput(t *testing.T) {
|
|||||||
// is not re-triggered if a token with incorrect policy access
|
// is not re-triggered if a token with incorrect policy access
|
||||||
// is used to render a template
|
// is used to render a template
|
||||||
func Test_NoAutoAuthSelfHealing_BadPolicy(t *testing.T) {
|
func Test_NoAutoAuthSelfHealing_BadPolicy(t *testing.T) {
|
||||||
logger := logging.NewVaultLogger(hclog.Trace)
|
// Unset the environment variable so that agent picks up the right test cluster address
|
||||||
cluster := vault.NewTestCluster(t,
|
t.Setenv(api.EnvVaultAddress, "")
|
||||||
&vault.CoreConfig{},
|
|
||||||
&vault.TestClusterOptions{
|
|
||||||
NumCores: 1,
|
|
||||||
HandlerFunc: vaulthttp.Handler,
|
|
||||||
})
|
|
||||||
cluster.Start()
|
|
||||||
defer cluster.Cleanup()
|
|
||||||
|
|
||||||
vault.TestWaitActive(t, cluster.Cores[0].Core)
|
tmpDir := t.TempDir()
|
||||||
|
pathKVData := filepath.Join(tmpDir, "kvData")
|
||||||
|
pathVaultToken := filepath.Join(tmpDir, "vault-token")
|
||||||
|
pathTokenFile := filepath.Join(tmpDir, "token-file")
|
||||||
|
policyName := "kv-access"
|
||||||
|
secretRenderInterval := 1 * time.Second
|
||||||
|
contextTimeout := 30 * time.Second
|
||||||
|
|
||||||
|
cluster := minimal.NewTestSoloCluster(t, nil)
|
||||||
|
logger := corehelpers.NewTestLogger(t)
|
||||||
serverClient := cluster.Cores[0].Client
|
serverClient := cluster.Cores[0].Client
|
||||||
|
|
||||||
// Unset the environment variable so that agent picks up the right test
|
|
||||||
// cluster address
|
|
||||||
defer os.Setenv(api.EnvVaultAddress, os.Getenv(api.EnvVaultAddress))
|
|
||||||
os.Unsetenv(api.EnvVaultAddress)
|
|
||||||
|
|
||||||
// Create temp dir for this test run
|
|
||||||
tmpDir, err := os.MkdirTemp("", "TestAutoAuth_SelfHealing")
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer os.RemoveAll(tmpDir)
|
|
||||||
|
|
||||||
// Write a policy with correct access to the secrets
|
// Write a policy with correct access to the secrets
|
||||||
serverClient.Sys().PutPolicy("kv-access", kvAccessPolicy)
|
err := serverClient.Sys().PutPolicy(policyName, kvAccessPolicy)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create a token without enough policy access to the kv secrets
|
// Create a token without enough policy access to the kv secrets
|
||||||
secret, err := serverClient.Auth().Token().Create(&api.TokenCreateRequest{})
|
secret, err := serverClient.Auth().Token().Create(&api.TokenCreateRequest{
|
||||||
|
Policies: []string{"test-autoauth"},
|
||||||
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, secret)
|
||||||
|
require.NotNil(t, secret.Auth)
|
||||||
|
require.NotEmpty(t, secret.Auth.ClientToken)
|
||||||
|
require.Len(t, secret.Auth.Policies, 2)
|
||||||
|
require.Contains(t, secret.Auth.Policies, "default")
|
||||||
|
require.Contains(t, secret.Auth.Policies, "test-autoauth")
|
||||||
token := secret.Auth.ClientToken
|
token := secret.Auth.ClientToken
|
||||||
|
|
||||||
// Write token to vault-token file
|
// Write token to vault-token file
|
||||||
tokenFilePath := filepath.Join(tmpDir, "vault-token")
|
tokenFile, err := os.Create(pathVaultToken)
|
||||||
tokenFile, err := os.Create(tokenFilePath)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = tokenFile.WriteString(token)
|
_, err = tokenFile.WriteString(token)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = tokenFile.Close()
|
err = tokenFile.Close()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
defer os.Remove(tokenFilePath)
|
// Give us some leeway of 3 errors 1 from each of: auth handler, sink server template server.
|
||||||
require.NoError(t, err)
|
errCh := make(chan error, 3)
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
|
|
||||||
// Create auth handler
|
// Create auth handler
|
||||||
am, err := tokenfile.NewTokenFileAuthMethod(&auth.AuthConfig{
|
am, err := tokenfile.NewTokenFileAuthMethod(&auth.AuthConfig{
|
||||||
Logger: logger.Named("auth.method"),
|
Logger: logger.Named("auth.method"),
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"token_file_path": filepath.Join(filepath.Join(tmpDir, "vault-token")),
|
"token_file_path": pathVaultToken,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ahConfig := &auth.AuthHandlerConfig{
|
ahConfig := &auth.AuthHandlerConfig{
|
||||||
Logger: logger.Named("auth.handler"),
|
Logger: logger.Named("auth.handler"),
|
||||||
Client: serverClient,
|
Client: serverClient,
|
||||||
@@ -296,34 +296,20 @@ func Test_NoAutoAuthSelfHealing_BadPolicy(t *testing.T) {
|
|||||||
ExitOnError: false,
|
ExitOnError: false,
|
||||||
}
|
}
|
||||||
ah := auth.NewAuthHandler(ahConfig)
|
ah := auth.NewAuthHandler(ahConfig)
|
||||||
errCh := make(chan error)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
errCh <- ah.Run(ctx, am)
|
errCh <- ah.Run(ctx, am)
|
||||||
}()
|
}()
|
||||||
defer func() {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
case err := <-errCh:
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Create sink file server
|
// Create sink file server
|
||||||
sinkFilePath := filepath.Join(tmpDir, "token-file")
|
_, err = os.Create(pathTokenFile)
|
||||||
_, err = os.Create(sinkFilePath)
|
|
||||||
defer os.Remove(sinkFilePath)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
config := &sink.SinkConfig{
|
config := &sink.SinkConfig{
|
||||||
Logger: logger.Named("sink.file"),
|
Logger: logger.Named("sink.file"),
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"path": sinkFilePath,
|
"path": pathTokenFile,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fs, err := file.NewFileSink(config)
|
fs, err := file.NewFileSink(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -334,30 +320,20 @@ func Test_NoAutoAuthSelfHealing_BadPolicy(t *testing.T) {
|
|||||||
Logger: logger.Named("sink.server"),
|
Logger: logger.Named("sink.server"),
|
||||||
Client: serverClient,
|
Client: serverClient,
|
||||||
})
|
})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
errCh <- ss.Run(ctx, ah.OutputCh, []*sink.SinkConfig{config}, ah.AuthInProgress)
|
errCh <- ss.Run(ctx, ah.OutputCh, []*sink.SinkConfig{config}, ah.AuthInProgress)
|
||||||
}()
|
}()
|
||||||
defer func() {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
case err := <-errCh:
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Create template server
|
// Create template server
|
||||||
sc := template.ServerConfig{
|
sc := template.ServerConfig{
|
||||||
Logger: logging.NewVaultLogger(hclog.Trace),
|
Logger: logger.Named("template.server"),
|
||||||
AgentConfig: &agentConfig.Config{
|
AgentConfig: &agentConfig.Config{
|
||||||
Vault: &agentConfig.Vault{
|
Vault: &agentConfig.Vault{
|
||||||
Address: serverClient.Address(),
|
Address: serverClient.Address(),
|
||||||
TLSSkipVerify: true,
|
TLSSkipVerify: true,
|
||||||
},
|
},
|
||||||
TemplateConfig: &agentConfig.TemplateConfig{
|
TemplateConfig: &agentConfig.TemplateConfig{
|
||||||
StaticSecretRenderInt: time.Second * 5,
|
StaticSecretRenderInt: secretRenderInterval,
|
||||||
},
|
},
|
||||||
// Need to crate at least one sink output so that it does not exit after rendering
|
// Need to crate at least one sink output so that it does not exit after rendering
|
||||||
AutoAuth: &agentConfig.AutoAuth{
|
AutoAuth: &agentConfig.AutoAuth{
|
||||||
@@ -365,7 +341,7 @@ func Test_NoAutoAuthSelfHealing_BadPolicy(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Type: "file",
|
Type: "file",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"path": filepath.Join(filepath.Join(tmpDir, "kvData")),
|
"path": pathKVData,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -378,60 +354,67 @@ func Test_NoAutoAuthSelfHealing_BadPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
templateTest := &ctconfig.TemplateConfig{
|
templateTest := &ctconfig.TemplateConfig{
|
||||||
Contents: pointerutil.StringPtr(kvDataTemplateContents),
|
Contents: pointerutil.StringPtr(kvDataTemplateContents),
|
||||||
|
Destination: pointerutil.StringPtr(pathKVData),
|
||||||
}
|
}
|
||||||
dstFile := fmt.Sprintf("%s/%s", tmpDir, "kvData")
|
|
||||||
templateTest.Destination = pointerutil.StringPtr(dstFile)
|
|
||||||
templatesToRender := []*ctconfig.TemplateConfig{templateTest}
|
templatesToRender := []*ctconfig.TemplateConfig{templateTest}
|
||||||
|
|
||||||
var server *template.Server
|
var server *template.Server
|
||||||
server = template.NewServer(&sc)
|
server = template.NewServer(&sc)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
errCh <- server.Run(ctx, ah.TemplateTokenCh, templatesToRender, ah.AuthInProgress, ah.InvalidToken)
|
errCh <- server.Run(ctx, ah.TemplateTokenCh, templatesToRender, ah.AuthInProgress, ah.InvalidToken)
|
||||||
}()
|
}()
|
||||||
defer func() {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
case err := <-errCh:
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Must be done at the very end so that nothing is blocking
|
// Trigger template render (mark the time as being earlier, based on the render interval)
|
||||||
defer cancel()
|
preTriggerTime := time.Now().Add(-secretRenderInterval)
|
||||||
|
|
||||||
// Trigger template render
|
|
||||||
ah.TemplateTokenCh <- token
|
ah.TemplateTokenCh <- token
|
||||||
_, err = waitForFiles(t, filepath.Join(tmpDir, "token-file"), time.Time{})
|
_, err = waitForFiles(t, pathTokenFile, preTriggerTime)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tokenInSink, err := os.ReadFile(filepath.Join(tmpDir, "token-file"))
|
tokenInSink, err := os.ReadFile(pathTokenFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, string(tokenInSink), token)
|
require.Equal(t, token, string(tokenInSink))
|
||||||
|
|
||||||
// Create new token with the correct policy access
|
// Create new token with the correct policy access
|
||||||
tokenSecret, err := serverClient.Auth().Token().Create(&api.TokenCreateRequest{
|
tokenSecret, err := serverClient.Auth().Token().Create(&api.TokenCreateRequest{
|
||||||
Policies: []string{"kv-access"},
|
Policies: []string{policyName},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, tokenSecret)
|
||||||
|
require.NotNil(t, tokenSecret.Auth)
|
||||||
|
require.NotEmpty(t, tokenSecret.Auth.ClientToken)
|
||||||
|
require.Len(t, tokenSecret.Auth.Policies, 2)
|
||||||
|
require.Contains(t, tokenSecret.Auth.Policies, "default")
|
||||||
|
require.Contains(t, tokenSecret.Auth.Policies, policyName)
|
||||||
newToken := tokenSecret.Auth.ClientToken
|
newToken := tokenSecret.Auth.ClientToken
|
||||||
|
|
||||||
// Write token to file
|
// Write token to file
|
||||||
err = os.WriteFile(filepath.Join(tmpDir, "vault-token"), []byte(token), 0o600)
|
err = os.WriteFile(pathVaultToken, []byte(token), 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Wait for any potential *incorrect* re-triggers of auto auth
|
// Wait for any potential *incorrect* re-triggers of auto auth
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(secretRenderInterval * 3)
|
||||||
|
|
||||||
// Auto auth should not have been re-triggered because of just a permission denied error
|
// Auto auth should not have been re-triggered because of just a permission denied error
|
||||||
// Verify that the new token has NOT been written to the token sink
|
// Verify that the new token has NOT been written to the token sink
|
||||||
tokenInSink, err = os.ReadFile(filepath.Join(tmpDir, "token-file"))
|
tokenInSink, err = os.ReadFile(pathTokenFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEqual(t, string(tokenInSink), newToken)
|
require.NotEqual(t, newToken, string(tokenInSink))
|
||||||
require.Equal(t, string(tokenInSink), token)
|
require.Equal(t, token, string(tokenInSink))
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
wrapUpTimeout := 5 * time.Second
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-time.After(wrapUpTimeout):
|
||||||
|
t.Fatal("test timed out")
|
||||||
|
case err := <-errCh:
|
||||||
|
require.NoError(t, err)
|
||||||
|
case <-ctx.Done():
|
||||||
|
// We can finish the test ourselves
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForFiles(t *testing.T, filePath string, prevModTime time.Time) (os.FileInfo, error) {
|
func waitForFiles(t *testing.T, filePath string, prevModTime time.Time) (os.FileInfo, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user