diff --git a/audit/broker.go b/audit/broker.go index 96cd1405f3d1..9f582bec048c 100644 --- a/audit/broker.go +++ b/audit/broker.go @@ -315,6 +315,12 @@ func (b *Broker) LogRequest(ctx context.Context, in *logical.LogInput) (ret erro // Audit event ended up in at least 1 sink. if len(status.CompleteSinks()) > 0 { + // We should log warnings to the operational logs regardless of whether + // we consider the overall auditing attempt to be successful. + if len(status.Warnings) > 0 { + b.logger.Error("log request underlying pipeline error(s)", "error", &multierror.Error{Errors: status.Warnings}) + } + return retErr.ErrorOrNil() } @@ -397,6 +403,12 @@ func (b *Broker) LogResponse(ctx context.Context, in *logical.LogInput) (ret err // Audit event ended up in at least 1 sink. if len(status.CompleteSinks()) > 0 { + // We should log warnings to the operational logs regardless of whether + // we consider the overall auditing attempt to be successful. + if len(status.Warnings) > 0 { + b.logger.Error("log response underlying pipeline error(s)", "error", &multierror.Error{Errors: status.Warnings}) + } + return retErr.ErrorOrNil() } diff --git a/builtin/logical/database/backend_test.go b/builtin/logical/database/backend_test.go index a1b96ad392f1..8cfa8535cb5f 100644 --- a/builtin/logical/database/backend_test.go +++ b/builtin/logical/database/backend_test.go @@ -359,7 +359,7 @@ func TestBackend_BadConnectionString(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, _ := postgreshelper.PrepareTestContainer(t, "13.4-buster") + cleanup, _ := postgreshelper.PrepareTestContainer(t) defer cleanup() respCheck := func(req *logical.Request) { @@ -410,7 +410,7 @@ func TestBackend_basic(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // Configure a connection @@ -665,7 +665,7 @@ func TestBackend_connectionCrud(t *testing.T) { dbFactory.sys = sys client := cluster.Cores[0].Client.Logical() - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // Mount the database plugin. @@ -872,7 +872,7 @@ func TestBackend_roleCrud(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // Configure a connection @@ -1121,7 +1121,7 @@ func TestBackend_allowedRoles(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // Configure a connection @@ -1318,7 +1318,7 @@ func TestBackend_RotateRootCredentials(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() connURL = strings.ReplaceAll(connURL, "postgres:secret", "{{username}}:{{password}}") diff --git a/builtin/logical/database/path_roles_test.go b/builtin/logical/database/path_roles_test.go index 91737da2cf8b..41a2e99758aa 100644 --- a/builtin/logical/database/path_roles_test.go +++ b/builtin/logical/database/path_roles_test.go @@ -222,7 +222,7 @@ func TestBackend_StaticRole_Config(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // create the database user @@ -487,7 +487,7 @@ func TestBackend_StaticRole_ReadCreds(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // create the database user @@ -667,7 +667,7 @@ func TestBackend_StaticRole_Updates(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // create the database user @@ -966,7 +966,7 @@ func TestBackend_StaticRole_Role_name_check(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // create the database user diff --git a/builtin/logical/database/rollback_test.go b/builtin/logical/database/rollback_test.go index f60491a6662c..47c768374296 100644 --- a/builtin/logical/database/rollback_test.go +++ b/builtin/logical/database/rollback_test.go @@ -44,7 +44,7 @@ func TestBackend_RotateRootCredentials_WAL_rollback(t *testing.T) { } defer lb.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() connURL = strings.ReplaceAll(connURL, "postgres:secret", "{{username}}:{{password}}") @@ -183,7 +183,7 @@ func TestBackend_RotateRootCredentials_WAL_no_rollback_1(t *testing.T) { } defer lb.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() connURL = strings.ReplaceAll(connURL, "postgres:secret", "{{username}}:{{password}}") @@ -291,7 +291,7 @@ func TestBackend_RotateRootCredentials_WAL_no_rollback_2(t *testing.T) { } defer lb.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() connURL = strings.ReplaceAll(connURL, "postgres:secret", "{{username}}:{{password}}") diff --git a/builtin/logical/database/rotation_test.go b/builtin/logical/database/rotation_test.go index c9917cb37458..99fc3ddf004b 100644 --- a/builtin/logical/database/rotation_test.go +++ b/builtin/logical/database/rotation_test.go @@ -63,7 +63,7 @@ func TestBackend_StaticRole_Rotation_basic(t *testing.T) { b.schedule = &TestSchedule{} - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // create the database user @@ -274,7 +274,7 @@ func TestBackend_StaticRole_Rotation_Schedule_ErrorRecover(t *testing.T) { b.schedule = &TestSchedule{} - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) t.Cleanup(cleanup) // create the database user @@ -458,7 +458,7 @@ func TestBackend_StaticRole_Rotation_NonStaticError(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // create the database user @@ -562,7 +562,7 @@ func TestBackend_StaticRole_Rotation_Revoke_user(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // create the database user @@ -783,7 +783,7 @@ func TestBackend_StaticRole_Rotation_QueueWAL_discard_role_newer_rotation_date(t t.Fatal("could not convert to db backend") } - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // create the database user @@ -952,7 +952,7 @@ func assertWALCount(t *testing.T, s logical.Storage, expected int, key string) { type userCreator func(t *testing.T, username, password string) func TestBackend_StaticRole_Rotation_PostgreSQL(t *testing.T) { - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() uc := userCreator(func(t *testing.T, username, password string) { createTestPGUser(t, connURL, username, password, testRoleStaticCreate) @@ -1246,7 +1246,7 @@ func TestBackend_StaticRole_Rotation_LockRegression(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // Configure a connection @@ -1325,7 +1325,7 @@ func TestBackend_StaticRole_Rotation_Invalid_Role(t *testing.T) { } defer b.Cleanup(context.Background()) - cleanup, connURL := postgreshelper.PrepareTestContainer(t, "") + cleanup, connURL := postgreshelper.PrepareTestContainer(t) defer cleanup() // create the database user diff --git a/builtin/logical/database/secret_creds.go b/builtin/logical/database/secret_creds.go index e2130c1cf7da..b485f7ca46bb 100644 --- a/builtin/logical/database/secret_creds.go +++ b/builtin/logical/database/secret_creds.go @@ -34,6 +34,9 @@ func (b *databaseBackend) secretCredsRenew() framework.OperationFunc { return nil, fmt.Errorf("secret is missing username internal data") } username, ok := usernameRaw.(string) + if !ok { + return nil, fmt.Errorf("username not a string") + } roleNameRaw, ok := req.Secret.InternalData["role"] if !ok { @@ -98,6 +101,9 @@ func (b *databaseBackend) secretCredsRevoke() framework.OperationFunc { return nil, fmt.Errorf("secret is missing username internal data") } username, ok := usernameRaw.(string) + if !ok { + return nil, fmt.Errorf("username not a string") + } var resp *logical.Response diff --git a/changelog/27790.txt b/changelog/27790.txt new file mode 100644 index 000000000000..1475d0831a2b --- /dev/null +++ b/changelog/27790.txt @@ -0,0 +1,3 @@ +```release-note:change +activity (enterprise): filter all fields in client count responses by the request namespace +``` \ No newline at end of file diff --git a/changelog/27809.txt b/changelog/27809.txt new file mode 100644 index 000000000000..332c9155d95a --- /dev/null +++ b/changelog/27809.txt @@ -0,0 +1,3 @@ +```release-note:improvement +audit: Ensure that any underyling errors from audit devices are logged even if we consider auditing to be a success. +``` \ No newline at end of file diff --git a/command/agentproxyshared/auth/auth.go b/command/agentproxyshared/auth/auth.go index 96f5026cbb92..91e189ed2604 100644 --- a/command/agentproxyshared/auth/auth.go +++ b/command/agentproxyshared/auth/auth.go @@ -313,10 +313,11 @@ func (ah *AuthHandler) Run(ctx context.Context, am AuthMethod) error { isTokenFileMethod = path == "auth/token/lookup-self" if isTokenFileMethod { token, _ := data["token"].(string) - lookupSelfClient, err := clientToUse.CloneWithHeaders() - if err != nil { + // The error is called clientErr as to not shadow the other err above it. + lookupSelfClient, clientErr := clientToUse.CloneWithHeaders() + if clientErr != nil { ah.logger.Error("failed to clone client to perform token lookup") - return err + return clientErr } lookupSelfClient.SetToken(token) secret, err = lookupSelfClient.Auth().Token().LookupSelf() diff --git a/command/pki_reissue_intermediate.go b/command/pki_reissue_intermediate.go index fa4dd38fbe77..7501d4c8622a 100644 --- a/command/pki_reissue_intermediate.go +++ b/command/pki_reissue_intermediate.go @@ -113,6 +113,10 @@ func (c *PKIReIssueCACommand) Run(args []string) int { } templateData, err := parseTemplateCertificate(*certificate, useExistingKey, keyRef) + if err != nil { + c.UI.Error(fmt.Sprintf("Error fetching parsing template certificate: %v", err)) + return 1 + } data := updateTemplateWithData(templateData, userData) return pkiIssue(c.BaseCommand, parentIssuer, intermediateMount, c.flagNewIssuerName, c.flagKeyStorageSource, data) diff --git a/go.mod b/go.mod index 96048e19d8a7..dc18dfcbb284 100644 --- a/go.mod +++ b/go.mod @@ -221,7 +221,7 @@ require ( golang.org/x/text v0.16.0 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d google.golang.org/api v0.181.0 - google.golang.org/grpc v1.64.0 + google.golang.org/grpc v1.64.1 google.golang.org/protobuf v1.34.1 gopkg.in/ory-am/dockertest.v3 v3.3.4 k8s.io/apimachinery v0.29.3 diff --git a/go.sum b/go.sum index f45ca45f82cf..dfcf5acdc7f6 100644 --- a/go.sum +++ b/go.sum @@ -3016,8 +3016,8 @@ google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/helper/testhelpers/pluginhelpers/pluginhelpers.go b/helper/testhelpers/pluginhelpers/pluginhelpers.go index 1a6643cae391..2d9c2355399d 100644 --- a/helper/testhelpers/pluginhelpers/pluginhelpers.go +++ b/helper/testhelpers/pluginhelpers/pluginhelpers.go @@ -76,15 +76,17 @@ func CompilePlugin(t testing.TB, typ consts.PluginType, pluginVersion string, pl var pluginBytes []byte dir := "" - var err error pluginRootDir := "builtin" if typ == consts.PluginTypeDatabase { pluginRootDir = "plugins" } for { - dir, err = os.Getwd() - if err != nil { - t.Fatal(err) + // So that we can assign to dir without overshadowing the other + // err variables. + var getWdErr error + dir, getWdErr = os.Getwd() + if getWdErr != nil { + t.Fatal(getWdErr) } // detect if we are in a subdirectory or the root directory and compensate if _, err := os.Stat(pluginRootDir); os.IsNotExist(err) { @@ -128,15 +130,20 @@ func CompilePlugin(t testing.TB, typ consts.PluginType, pluginVersion string, pl } // write the cached plugin if necessary - if _, err := os.Stat(pluginPath); os.IsNotExist(err) { - err = os.WriteFile(pluginPath, pluginBytes, 0o755) - } - if err != nil { - t.Fatal(err) + _, statErr := os.Stat(pluginPath) + if os.IsNotExist(statErr) { + err := os.WriteFile(pluginPath, pluginBytes, 0o755) + if err != nil { + t.Fatal(err) + } + } else { + if statErr != nil { + t.Fatal(statErr) + } } sha := sha256.New() - _, err = sha.Write(pluginBytes) + _, err := sha.Write(pluginBytes) if err != nil { t.Fatal(err) } diff --git a/helper/testhelpers/postgresql/postgresqlhelper.go b/helper/testhelpers/postgresql/postgresqlhelper.go index 7e5f25c626af..f0aa1203bdda 100644 --- a/helper/testhelpers/postgresql/postgresqlhelper.go +++ b/helper/testhelpers/postgresql/postgresqlhelper.go @@ -14,13 +14,29 @@ import ( "github.com/hashicorp/vault/sdk/helper/docker" ) -func PrepareTestContainer(t *testing.T, version string) (func(), string) { - env := []string{ - "POSTGRES_PASSWORD=secret", - "POSTGRES_DB=database", +const postgresVersion = "13.4-buster" + +func defaultRunOpts(t *testing.T) docker.RunOptions { + return docker.RunOptions{ + ContainerName: "postgres", + ImageRepo: "docker.mirror.hashicorp.services/postgres", + ImageTag: postgresVersion, + Env: []string{ + "POSTGRES_PASSWORD=secret", + "POSTGRES_DB=database", + }, + Ports: []string{"5432/tcp"}, + DoNotAutoRemove: false, + LogConsumer: func(s string) { + if t.Failed() { + t.Logf("container logs: %s", s) + } + }, } +} - _, cleanup, url, _ := prepareTestContainer(t, "postgres", "docker.mirror.hashicorp.services/postgres", version, "secret", true, false, false, env) +func PrepareTestContainer(t *testing.T) (func(), string) { + _, cleanup, url, _ := prepareTestContainer(t, defaultRunOpts(t), "secret", true, false) return cleanup, url } @@ -28,64 +44,82 @@ func PrepareTestContainer(t *testing.T, version string) (func(), string) { // PrepareTestContainerWithVaultUser will setup a test container with a Vault // admin user configured so that we can safely call rotate-root without // rotating the root DB credentials -func PrepareTestContainerWithVaultUser(t *testing.T, ctx context.Context, version string) (func(), string) { - env := []string{ - "POSTGRES_PASSWORD=secret", - "POSTGRES_DB=database", +func PrepareTestContainerWithVaultUser(t *testing.T, ctx context.Context) (func(), string) { + runner, cleanup, url, id := prepareTestContainer(t, defaultRunOpts(t), "secret", true, false) + + cmd := []string{"psql", "-U", "postgres", "-c", "CREATE USER vaultadmin WITH LOGIN PASSWORD 'vaultpass' SUPERUSER"} + _, err := runner.RunCmdInBackground(ctx, id, cmd) + if err != nil { + t.Fatalf("Could not run command (%v) in container: %v", cmd, err) } - runner, cleanup, url, id := prepareTestContainer(t, "postgres", "docker.mirror.hashicorp.services/postgres", version, "secret", true, false, false, env) + return cleanup, url +} + +func PrepareTestContainerWithSSL(t *testing.T, ctx context.Context, version string) (func(), string) { + runOpts := defaultRunOpts(t) + runOpts.Cmd = []string{"-c", "log_statement=all"} + runner, cleanup, url, id := prepareTestContainer(t, runOpts, "secret", true, false) + + content := "echo 'hostssl all all all cert clientcert=verify-ca' > /var/lib/postgresql/data/pg_hba.conf" + // Copy the ssl init script into the newly running container. + buildCtx := docker.NewBuildContext() + buildCtx["ssl-conf.sh"] = docker.PathContentsFromBytes([]byte(content)) + if err := runner.CopyTo(id, "/usr/local/bin", buildCtx); err != nil { + t.Fatalf("Could not copy ssl init script into container: %v", err) + } - cmd := []string{"psql", "-U", "postgres", "-c", "CREATE USER vaultadmin WITH LOGIN PASSWORD 'vaultpass' SUPERUSER"} + // run the ssl init script to overwrite the pg_hba.conf file and set it to + // require SSL for each connection + cmd := []string{"bash", "/usr/local/bin/ssl-conf.sh"} _, err := runner.RunCmdInBackground(ctx, id, cmd) if err != nil { t.Fatalf("Could not run command (%v) in container: %v", cmd, err) } + // reload so the config changes take effect + cmd = []string{"psql", "-U", "postgres", "-c", "SELECT pg_reload_conf()"} + _, err = runner.RunCmdInBackground(ctx, id, cmd) + if err != nil { + t.Fatalf("Could not run command (%v) in container: %v", cmd, err) + } + return cleanup, url } func PrepareTestContainerWithPassword(t *testing.T, version, password string) (func(), string) { - env := []string{ + runOpts := defaultRunOpts(t) + runOpts.Env = []string{ "POSTGRES_PASSWORD=" + password, "POSTGRES_DB=database", } - _, cleanup, url, _ := prepareTestContainer(t, "postgres", "docker.mirror.hashicorp.services/postgres", version, password, true, false, false, env) + _, cleanup, url, _ := prepareTestContainer(t, runOpts, password, true, false) return cleanup, url } func PrepareTestContainerRepmgr(t *testing.T, name, version string, envVars []string) (*docker.Runner, func(), string, string) { - env := append(envVars, + runOpts := defaultRunOpts(t) + runOpts.ImageRepo = "docker.mirror.hashicorp.services/bitnami/postgresql-repmgr" + runOpts.ImageTag = version + runOpts.Env = append(envVars, "REPMGR_PARTNER_NODES=psql-repl-node-0,psql-repl-node-1", "REPMGR_PRIMARY_HOST=psql-repl-node-0", "REPMGR_PASSWORD=repmgrpass", "POSTGRESQL_PASSWORD=secret") + runOpts.DoNotAutoRemove = true - return prepareTestContainer(t, name, "docker.mirror.hashicorp.services/bitnami/postgresql-repmgr", version, "secret", false, true, true, env) + return prepareTestContainer(t, runOpts, "secret", false, true) } -func prepareTestContainer(t *testing.T, name, repo, version, password string, - addSuffix, forceLocalAddr, doNotAutoRemove bool, envVars []string, +func prepareTestContainer(t *testing.T, runOpts docker.RunOptions, password string, addSuffix, forceLocalAddr bool, ) (*docker.Runner, func(), string, string) { if os.Getenv("PG_URL") != "" { return nil, func() {}, "", os.Getenv("PG_URL") } - if version == "" { - version = "11" - } - - runOpts := docker.RunOptions{ - ContainerName: name, - ImageRepo: repo, - ImageTag: version, - Env: envVars, - Ports: []string{"5432/tcp"}, - DoNotAutoRemove: doNotAutoRemove, - } - if repo == "bitnami/postgresql-repmgr" { + if runOpts.ImageRepo == "bitnami/postgresql-repmgr" { runOpts.NetworkID = os.Getenv("POSTGRES_MULTIHOST_NET") } @@ -94,7 +128,7 @@ func prepareTestContainer(t *testing.T, name, repo, version, password string, t.Fatalf("Could not start docker Postgres: %s", err) } - svc, containerID, err := runner.StartNewService(context.Background(), addSuffix, forceLocalAddr, connectPostgres(password, repo)) + svc, containerID, err := runner.StartNewService(context.Background(), addSuffix, forceLocalAddr, connectPostgres(password, runOpts.ImageRepo)) if err != nil { t.Fatalf("Could not start docker Postgres: %s", err) } diff --git a/physical/postgresql/postgresql_test.go b/physical/postgresql/postgresql_test.go index 301fc15ec263..0dc0ce948602 100644 --- a/physical/postgresql/postgresql_test.go +++ b/physical/postgresql/postgresql_test.go @@ -22,7 +22,7 @@ func TestPostgreSQLBackend(t *testing.T) { // Use docker as pg backend if no url is provided via environment variables connURL := os.Getenv("PGURL") if connURL == "" { - cleanup, u := postgresql.PrepareTestContainer(t, "11.1") + cleanup, u := postgresql.PrepareTestContainer(t) defer cleanup() connURL = u } diff --git a/plugins/database/postgresql/postgresql_test.go b/plugins/database/postgresql/postgresql_test.go index 90184e10a3eb..23b04788bbfb 100644 --- a/plugins/database/postgresql/postgresql_test.go +++ b/plugins/database/postgresql/postgresql_test.go @@ -24,7 +24,7 @@ import ( ) func getPostgreSQL(t *testing.T, options map[string]interface{}) (*PostgreSQL, func()) { - cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgresql.PrepareTestContainer(t) connectionDetails := map[string]interface{}{ "connection_url": connURL, @@ -70,7 +70,7 @@ func TestPostgreSQL_InitializeWithStringVals(t *testing.T) { } func TestPostgreSQL_Initialize_ConnURLWithDSNFormat(t *testing.T) { - cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgresql.PrepareTestContainer(t) defer cleanup() dsnConnURL, err := dbutil.ParseURL(connURL) @@ -185,7 +185,7 @@ func TestPostgreSQL_Initialize_CloudGCP(t *testing.T) { // TestPostgreSQL_PasswordAuthentication tests that the default "password_authentication" is "none", and that // an error is returned if an invalid "password_authentication" is provided. func TestPostgreSQL_PasswordAuthentication(t *testing.T) { - cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgresql.PrepareTestContainer(t) defer cleanup() dsnConnURL, err := dbutil.ParseURL(connURL) @@ -227,7 +227,7 @@ func TestPostgreSQL_PasswordAuthentication(t *testing.T) { // TestPostgreSQL_PasswordAuthentication_SCRAMSHA256 tests that password_authentication works when set to scram-sha-256. // When sending an encrypted password, the raw password should still successfully authenticate the user. func TestPostgreSQL_PasswordAuthentication_SCRAMSHA256(t *testing.T) { - cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgresql.PrepareTestContainer(t) defer cleanup() dsnConnURL, err := dbutil.ParseURL(connURL) @@ -1092,7 +1092,7 @@ func TestUsernameGeneration(t *testing.T) { } func TestNewUser_CustomUsername(t *testing.T) { - cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster") + cleanup, connURL := postgresql.PrepareTestContainer(t) defer cleanup() type testCase struct { diff --git a/ui/app/components/transit-edit.js b/ui/app/components/transit-edit.js index c3f34b3d8d32..7949912cac66 100644 --- a/ui/app/components/transit-edit.js +++ b/ui/app/components/transit-edit.js @@ -60,10 +60,10 @@ export default Component.extend(FocusOnInsertMixin, { models: [this.key.backend, this.key.id], query: { tab: 'details' }, }, - { label: 'edit' }, + { label: 'Edit' }, ]; } else if (this.mode === 'create') { - return [...baseCrumbs, { label: 'create' }]; + return [...baseCrumbs, { label: 'Create' }]; } return baseCrumbs; }, diff --git a/ui/app/controllers/vault/cluster/access/leases/list.js b/ui/app/controllers/vault/cluster/access/leases/list.js index 31b22f0db531..6bab2deafd50 100644 --- a/ui/app/controllers/vault/cluster/access/leases/list.js +++ b/ui/app/controllers/vault/cluster/access/leases/list.js @@ -26,7 +26,7 @@ export default Controller.extend(ListController, { backendCrumb: computed('clusterController.model.name', function () { return { - label: 'leases', + label: 'Leases', text: 'Leases', path: 'vault.cluster.access.leases.list-root', model: this.clusterController.model.name, diff --git a/ui/app/controllers/vault/cluster/access/leases/show.js b/ui/app/controllers/vault/cluster/access/leases/show.js index f8f8e7efd83f..1838ad3bdc51 100644 --- a/ui/app/controllers/vault/cluster/access/leases/show.js +++ b/ui/app/controllers/vault/cluster/access/leases/show.js @@ -13,7 +13,7 @@ export default Controller.extend({ backendCrumb: computed('clusterController.model.name', function () { return { - label: 'leases', + label: 'Leases', text: 'Leases', path: 'vault.cluster.access.leases.list-root', model: this.clusterController.model.name, diff --git a/ui/app/routes/vault/cluster/secrets/backend/actions.js b/ui/app/routes/vault/cluster/secrets/backend/actions.js index c1b413465096..2171a8e3d6cf 100644 --- a/ui/app/routes/vault/cluster/secrets/backend/actions.js +++ b/ui/app/routes/vault/cluster/secrets/backend/actions.js @@ -47,7 +47,7 @@ export default EditBase.extend({ models: [model.secret.backend, model.secret.id], }, { - label: 'actions', + label: 'Actions', }, ]); }, diff --git a/ui/lib/kubernetes/addon/routes/configuration.js b/ui/lib/kubernetes/addon/routes/configuration.js index 52edfff7de1e..270f87e4057c 100644 --- a/ui/lib/kubernetes/addon/routes/configuration.js +++ b/ui/lib/kubernetes/addon/routes/configuration.js @@ -28,7 +28,8 @@ export default class KubernetesConfigureRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, - { label: resolvedModel.backend.id }, + { label: resolvedModel.backend.id, route: 'overview', model: resolvedModel.backend }, + { label: 'Configuration' }, ]; } } diff --git a/ui/lib/kubernetes/addon/routes/configure.js b/ui/lib/kubernetes/addon/routes/configure.js index 6cd94bca26db..e5f7293d9b3d 100644 --- a/ui/lib/kubernetes/addon/routes/configure.js +++ b/ui/lib/kubernetes/addon/routes/configure.js @@ -22,8 +22,8 @@ export default class KubernetesConfigureRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, - { label: resolvedModel.backend, route: 'overview' }, - { label: 'configure' }, + { label: resolvedModel.backend, route: 'overview', model: resolvedModel.backend }, + { label: 'Configure' }, ]; } } diff --git a/ui/lib/kubernetes/addon/routes/roles/create.js b/ui/lib/kubernetes/addon/routes/roles/create.js index 43d742bbd91f..f87b7b7a0dc9 100644 --- a/ui/lib/kubernetes/addon/routes/roles/create.js +++ b/ui/lib/kubernetes/addon/routes/roles/create.js @@ -20,8 +20,8 @@ export default class KubernetesRolesCreateRoute extends Route { controller.breadcrumbs = [ { label: resolvedModel.backend, route: 'overview' }, - { label: 'roles', route: 'roles' }, - { label: 'create' }, + { label: 'Roles', route: 'roles', model: resolvedModel.backend }, + { label: 'Create' }, ]; } } diff --git a/ui/lib/kubernetes/addon/routes/roles/index.js b/ui/lib/kubernetes/addon/routes/roles/index.js index 1a868cc3c0f7..7aaebebfd625 100644 --- a/ui/lib/kubernetes/addon/routes/roles/index.js +++ b/ui/lib/kubernetes/addon/routes/roles/index.js @@ -41,7 +41,8 @@ export default class KubernetesRolesRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, - { label: resolvedModel.backend.id }, + { label: resolvedModel.backend.id, route: 'overview', model: resolvedModel.backend }, + { label: 'Roles' }, ]; } } diff --git a/ui/lib/kubernetes/addon/routes/roles/role/credentials.js b/ui/lib/kubernetes/addon/routes/roles/role/credentials.js index 6167f62aa7b5..840095bc60a6 100644 --- a/ui/lib/kubernetes/addon/routes/roles/role/credentials.js +++ b/ui/lib/kubernetes/addon/routes/roles/role/credentials.js @@ -20,9 +20,9 @@ export default class KubernetesRoleCredentialsRoute extends Route { controller.breadcrumbs = [ { label: resolvedModel.backend, route: 'overview' }, - { label: 'roles', route: 'roles' }, + { label: 'Roles', route: 'roles', model: resolvedModel.backend }, { label: resolvedModel.roleName, route: 'roles.role.details' }, - { label: 'credentials' }, + { label: 'Credentials' }, ]; } } diff --git a/ui/lib/kubernetes/addon/routes/roles/role/details.js b/ui/lib/kubernetes/addon/routes/roles/role/details.js index aafa8cdcbb38..3ef091dda8d3 100644 --- a/ui/lib/kubernetes/addon/routes/roles/role/details.js +++ b/ui/lib/kubernetes/addon/routes/roles/role/details.js @@ -21,7 +21,7 @@ export default class KubernetesRoleDetailsRoute extends Route { controller.breadcrumbs = [ { label: resolvedModel.backend, route: 'overview' }, - { label: 'roles', route: 'roles' }, + { label: 'Roles', route: 'roles', model: resolvedModel.backend }, { label: resolvedModel.name }, ]; } diff --git a/ui/lib/kubernetes/addon/routes/roles/role/edit.js b/ui/lib/kubernetes/addon/routes/roles/role/edit.js index 68dd3f070f30..78fa57249c7f 100644 --- a/ui/lib/kubernetes/addon/routes/roles/role/edit.js +++ b/ui/lib/kubernetes/addon/routes/roles/role/edit.js @@ -21,9 +21,9 @@ export default class KubernetesRoleEditRoute extends Route { controller.breadcrumbs = [ { label: resolvedModel.backend, route: 'overview' }, - { label: 'roles', route: 'roles' }, + { label: 'Roles', route: 'roles', model: resolvedModel.backend }, { label: resolvedModel.name, route: 'roles.role' }, - { label: 'edit' }, + { label: 'Edit' }, ]; } } diff --git a/ui/lib/kv/addon/routes/configuration.js b/ui/lib/kv/addon/routes/configuration.js index 31ae8c72a698..8f7ec7b6f862 100644 --- a/ui/lib/kv/addon/routes/configuration.js +++ b/ui/lib/kv/addon/routes/configuration.js @@ -26,7 +26,7 @@ export default class KvConfigurationRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.mountConfig.id, route: 'list', model: resolvedModel.engineConfig.backend }, - { label: 'configuration' }, + { label: 'Configuration' }, ]; } } diff --git a/ui/lib/kv/addon/routes/create.js b/ui/lib/kv/addon/routes/create.js index 0d80d2094371..e865c6193e4a 100644 --- a/ui/lib/kv/addon/routes/create.js +++ b/ui/lib/kv/addon/routes/create.js @@ -34,7 +34,7 @@ export default class KvSecretsCreateRoute extends Route { { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.backend, route: 'list', model: resolvedModel.backend }, ...breadcrumbsForSecret(resolvedModel.backend, resolvedModel.path), - { label: 'create' }, + { label: 'Create' }, ]; controller.breadcrumbs = crumbs; } diff --git a/ui/lib/kv/addon/routes/secret/details/edit.js b/ui/lib/kv/addon/routes/secret/details/edit.js index c2be82e45948..1be2cf263084 100644 --- a/ui/lib/kv/addon/routes/secret/details/edit.js +++ b/ui/lib/kv/addon/routes/secret/details/edit.js @@ -38,7 +38,7 @@ export default class KvSecretDetailsEditRoute extends Route { { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.backend, route: 'list', model: resolvedModel.backend }, ...breadcrumbsForSecret(resolvedModel.backend, resolvedModel.path), - { label: 'edit' }, + { label: 'Edit' }, ]; } } diff --git a/ui/lib/kv/addon/routes/secret/metadata/diff.js b/ui/lib/kv/addon/routes/secret/metadata/diff.js index 9cb944b40e70..39b4fa4ee346 100644 --- a/ui/lib/kv/addon/routes/secret/metadata/diff.js +++ b/ui/lib/kv/addon/routes/secret/metadata/diff.js @@ -15,8 +15,8 @@ export default class KvSecretMetadataDiffRoute extends Route { { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.backend, route: 'list', model: resolvedModel.backend }, ...breadcrumbsForSecret(resolvedModel.backend, resolvedModel.path), - { label: 'version history', route: 'secret.metadata.versions' }, - { label: 'diff' }, + { label: 'Version History', route: 'secret.metadata.versions' }, + { label: 'Diff' }, ]; controller.set('breadcrumbs', breadcrumbsArray); } diff --git a/ui/lib/kv/addon/routes/secret/metadata/edit.js b/ui/lib/kv/addon/routes/secret/metadata/edit.js index d250d8492ab8..e39cf669b324 100644 --- a/ui/lib/kv/addon/routes/secret/metadata/edit.js +++ b/ui/lib/kv/addon/routes/secret/metadata/edit.js @@ -16,8 +16,8 @@ export default class KvSecretMetadataEditRoute extends Route { { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.backend, route: 'list', model: resolvedModel.backend }, ...breadcrumbsForSecret(resolvedModel.backend, resolvedModel.path), - { label: 'metadata', route: 'secret.metadata' }, - { label: 'edit' }, + { label: 'Metadata', route: 'secret.metadata' }, + { label: 'Edit' }, ]; controller.set('breadcrumbs', breadcrumbsArray); diff --git a/ui/lib/kv/addon/routes/secret/metadata/index.js b/ui/lib/kv/addon/routes/secret/metadata/index.js index aea64592f84a..ddc4e7e90a1a 100644 --- a/ui/lib/kv/addon/routes/secret/metadata/index.js +++ b/ui/lib/kv/addon/routes/secret/metadata/index.js @@ -16,7 +16,7 @@ export default class KvSecretMetadataIndexRoute extends Route { { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.backend, route: 'list', model: resolvedModel.backend }, ...breadcrumbsForSecret(resolvedModel.backend, resolvedModel.path), - { label: 'metadata' }, + { label: 'Metadata' }, ]; controller.set('breadcrumbs', breadcrumbsArray); diff --git a/ui/lib/kv/addon/routes/secret/metadata/versions.js b/ui/lib/kv/addon/routes/secret/metadata/versions.js index ff152d1e0f96..1856533159d4 100644 --- a/ui/lib/kv/addon/routes/secret/metadata/versions.js +++ b/ui/lib/kv/addon/routes/secret/metadata/versions.js @@ -13,7 +13,7 @@ export default class KvSecretMetadataVersionsRoute extends Route { { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.backend, route: 'list', model: resolvedModel.backend }, ...breadcrumbsForSecret(resolvedModel.backend, resolvedModel.path), - { label: 'version history' }, + { label: 'Version History' }, ]; controller.set('breadcrumbs', breadcrumbsArray); diff --git a/ui/lib/kv/addon/routes/secret/paths.js b/ui/lib/kv/addon/routes/secret/paths.js index b822b514ada2..20689cd65b3a 100644 --- a/ui/lib/kv/addon/routes/secret/paths.js +++ b/ui/lib/kv/addon/routes/secret/paths.js @@ -14,7 +14,7 @@ export default class KvSecretPathsRoute extends Route { { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.backend, route: 'list', model: resolvedModel.backend }, ...breadcrumbsForSecret(resolvedModel.backend, resolvedModel.path), - { label: 'paths' }, + { label: 'Paths' }, ]; } } diff --git a/ui/lib/ldap/addon/routes/configuration.ts b/ui/lib/ldap/addon/routes/configuration.ts index 3e7e8bf91b1b..2f22f64a106a 100644 --- a/ui/lib/ldap/addon/routes/configuration.ts +++ b/ui/lib/ldap/addon/routes/configuration.ts @@ -51,7 +51,8 @@ export default class LdapConfigurationRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, - { label: resolvedModel.backendModel.id }, + { label: resolvedModel.backendModel.id, route: 'overview', model: resolvedModel.backend }, + { label: 'Configuration' }, ]; } } diff --git a/ui/lib/ldap/addon/routes/libraries/create.ts b/ui/lib/ldap/addon/routes/libraries/create.ts index 67c7775fb848..6da15c866940 100644 --- a/ui/lib/ldap/addon/routes/libraries/create.ts +++ b/ui/lib/ldap/addon/routes/libraries/create.ts @@ -36,8 +36,8 @@ export default class LdapLibrariesCreateRoute extends Route { controller.breadcrumbs = [ { label: resolvedModel.backend, route: 'overview' }, - { label: 'libraries', route: 'libraries' }, - { label: 'create' }, + { label: 'Libraries', route: 'libraries' }, + { label: 'Create' }, ]; } } diff --git a/ui/lib/ldap/addon/routes/libraries/index.ts b/ui/lib/ldap/addon/routes/libraries/index.ts index 3a967888ca55..8ea7c7b867d2 100644 --- a/ui/lib/ldap/addon/routes/libraries/index.ts +++ b/ui/lib/ldap/addon/routes/libraries/index.ts @@ -51,7 +51,8 @@ export default class LdapLibrariesRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, - { label: resolvedModel.backendModel.id }, + { label: resolvedModel.backendModel.id, route: 'overview', model: resolvedModel.backend }, + { label: 'Libraries' }, ]; } } diff --git a/ui/lib/ldap/addon/routes/roles/create.ts b/ui/lib/ldap/addon/routes/roles/create.ts index 4c10a0e83093..10eaa9cb5eb2 100644 --- a/ui/lib/ldap/addon/routes/roles/create.ts +++ b/ui/lib/ldap/addon/routes/roles/create.ts @@ -36,8 +36,8 @@ export default class LdapRolesCreateRoute extends Route { controller.breadcrumbs = [ { label: resolvedModel.backend, route: 'overview' }, - { label: 'roles', route: 'roles' }, - { label: 'create' }, + { label: 'Roles', route: 'roles' }, + { label: 'Create' }, ]; } } diff --git a/ui/lib/ldap/addon/routes/roles/index.ts b/ui/lib/ldap/addon/routes/roles/index.ts index d65c1719154c..962c48cf9b9f 100644 --- a/ui/lib/ldap/addon/routes/roles/index.ts +++ b/ui/lib/ldap/addon/routes/roles/index.ts @@ -76,7 +76,8 @@ export default class LdapRolesRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, - { label: resolvedModel.backendModel.id }, + { label: resolvedModel.backendModel.id, route: 'overview', model: resolvedModel.backend }, + { label: 'Roles' }, ]; } diff --git a/ui/lib/pki/addon/routes/certificates/certificate/details.js b/ui/lib/pki/addon/routes/certificates/certificate/details.js index 577ff63f2748..6a7f6cc65c1e 100644 --- a/ui/lib/pki/addon/routes/certificates/certificate/details.js +++ b/ui/lib/pki/addon/routes/certificates/certificate/details.js @@ -19,7 +19,7 @@ export default class PkiCertificateDetailsRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'certificates', route: 'certificates.index', model: this.secretMountPath.currentPath }, + { label: 'Certificates', route: 'certificates.index', model: this.secretMountPath.currentPath }, { label: model.id }, ]; } diff --git a/ui/lib/pki/addon/routes/configuration/create.js b/ui/lib/pki/addon/routes/configuration/create.js index 917d4976fe3b..2786f98580a1 100644 --- a/ui/lib/pki/addon/routes/configuration/create.js +++ b/ui/lib/pki/addon/routes/configuration/create.js @@ -25,7 +25,7 @@ export default class PkiConfigurationCreateRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'configure' }, + { label: 'Configure' }, ]; } } diff --git a/ui/lib/pki/addon/routes/configuration/edit.js b/ui/lib/pki/addon/routes/configuration/edit.js index e5981ce2f70b..789cb3db8945 100644 --- a/ui/lib/pki/addon/routes/configuration/edit.js +++ b/ui/lib/pki/addon/routes/configuration/edit.js @@ -27,8 +27,8 @@ export default class PkiConfigurationEditRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'configuration', route: 'configuration.index', model: this.secretMountPath.currentPath }, - { label: 'edit' }, + { label: 'Configuration', route: 'configuration.index', model: this.secretMountPath.currentPath }, + { label: 'Edit' }, ]; } } diff --git a/ui/lib/pki/addon/routes/issuers/generate-intermediate.js b/ui/lib/pki/addon/routes/issuers/generate-intermediate.js index c50636d66a95..863fd0234e50 100644 --- a/ui/lib/pki/addon/routes/issuers/generate-intermediate.js +++ b/ui/lib/pki/addon/routes/issuers/generate-intermediate.js @@ -21,8 +21,8 @@ export default class PkiIssuersGenerateIntermediateRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, - { label: 'generate CSR' }, + { label: 'Issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, + { label: 'Generate CSR' }, ]; } } diff --git a/ui/lib/pki/addon/routes/issuers/generate-root.js b/ui/lib/pki/addon/routes/issuers/generate-root.js index 57300776fd89..e45d2cf55f12 100644 --- a/ui/lib/pki/addon/routes/issuers/generate-root.js +++ b/ui/lib/pki/addon/routes/issuers/generate-root.js @@ -21,7 +21,7 @@ export default class PkiIssuersGenerateRootRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'generate root' }, + { label: 'Generate Root' }, ]; } } diff --git a/ui/lib/pki/addon/routes/issuers/import.js b/ui/lib/pki/addon/routes/issuers/import.js index 65612f4ea14d..74905f6c3610 100644 --- a/ui/lib/pki/addon/routes/issuers/import.js +++ b/ui/lib/pki/addon/routes/issuers/import.js @@ -21,8 +21,8 @@ export default class PkiIssuersImportRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, - { label: 'import' }, + { label: 'Issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, + { label: 'Import' }, ]; } } diff --git a/ui/lib/pki/addon/routes/issuers/index.js b/ui/lib/pki/addon/routes/issuers/index.js index 9d2089a1869d..c63804885093 100644 --- a/ui/lib/pki/addon/routes/issuers/index.js +++ b/ui/lib/pki/addon/routes/issuers/index.js @@ -37,7 +37,7 @@ export default class PkiIssuersListRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, + { label: 'Issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, ]; } diff --git a/ui/lib/pki/addon/routes/issuers/issuer.js b/ui/lib/pki/addon/routes/issuers/issuer.js index b928f994da99..6644ef40e965 100644 --- a/ui/lib/pki/addon/routes/issuers/issuer.js +++ b/ui/lib/pki/addon/routes/issuers/issuer.js @@ -23,7 +23,7 @@ export default class PkiIssuerIndexRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, + { label: 'Issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, ]; } } diff --git a/ui/lib/pki/addon/routes/issuers/issuer/cross-sign.js b/ui/lib/pki/addon/routes/issuers/issuer/cross-sign.js index fc72482cafab..b1da88b88167 100644 --- a/ui/lib/pki/addon/routes/issuers/issuer/cross-sign.js +++ b/ui/lib/pki/addon/routes/issuers/issuer/cross-sign.js @@ -22,13 +22,13 @@ export default class PkiIssuerCrossSignRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, + { label: 'Issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, { label: resolvedModel.id, route: 'issuers.issuer.details', models: [this.secretMountPath.currentPath, resolvedModel.id], }, - { label: 'cross-sign' }, + { label: 'Cross-sign' }, ]; } } diff --git a/ui/lib/pki/addon/routes/issuers/issuer/details.js b/ui/lib/pki/addon/routes/issuers/issuer/details.js index d4409d3760a9..ce260cb07bbb 100644 --- a/ui/lib/pki/addon/routes/issuers/issuer/details.js +++ b/ui/lib/pki/addon/routes/issuers/issuer/details.js @@ -28,7 +28,7 @@ export default class PkiIssuerDetailsRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: resolvedModel.backend }, - { label: 'issuers', route: 'issuers.index', model: resolvedModel.backend }, + { label: 'Issuers', route: 'issuers.index', model: resolvedModel.backend }, { label: resolvedModel.issuer.id }, ]; } diff --git a/ui/lib/pki/addon/routes/issuers/issuer/edit.js b/ui/lib/pki/addon/routes/issuers/issuer/edit.js index 5632fd80e88c..51d4b3207ed9 100644 --- a/ui/lib/pki/addon/routes/issuers/issuer/edit.js +++ b/ui/lib/pki/addon/routes/issuers/issuer/edit.js @@ -25,13 +25,13 @@ export default class PkiIssuerEditRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, + { label: 'Issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, { label: resolvedModel.id, route: 'issuers.issuer.details', models: [this.secretMountPath.currentPath, resolvedModel.id], }, - { label: 'update' }, + { label: 'Update' }, ]; } } diff --git a/ui/lib/pki/addon/routes/issuers/issuer/rotate-root.js b/ui/lib/pki/addon/routes/issuers/issuer/rotate-root.js index 24025f959da4..f25d06cdcf37 100644 --- a/ui/lib/pki/addon/routes/issuers/issuer/rotate-root.js +++ b/ui/lib/pki/addon/routes/issuers/issuer/rotate-root.js @@ -41,13 +41,13 @@ export default class PkiIssuerRotateRootRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: resolvedModel.oldRoot.backend }, - { label: 'issuers', route: 'issuers.index', model: resolvedModel.oldRoot.backend }, + { label: 'Issuers', route: 'issuers.index', model: resolvedModel.oldRoot.backend }, { label: resolvedModel.oldRoot.id, route: 'issuers.issuer.details', models: [resolvedModel.oldRoot.backend, resolvedModel.oldRoot.id], }, - { label: 'rotate root' }, + { label: 'Rotate Root' }, ]; } } diff --git a/ui/lib/pki/addon/routes/issuers/issuer/sign.js b/ui/lib/pki/addon/routes/issuers/issuer/sign.js index 7672037d8476..f2fd1884a7b2 100644 --- a/ui/lib/pki/addon/routes/issuers/issuer/sign.js +++ b/ui/lib/pki/addon/routes/issuers/issuer/sign.js @@ -21,13 +21,13 @@ export default class PkiIssuerSignRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, + { label: 'Issuers', route: 'issuers.index', model: this.secretMountPath.currentPath }, { label: resolvedModel.issuerRef, route: 'issuers.issuer.details', models: [this.secretMountPath.currentPath, resolvedModel.issuerRef], }, - { label: 'sign intermediate' }, + { label: 'Sign Intermediate' }, ]; } } diff --git a/ui/lib/pki/addon/routes/keys/create.js b/ui/lib/pki/addon/routes/keys/create.js index 3646a11ad471..a5cacd2ea95d 100644 --- a/ui/lib/pki/addon/routes/keys/create.js +++ b/ui/lib/pki/addon/routes/keys/create.js @@ -21,8 +21,8 @@ export default class PkiKeysCreateRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'keys', route: 'keys.index', model: this.secretMountPath.currentPath }, - { label: 'generate' }, + { label: 'Keys', route: 'keys.index', model: this.secretMountPath.currentPath }, + { label: 'Generate' }, ]; } } diff --git a/ui/lib/pki/addon/routes/keys/import.js b/ui/lib/pki/addon/routes/keys/import.js index b180f39b8c42..eb0154b9e759 100644 --- a/ui/lib/pki/addon/routes/keys/import.js +++ b/ui/lib/pki/addon/routes/keys/import.js @@ -21,8 +21,8 @@ export default class PkiKeysImportRoute extends Route { controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.secretMountPath.currentPath, route: 'overview', model: this.secretMountPath.currentPath }, - { label: 'keys', route: 'keys.index', model: this.secretMountPath.currentPath }, - { label: 'import' }, + { label: 'Keys', route: 'keys.index', model: this.secretMountPath.currentPath }, + { label: 'Import' }, ]; } } diff --git a/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-navigation-test.js b/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-navigation-test.js index 50efa15c9748..1adc273251c0 100644 --- a/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-navigation-test.js +++ b/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-navigation-test.js @@ -277,7 +277,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { `/vault/secrets/${backend}/kv/${secretPathUrlEncoded}/metadata`, `goes to metadata page` ); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath); assert .dom(`${PAGE.metadata.customMetadataSection} ${PAGE.emptyStateTitle}`) @@ -293,7 +293,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { `/vault/secrets/${backend}/kv/${secretPathUrlEncoded}/metadata/edit`, `goes to metadata edit page` ); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata', 'edit']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata', 'Edit']); await click(FORM.cancelBtn); assert.strictEqual( currentURL(), @@ -306,7 +306,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { const backend = this.backend; await navToBackend(backend); await click(PAGE.secretTab('Configuration')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'configuration']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'Configuration']); assert.dom(PAGE.title).hasText(`${backend} version 2`, 'correct page title for configuration'); await click(PAGE.secretTab('Secrets')); @@ -318,25 +318,25 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { assert.dom(PAGE.title).hasText(secretPath, 'correct page title for secret detail'); await click(PAGE.detail.createNewVersion); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'edit']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Edit']); assert.dom(PAGE.title).hasText('Create New Version', 'correct page title for secret edit'); await click(PAGE.breadcrumbAtIdx(2)); await click(PAGE.secretTab('Metadata')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for metadata'); await click(PAGE.metadata.editBtn); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata', 'edit']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata', 'Edit']); assert.dom(PAGE.title).hasText('Edit Secret Metadata', 'correct page title for metadata edit'); await click(PAGE.breadcrumbAtIdx(3)); await click(PAGE.secretTab('Paths')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'paths']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Paths']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for paths'); await click(PAGE.secretTab('Version History')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'version history']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Version History']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for version history'); }); }); @@ -477,7 +477,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { `/vault/secrets/${backend}/kv/${secretPathUrlEncoded}/metadata`, `goes to metadata page` ); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath); assert.dom(PAGE.toolbarAction).doesNotExist('no toolbar actions available on metadata'); assert @@ -493,7 +493,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { const backend = this.backend; await navToBackend(backend); await click(PAGE.secretTab('Configuration')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'configuration']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'Configuration']); assert.dom(PAGE.title).hasText(`${backend} version 2`, 'title correct on config page'); await click(PAGE.secretTab('Secrets')); @@ -508,13 +508,13 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { assert.dom(PAGE.detail.createNewVersion).doesNotExist('cannot create new version'); await click(PAGE.secretTab('Metadata')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'app', 'nested', 'secret', 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'app', 'nested', 'secret', 'Metadata']); assert.dom(PAGE.title).hasText('app/nested/secret', 'title correct on metadata'); assert.dom(PAGE.metadata.editBtn).doesNotExist('cannot edit metadata'); await click(PAGE.secretTab('Paths')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'app', 'nested', 'secret', 'paths']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'app', 'nested', 'secret', 'Paths']); assert.dom(PAGE.title).hasText('app/nested/secret', 'correct page title for paths'); assert.dom(PAGE.secretTab('Version History')).doesNotExist('Version History tab not shown'); @@ -650,7 +650,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { `/vault/secrets/${backend}/kv/${secretPathUrlEncoded}/metadata`, `goes to metadata page` ); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath); assert .dom(`${PAGE.metadata.customMetadataSection} ${PAGE.emptyStateTitle}`) @@ -666,7 +666,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { await navToBackend(backend); await click(PAGE.secretTab('Configuration')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'configuration']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'Configuration']); assert.dom(PAGE.title).hasText(`${backend} version 2`, 'correct page title for configuration'); await click(PAGE.secretTab('Secrets')); @@ -680,13 +680,13 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { assert.dom(PAGE.detail.createNewVersion).doesNotExist('cannot create new version'); await click(PAGE.secretTab('Metadata')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for metadata'); assert.dom(PAGE.metadata.editBtn).doesNotExist('cannot edit metadata'); await click(PAGE.secretTab('Paths')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'paths']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Paths']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for paths'); assert.dom(PAGE.secretTab('Version History')).doesNotExist('Version History tab not shown'); @@ -837,7 +837,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { `/vault/secrets/${backend}/kv/${secretPathUrlEncoded}/metadata`, `goes to metadata page` ); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath); assert .dom(`${PAGE.metadata.customMetadataSection} ${PAGE.emptyStateTitle}`) @@ -853,7 +853,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { `/vault/secrets/${backend}/kv/${secretPathUrlEncoded}/metadata/edit`, `goes to metadata edit page` ); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata', 'edit']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata', 'Edit']); await click(FORM.cancelBtn); assert.strictEqual( currentURL(), @@ -866,7 +866,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { const backend = this.backend; await navToBackend(backend); await click(PAGE.secretTab('Configuration')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'configuration']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'Configuration']); assert.dom(PAGE.title).hasText(`${backend} version 2`, 'correct page title for configuration'); await click(PAGE.secretTab('Secrets')); @@ -878,20 +878,20 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { assert.dom(PAGE.title).hasText(secretPath, 'correct page title for secret detail'); await click(PAGE.secretTab('Metadata')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for metadata'); await click(PAGE.metadata.editBtn); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata', 'edit']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata', 'Edit']); assert.dom(PAGE.title).hasText('Edit Secret Metadata', 'correct page title for metadata edit'); await click(PAGE.breadcrumbAtIdx(3)); await click(PAGE.secretTab('Paths')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'paths']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Paths']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for paths'); await click(PAGE.secretTab('Version History')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'version history']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Version History']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for version history'); }); }); @@ -1052,7 +1052,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { `/vault/secrets/${backend}/kv/${secretPathUrlEncoded}/metadata`, `goes to metadata page` ); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath); assert .dom(`${PAGE.metadata.customMetadataSection} ${PAGE.emptyStateTitle}`) @@ -1064,7 +1064,7 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { const backend = this.backend; await navToBackend(backend); await click(PAGE.secretTab('Configuration')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'configuration']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'Configuration']); assert.dom(PAGE.title).hasText(`${backend} version 2`, 'correct page title for configuration'); await click(PAGE.secretTab('Secrets')); @@ -1077,19 +1077,19 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) { assert.dom(PAGE.title).hasText(secretPath, 'correct page title for secret detail'); await click(PAGE.detail.createNewVersion); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'edit']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Edit']); assert.dom(PAGE.title).hasText('Create New Version', 'correct page title for secret edit'); await click(PAGE.breadcrumbAtIdx(2)); await click(PAGE.secretTab('Metadata')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for metadata'); assert.dom(PAGE.metadata.editBtn).doesNotExist('cannot edit metadata'); await click(PAGE.breadcrumbAtIdx(2)); await click(PAGE.secretTab('Paths')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'paths']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Paths']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for paths'); assert.dom(PAGE.secretTab('Version History')).doesNotExist('Version History tab not shown'); @@ -1197,7 +1197,7 @@ path "${this.backend}/*" { const backend = this.backend; await navToBackend(backend); await click(PAGE.secretTab('Configuration')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'configuration']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, 'Configuration']); assert.dom(PAGE.title).hasText(`${backend} version 2`, 'correct page title for configuration'); await click(PAGE.secretTab('Secrets')); @@ -1228,21 +1228,21 @@ path "${this.backend}/*" { assert.dom(PAGE.title).hasText(secretPath, 'correct page title for secret detail'); await click(PAGE.secretTab('Metadata')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'metadata']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Metadata']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for metadata'); assert.dom(PAGE.metadata.editBtn).doesNotExist('cannot edit metadata'); await click(PAGE.breadcrumbAtIdx(2)); await click(PAGE.secretTab('Paths')); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'paths']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Paths']); assert.dom(PAGE.title).hasText(secretPath, 'correct page title for paths'); assert.dom(PAGE.secretTab('Version History')).doesNotExist('Version History tab not shown'); await click(PAGE.secretTab('Secret')); await click(PAGE.detail.createNewVersion); - assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'edit']); + assertCorrectBreadcrumbs(assert, ['Secrets', backend, secretPath, 'Edit']); assert.dom(PAGE.title).hasText('Create New Version', 'correct page title for secret edit'); }); }); diff --git a/ui/tests/integration/components/kv/page/kv-page-metadata-edit-test.js b/ui/tests/integration/components/kv/page/kv-page-metadata-edit-test.js index 8a827d1519d9..6cef2ea9f337 100644 --- a/ui/tests/integration/components/kv/page/kv-page-metadata-edit-test.js +++ b/ui/tests/integration/components/kv/page/kv-page-metadata-edit-test.js @@ -44,7 +44,7 @@ module('Integration | Component | kv | Page::Secret::Metadata::Edit', function ( { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.metadataModelCreate.backend, route: 'list' }, { label: this.metadataModelCreate.path, route: 'secret.details', model: this.metadataModelCreate.path }, - { label: 'metadata' }, + { label: 'Metadata' }, ]; await render( hbs` @@ -74,7 +74,7 @@ module('Integration | Component | kv | Page::Secret::Metadata::Edit', function ( { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.metadataModelEdit.backend, route: 'list' }, { label: this.metadataModelEdit.path, route: 'secret.details', model: this.metadataModelEdit.path }, - { label: 'metadata' }, + { label: 'Metadata' }, ]; await render( hbs` @@ -131,7 +131,7 @@ module('Integration | Component | kv | Page::Secret::Metadata::Edit', function ( { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.metadataModelEdit.backend, route: 'list' }, { label: this.metadataModelEdit.path, route: 'secret.details', model: this.metadataModelEdit.path }, - { label: 'metadata' }, + { label: 'Metadata' }, ]; await render( hbs` @@ -162,7 +162,7 @@ module('Integration | Component | kv | Page::Secret::Metadata::Edit', function ( { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.metadataModelEdit.backend, route: 'list' }, { label: this.metadataModelEdit.path, route: 'secret.details', model: this.metadataModelEdit.path }, - { label: 'metadata' }, + { label: 'Metadata' }, ]; await render( hbs` diff --git a/ui/tests/integration/components/kv/page/kv-page-version-diff-test.js b/ui/tests/integration/components/kv/page/kv-page-version-diff-test.js index 31017a635e68..981a2ff1993f 100644 --- a/ui/tests/integration/components/kv/page/kv-page-version-diff-test.js +++ b/ui/tests/integration/components/kv/page/kv-page-version-diff-test.js @@ -21,7 +21,7 @@ module('Integration | Component | kv | Page::Secret::Metadata::VersionDiff', fun hooks.beforeEach(async function () { this.backend = 'kv-engine'; this.path = 'my-secret'; - this.breadcrumbs = [{ label: 'version history', route: 'secret.metadata.versions' }, { label: 'diff' }]; + this.breadcrumbs = [{ label: 'Version History', route: 'secret.metadata.versions' }, { label: 'Diff' }]; this.store = this.owner.lookup('service:store'); this.server.post('/sys/capabilities-self', allowAllCapabilitiesStub()); diff --git a/ui/tests/integration/components/kv/page/kv-page-version-history-test.js b/ui/tests/integration/components/kv/page/kv-page-version-history-test.js index 0bfd727b411f..2ccf91c86143 100644 --- a/ui/tests/integration/components/kv/page/kv-page-version-history-test.js +++ b/ui/tests/integration/components/kv/page/kv-page-version-history-test.js @@ -39,7 +39,7 @@ module('Integration | Component | kv | Page::Secret::Metadata::Version-History', { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: this.metadata.backend, route: 'list' }, { label: this.metadata.path, route: 'secret.details', model: this.metadata.path }, - { label: 'version history' }, + { label: 'Version History' }, ]; }); diff --git a/ui/tests/integration/components/ldap/page/library/create-and-edit-test.js b/ui/tests/integration/components/ldap/page/library/create-and-edit-test.js index 28e1e5af0d50..5a852b953aa2 100644 --- a/ui/tests/integration/components/ldap/page/library/create-and-edit-test.js +++ b/ui/tests/integration/components/ldap/page/library/create-and-edit-test.js @@ -37,8 +37,8 @@ module('Integration | Component | ldap | Page::Library::CreateAndEdit', function this.breadcrumbs = [ { label: 'ldap', route: 'overview' }, - { label: 'libraries', route: 'libraries' }, - { label: 'create' }, + { label: 'Libraries', route: 'libraries' }, + { label: 'Create' }, ]; this.renderComponent = () => { diff --git a/ui/tests/integration/components/ldap/page/role/create-and-edit-test.js b/ui/tests/integration/components/ldap/page/role/create-and-edit-test.js index 1e4620339a46..3391147f2559 100644 --- a/ui/tests/integration/components/ldap/page/role/create-and-edit-test.js +++ b/ui/tests/integration/components/ldap/page/role/create-and-edit-test.js @@ -40,8 +40,8 @@ module('Integration | Component | ldap | Page::Role::CreateAndEdit', function (h this.breadcrumbs = [ { label: 'ldap', route: 'overview' }, - { label: 'roles', route: 'roles' }, - { label: 'create' }, + { label: 'Roles', route: 'roles' }, + { label: 'Create' }, ]; this.renderComponent = () => { diff --git a/vault/activity_log.go b/vault/activity_log.go index 2931a37320e1..b7dc6ea470ce 100644 --- a/vault/activity_log.go +++ b/vault/activity_log.go @@ -2779,11 +2779,11 @@ func (a *ActivityLog) prepareMonthsResponseForQuery(ctx context.Context, byMonth for _, monthsRecord := range byMonth { newClientsResponse := &ResponseNewClients{} if monthsRecord.NewClients.Counts.HasCounts() { - newClientsNSResponse, err := a.prepareNamespaceResponse(ctx, monthsRecord.NewClients.Namespaces) + newClientsTotal, newClientsNSResponse, err := a.prepareNamespaceResponse(ctx, monthsRecord.NewClients.Namespaces) if err != nil { return nil, err } - newClientsResponse.Counts = a.countsRecordToCountsResponse(monthsRecord.NewClients.Counts, false) + newClientsResponse.Counts = newClientsTotal newClientsResponse.Namespaces = newClientsNSResponse } @@ -2791,11 +2791,11 @@ func (a *ActivityLog) prepareMonthsResponseForQuery(ctx context.Context, byMonth Timestamp: time.Unix(monthsRecord.Timestamp, 0).UTC().Format(time.RFC3339), } if monthsRecord.Counts.HasCounts() { - nsResponse, err := a.prepareNamespaceResponse(ctx, monthsRecord.Namespaces) + monthTotal, nsResponse, err := a.prepareNamespaceResponse(ctx, monthsRecord.Namespaces) if err != nil { return nil, err } - monthResponse.Counts = a.countsRecordToCountsResponse(monthsRecord.Counts, false) + monthResponse.Counts = monthTotal monthResponse.Namespaces = nsResponse monthResponse.NewClients = newClientsResponse months = append(months, monthResponse) @@ -2804,14 +2804,16 @@ func (a *ActivityLog) prepareMonthsResponseForQuery(ctx context.Context, byMonth return months, nil } -// prepareNamespaceResponse populates the namespace portion of the activity log response struct -// from -func (a *ActivityLog) prepareNamespaceResponse(ctx context.Context, nsRecords []*activity.MonthlyNamespaceRecord) ([]*ResponseNamespace, error) { +// prepareNamespaceResponse takes monthly namespace records and converts them +// into the response namespace format. The function also returns counts for the +// total number of clients per type seen that month. +func (a *ActivityLog) prepareNamespaceResponse(ctx context.Context, nsRecords []*activity.MonthlyNamespaceRecord) (*ResponseCounts, []*ResponseNamespace, error) { queryNS, err := namespace.FromContext(ctx) if err != nil { - return nil, err + return nil, nil, err } - nsResponse := make([]*ResponseNamespace, 0, len(nsRecords)) + totalCounts := &ResponseCounts{} + nsResponses := make([]*ResponseNamespace, 0, len(nsRecords)) for _, nsRecord := range nsRecords { if !nsRecord.Counts.HasCounts() { continue @@ -2819,7 +2821,7 @@ func (a *ActivityLog) prepareNamespaceResponse(ctx context.Context, nsRecords [] ns, err := NamespaceByID(ctx, nsRecord.NamespaceID, a.core) if err != nil { - return nil, err + return nil, nil, err } if a.includeInResponse(queryNS, ns) { mountResponse := make([]*ResponseMount, 0, len(nsRecord.Mounts)) @@ -2840,15 +2842,18 @@ func (a *ActivityLog) prepareNamespaceResponse(ctx context.Context, nsRecords [] } else { displayPath = ns.Path } - nsResponse = append(nsResponse, &ResponseNamespace{ + nsResponse := &ResponseNamespace{ NamespaceID: nsRecord.NamespaceID, NamespacePath: displayPath, Counts: *a.countsRecordToCountsResponse(nsRecord.Counts, false), Mounts: mountResponse, - }) + } + nsResponses = append(nsResponses, nsResponse) + + totalCounts.Add(&nsResponse.Counts) } } - return nsResponse, nil + return totalCounts, nsResponses, nil } // partialMonthClientCount returns the number of clients used so far this month. diff --git a/vault/census.go b/vault/census.go index fc1cf2b10851..3481adacd22e 100644 --- a/vault/census.go +++ b/vault/census.go @@ -5,12 +5,16 @@ package vault -import "time" +import ( + "context" + "time" +) + +const utilizationBasePath = "utilization" // CensusAgent is a stub for OSS type CensusReporter interface{} -func (c *Core) setupCensusManager() error { return nil } func (c *Core) BillingStart() time.Time { return time.Time{} } func (c *Core) AutomatedLicenseReportingEnabled() bool { return false } func (c *Core) CensusAgent() CensusReporter { return nil } @@ -19,3 +23,9 @@ func (c *Core) StartManualCensusSnapshots() {} func (c *Core) ManualLicenseReportingEnabled() bool { return false } func (c *Core) ManualCensusSnapshotInterval() time.Duration { return time.Duration(0) } func (c *Core) ManualCensusSnapshotRetentionTime() time.Duration { return time.Duration(0) } +func (c *Core) StartCensusReports(ctx context.Context) {} +func (c *Core) SetRetentionMonths(months int) error { return nil } +func (c *Core) ReloadCensusManager(licenseChange bool) error { return nil } +func (c *Core) parseCensusManagerConfig(conf *CoreConfig) (CensusManagerConfig, error) { + return CensusManagerConfig{}, nil +} diff --git a/vault/census_manager.go b/vault/census_manager.go new file mode 100644 index 000000000000..3a98f47b2079 --- /dev/null +++ b/vault/census_manager.go @@ -0,0 +1,42 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +//go:build !enterprise + +package vault + +import ( + "context" + "time" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/logical" +) + +// CensusManager provides stub behavior for CE, simplifying the logic between CE +// and ENT. This will always be marked active: false. +type CensusManager struct { + active bool + logger hclog.Logger +} + +// CensusManagerConfig is empty on CE. +type CensusManagerConfig struct{} + +// NewCensusManager sets up the stub CensusManager on CE with active: false. +func NewCensusManager(logger hclog.Logger, conf CensusManagerConfig, storage logical.Storage) (*CensusManager, error) { + return &CensusManager{ + active: false, + logger: logger, + }, nil +} + +// setupCensusManager is a stub on CE. +func (c *Core) setupCensusManager(ctx context.Context) error { + return nil +} + +// BillingStart is a stub on CE. +func (cm *CensusManager) BillingStart() time.Time { + return time.Time{} +} diff --git a/vault/census_stubs_oss.go b/vault/census_stubs_oss.go deleted file mode 100644 index f52717a5c91e..000000000000 --- a/vault/census_stubs_oss.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -//go:build !enterprise - -package vault - -import "context" - -//go:generate go run github.com/hashicorp/vault/tools/stubmaker - -func (c *Core) StartCensusReports(ctx context.Context) {} -func (c *Core) SetRetentionMonths(months int) error { return nil } -func (c *Core) ReloadCensusManager(licenseChange bool) error { return nil } diff --git a/vault/core.go b/vault/core.go index 4e9518cc1518..21145f6a3b4b 100644 --- a/vault/core.go +++ b/vault/core.go @@ -727,6 +727,8 @@ type Core struct { periodicLeaderRefreshInterval time.Duration clusterAddrBridge *raft.ClusterAddrBridge + + censusManager *CensusManager } func (c *Core) ActiveNodeClockSkewMillis() int64 { @@ -1316,6 +1318,19 @@ func NewCore(conf *CoreConfig) (*Core, error) { c.versionHistory = make(map[string]VaultVersion) } + // Setup the Census Manager + cmConfig, err := c.parseCensusManagerConfig(conf) + if err != nil { + return nil, err + } + + cmLogger := conf.Logger.Named("reporting") + c.allLoggers = append(c.allLoggers, cmLogger) + c.censusManager, err = NewCensusManager(cmLogger, cmConfig, NewBarrierView(c.barrier, utilizationBasePath)) + if err != nil { + return nil, err + } + // Events eventsLogger := conf.Logger.Named("events") c.allLoggers = append(c.allLoggers, eventsLogger) @@ -2449,15 +2464,16 @@ func (s standardUnsealStrategy) unseal(ctx context.Context, logger log.Logger, c return err } - if err := c.setupCensusManager(); err != nil { - logger.Error("failed to instantiate the license reporting agent", "error", err) + if err := c.setupCensusManager(ctx); err != nil { + return err } c.StartCensusReports(ctx) c.StartManualCensusSnapshots() } else { - broker, err := audit.NewBroker(logger) + brokerLogger := logger.Named("audit") + broker, err := audit.NewBroker(brokerLogger) if err != nil { return err } diff --git a/vault/eventbus/bus.go b/vault/eventbus/bus.go index b45839f1ac0b..8f8b174a5245 100644 --- a/vault/eventbus/bus.go +++ b/vault/eventbus/bus.go @@ -237,6 +237,9 @@ func (bus *EventBus) subscribeInternal(ctx context.Context, namespacePathPattern var filterNode *eventlogger.Filter if cluster != nil { filterNode, err = newClusterFilterNode(bus.filters, clusterID(*cluster)) + if err != nil { + return nil, nil, err + } } else { filterNode, err = newFilterNode(namespacePathPatterns, pattern, bexprFilter) if err != nil { diff --git a/vault/external_tests/plugin/external_plugin_test.go b/vault/external_tests/plugin/external_plugin_test.go index d2a73a51d3f2..9f8152190153 100644 --- a/vault/external_tests/plugin/external_plugin_test.go +++ b/vault/external_tests/plugin/external_plugin_test.go @@ -696,7 +696,7 @@ func TestExternalPlugin_Database(t *testing.T) { t.Run(dbName, func(t *testing.T) { roleName := "test-role-" + dbName - cleanupContainer, connURL := postgreshelper.PrepareTestContainerWithVaultUser(t, context.Background(), "13.4-buster") + cleanupContainer, connURL := postgreshelper.PrepareTestContainerWithVaultUser(t, context.Background()) t.Cleanup(cleanupContainer) _, err := client.Logical().Write("database/config/"+dbName, map[string]interface{}{ @@ -819,7 +819,7 @@ func TestExternalPlugin_DatabaseReload(t *testing.T) { dbName := fmt.Sprintf("%s-%d", plugin.Name, 0) roleName := "test-role-" + dbName - cleanupContainer, connURL := postgreshelper.PrepareTestContainerWithVaultUser(t, context.Background(), "13.4-buster") + cleanupContainer, connURL := postgreshelper.PrepareTestContainerWithVaultUser(t, context.Background()) t.Cleanup(cleanupContainer) _, err := client.Logical().Write("database/config/"+dbName, map[string]interface{}{ @@ -1204,7 +1204,7 @@ func TestCore_UpgradePluginUsingPinnedVersion_Database(t *testing.T) { t.Fatal(err) } - cleanupPG, connURL := postgreshelper.PrepareTestContainerWithVaultUser(t, context.Background(), "13.4-buster") + cleanupPG, connURL := postgreshelper.PrepareTestContainerWithVaultUser(t, context.Background()) t.Cleanup(cleanupPG) // Mount 1.0.0 then pin to 1.0.1 diff --git a/website/content/api-docs/index.mdx b/website/content/api-docs/index.mdx index 26b532ca6d43..a5a4166387df 100644 --- a/website/content/api-docs/index.mdx +++ b/website/content/api-docs/index.mdx @@ -54,6 +54,8 @@ in periods. Otherwise, Vault will return a 404 unsupported path error. ## Namespaces +@include 'alerts/enterprise-and-hcp.mdx' + When using [Namespaces](/vault/docs/enterprise/namespaces) the final path of the API request is relative to the `X-Vault-Namespace` header. For instance, if a request URI is `secret/foo` with the `X-Vault-Namespace` header set as `ns1/ns2/`, @@ -83,6 +85,19 @@ $ curl \ http://127.0.0.1:8200/v1/ns1/ns2/secret/foo ``` + + +When you are working with HCP Vault Dedicated, your request must specify the +target namespace. In absence of an explicit namespace, Vault tries to send +the request to `root` namespace which results in an error. + +The top-level namespace for HCP Vault Dedicated clusters is `admin`, so the +requests must include `-H "X-Vault-Namespace: admin"` header or `admin` in the +API endpoint path. + + + + ## API operations Typically the request data, body and response data to and from Vault is in JSON. diff --git a/website/content/docs/agent-and-proxy/proxy/caching/static-secret-caching.mdx b/website/content/docs/agent-and-proxy/proxy/caching/static-secret-caching.mdx index ed4385824cbd..3f7b0417facd 100644 --- a/website/content/docs/agent-and-proxy/proxy/caching/static-secret-caching.mdx +++ b/website/content/docs/agent-and-proxy/proxy/caching/static-secret-caching.mdx @@ -146,7 +146,7 @@ the cache or forwarded from Vault. In the event of a hit, Proxy also sets the The top level `cache` block has the following configuration entries relating to static secret caching: - `cache_static_secrets` `(bool: false)` - Enables static secret caching when -set to `true`. When `cache_static_secrets` and `auth_auth` are both enabled, +set to `true`. When `cache_static_secrets` and `auto_auth` are both enabled, Vault Proxy serves KV secrets directly from the cache to clients with sufficient permission. diff --git a/website/content/docs/concepts/policies.mdx b/website/content/docs/concepts/policies.mdx index f01b0bf8b8bf..6c9bd3d1143c 100644 --- a/website/content/docs/concepts/policies.mdx +++ b/website/content/docs/concepts/policies.mdx @@ -193,6 +193,11 @@ wildcard appears in the same place, both end in `*` and the latter has two wildc segments while the former has zero. So we end at rule (3), and give `"secret/+/+/foo/*"` _lower_ priority. +Another example utilizing Vault [namespaces](/vault/docs/enterprise/namespaces), given [nested](/vault/tutorials/enterprise/namespace-structure) namespaces `ns1/ns2/ns3` and two paths, +`"secret/*"` and `"ns1/ns2/ns3/secret/apps/*"` where `secret` is a mountpoint in namespace `ns3`. The first path is +defined in a policy inside/relative to namespace `ns3` while the second path is defined in a policy in the `root` namespace. +Both paths end in `*` but the first is shorter. So we end at rule (4), and give `"secret/*"` _lower_ priority. + !> **Informational:**The glob character referred to in this documentation is the asterisk (`*`). It _is not a regular expression_ and is only supported **as the last character of the path**! diff --git a/website/content/docs/configuration/service-registration/kubernetes.mdx b/website/content/docs/configuration/service-registration/kubernetes.mdx index 2e7af4a47079..14728f9a476e 100644 --- a/website/content/docs/configuration/service-registration/kubernetes.mdx +++ b/website/content/docs/configuration/service-registration/kubernetes.mdx @@ -71,7 +71,7 @@ metadata: vault-initialized: "true" vault-perf-standby: "false" vault-sealed: "false" - vault-version: 1.16.1 + vault-version: 1.17.2 ``` After shutdowns, Vault pods will bear the following labels: @@ -86,7 +86,7 @@ metadata: vault-initialized: "false" vault-perf-standby: "false" vault-sealed: "true" - vault-version: 1.16.1 + vault-version: 1.17.2 ``` ## Label definitions @@ -102,7 +102,7 @@ metadata: - `vault-sealed` `(string: "true"/"false")` – Vault sealed is updated dynamically each time Vault's sealed/unsealed status changes. True indicates that Vault is currently sealed. False indicates that Vault is currently unsealed. -- `vault-version` `(string: "1.16.1")` – Vault version is a string that will not change during a pod's lifecycle. +- `vault-version` `(string: "1.17.2")` – Vault version is a string that will not change during a pod's lifecycle. ## Working with vault's service discovery labels @@ -118,7 +118,7 @@ metadata: labels: app.kubernetes.io/instance: vault app.kubernetes.io/name: vault - helm.sh/chart: vault-0.1.2 + helm.sh/chart: vault-0.28.1 name: vault-active-us-east namespace: default spec: @@ -156,7 +156,7 @@ $ vault write -f sys/replication/performance/primary/enable \ In conjunction with the pod labels and the `OnDelete` upgrade strategy, upgrades are much easier to orchestrate: ```shell-session -$ helm upgrade vault --set='server.image.tag=1.16.1' +$ helm upgrade vault --set='server.image.tag=1.17.2' $ kubectl delete pod --selector=vault-active=false \ --selector=vault-version=1.2.3 diff --git a/website/content/docs/platform/k8s/helm/configuration.mdx b/website/content/docs/platform/k8s/helm/configuration.mdx index ecf71217da27..beeb08a763fb 100644 --- a/website/content/docs/platform/k8s/helm/configuration.mdx +++ b/website/content/docs/platform/k8s/helm/configuration.mdx @@ -79,7 +79,7 @@ and consider if they're appropriate for your deployment. - `repository` (`string: "hashicorp/vault-k8s"`) - The name of the Docker image for Vault Agent Injector. - - `tag` (`string: "1.4.1"`) - The tag of the Docker image for the Vault Agent Injector. **This should be pinned to a specific version when running in production.** Otherwise, other changes to the chart may inadvertently upgrade your admission controller. + - `tag` (`string: "1.4.2"`) - The tag of the Docker image for the Vault Agent Injector. **This should be pinned to a specific version when running in production.** Otherwise, other changes to the chart may inadvertently upgrade your admission controller. - `pullPolicy` (`string: "IfNotPresent"`) - The pull policy for container images. The default pull policy is `IfNotPresent` which causes the Kubelet to skip pulling an image if it already exists. @@ -87,7 +87,7 @@ and consider if they're appropriate for your deployment. - `repository` (`string: "hashicorp/vault"`) - The name of the Docker image for the Vault Agent sidecar. This should be set to the official Vault Docker image. - - `tag` (`string: "1.16.1"`) - The tag of the Vault Docker image to use for the Vault Agent Sidecar. **Vault 1.3.1+ is required by the admission controller**. + - `tag` (`string: "1.17.2"`) - The tag of the Vault Docker image to use for the Vault Agent Sidecar. **Vault 1.3.1+ is required by the admission controller**. - `agentDefaults` - Values that configure the injected Vault Agent containers default values. @@ -351,7 +351,7 @@ and consider if they're appropriate for your deployment. - `repository` (`string: "hashicorp/vault"`) - The name of the Docker image for the containers running Vault. - - `tag` (`string: "1.16.1"`) - The tag of the Docker image for the containers running Vault. **This should be pinned to a specific version when running in production.** Otherwise, other changes to the chart may inadvertently upgrade your admission controller. + - `tag` (`string: "1.17.2"`) - The tag of the Docker image for the containers running Vault. **This should be pinned to a specific version when running in production.** Otherwise, other changes to the chart may inadvertently upgrade your admission controller. - `pullPolicy` (`string: "IfNotPresent"`) - The pull policy for container images. The default pull policy is `IfNotPresent` which causes the Kubelet to skip pulling an image if it already exists. @@ -724,7 +724,7 @@ and consider if they're appropriate for your deployment. "sample/annotation2": "bar" ``` - - `configAnnotation` (`boolean: false`) - Add an annotation to the server configmap and the statefulset pods, `vaultproject.io/config-checksum`, that is a hash of the Vault configuration. This can be used together with an OnDelete deployment strategy to help identify which pods still need to be deleted during a deployment to pick up any configuration changes. + - `includeConfigAnnotation` (`boolean: false`) - Add an annotation to the server configmap and the statefulset pods, `vaultproject.io/config-checksum`, that is a hash of the Vault configuration. This can be used together with an OnDelete deployment strategy to help identify which pods still need to be deleted during a deployment to pick up any configuration changes. - `service` - Values that configure the Kubernetes service created for Vault. These options are also used for the `active` and `standby` services when [`ha`](#ha) is enabled. @@ -1090,7 +1090,7 @@ and consider if they're appropriate for your deployment. - `repository` (`string: "hashicorp/vault-csi-provider"`) - The name of the Docker image for the Vault CSI Provider. - - `tag` (`string: "1.4.2"`) - The tag of the Docker image for the Vault CSI Provider.. **This should be pinned to a specific version when running in production.** Otherwise, other changes to the chart may inadvertently upgrade your CSI provider. + - `tag` (`string: "1.4.3"`) - The tag of the Docker image for the Vault CSI Provider.. **This should be pinned to a specific version when running in production.** Otherwise, other changes to the chart may inadvertently upgrade your CSI provider. - `pullPolicy` (`string: "IfNotPresent"`) - The pull policy for container images. The default pull policy is `IfNotPresent` which causes the Kubelet to skip pulling an image if it already exists locally. @@ -1239,7 +1239,7 @@ and consider if they're appropriate for your deployment. - `repository` (`string: "hashicorp/vault"`) - The name of the Docker image for the Vault Agent sidecar. This should be set to the official Vault Docker image. - - `tag` (`string: "1.16.1"`) - The tag of the Vault Docker image to use for the Vault Agent Sidecar. + - `tag` (`string: "1.17.2"`) - The tag of the Vault Docker image to use for the Vault Agent Sidecar. - `logFormat` (`string: "standard"`) - - `logLevel` (`string: "info"`) - @@ -1258,7 +1258,9 @@ and consider if they're appropriate for your deployment. the `telemetry {}` stanza in the Vault configuration. See the [telemetry](/vault/docs/configuration/telemetry) [docs](/vault/docs/internals/telemetry) for more on the Vault configuration. - Currently, this chart does not support authenticating to Vault's metrics endpoint, so the following `telemetry {}` block must be included in the `listener "tcp" {}` stanza of the Vault configuration: + If authorization is not set for authenticating to Vault's metrics endpoint, + the following Vault server `telemetry{}` config must be included in the + `listener "tcp"{}` stanza of the Vault configuration: ```yaml listener "tcp" { @@ -1299,6 +1301,31 @@ and consider if they're appropriate for your deployment. - `scrapeTimeout` (`string: "10s"`) - Timeout for Prometheus scrapes. + - `tlsConfig` (`dictionary: {}`) - tlsConfig used for scraping the Vault metrics API. See the + prometheus [API + reference](https://prometheus-operator.dev/docs/api-reference/api/#monitoring.coreos.com/v1.TLSConfig) + for more details. + + ```yaml + tlsConfig: + ca: + secret: + name: vault-metrics-client + key: ca.crt + ``` + + - `authorization` (`dictionary: {}`) - Authorization used for scraping the Vault metrics API. + See the prometheus [API + reference](https://prometheus-operator.dev/docs/api-reference/api/#monitoring.coreos.com/v1.SafeAuthorization) + for more details. + + ```yaml + authorization: + credentials: + name: vault-metrics-client + key: token + ``` + - `prometheusRules` - Values that configure Prometheus rules. - `enabled` (`boolean: false`) - Deploy the PrometheusRule custom resource for AlertManager-based diff --git a/website/content/docs/platform/k8s/helm/enterprise.mdx b/website/content/docs/platform/k8s/helm/enterprise.mdx index 0cb478a1fe18..cd2520c9d327 100644 --- a/website/content/docs/platform/k8s/helm/enterprise.mdx +++ b/website/content/docs/platform/k8s/helm/enterprise.mdx @@ -33,7 +33,7 @@ In your chart overrides, set the values of [`server.image`](/vault/docs/platform server: image: repository: hashicorp/vault-enterprise - tag: 1.16.1-ent + tag: 1.17.2-ent enterpriseLicense: secretName: vault-ent-license ``` diff --git a/website/content/docs/platform/k8s/helm/examples/enterprise-dr-with-raft.mdx b/website/content/docs/platform/k8s/helm/examples/enterprise-dr-with-raft.mdx index 31aad1145aae..256a687e8b9c 100644 --- a/website/content/docs/platform/k8s/helm/examples/enterprise-dr-with-raft.mdx +++ b/website/content/docs/platform/k8s/helm/examples/enterprise-dr-with-raft.mdx @@ -23,7 +23,7 @@ First, create the primary cluster: ```shell helm install vault-primary hashicorp/vault \ --set='server.image.repository=hashicorp/vault-enterprise' \ - --set='server.image.tag=1.16.1-ent' \ + --set='server.image.tag=1.17.2-ent' \ --set='server.ha.enabled=true' \ --set='server.ha.raft.enabled=true' ``` @@ -75,7 +75,7 @@ disaster recovery replication. ```shell helm install vault-secondary hashicorp/vault \ --set='server.image.repository=hashicorp/vault-enterprise' \ - --set='server.image.tag=1.16.1-ent' \ + --set='server.image.tag=1.17.2-ent' \ --set='server.ha.enabled=true' \ --set='server.ha.raft.enabled=true' ``` diff --git a/website/content/docs/platform/k8s/helm/examples/enterprise-perf-with-raft.mdx b/website/content/docs/platform/k8s/helm/examples/enterprise-perf-with-raft.mdx index 5acd396fe001..78b49ad36526 100644 --- a/website/content/docs/platform/k8s/helm/examples/enterprise-perf-with-raft.mdx +++ b/website/content/docs/platform/k8s/helm/examples/enterprise-perf-with-raft.mdx @@ -23,7 +23,7 @@ First, create the primary cluster: ```shell helm install vault-primary hashicorp/vault \ --set='server.image.repository=hashicorp/vault-enterprise' \ - --set='server.image.tag=1.16.1-ent' \ + --set='server.image.tag=1.17.2-ent' \ --set='server.ha.enabled=true' \ --set='server.ha.raft.enabled=true' ``` @@ -74,7 +74,7 @@ With the primary cluster created, next create a secondary cluster. ```shell helm install vault-secondary hashicorp/vault \ --set='server.image.repository=hashicorp/vault-enterprise' \ - --set='server.image.tag=1.16.1-ent' \ + --set='server.image.tag=1.17.2-ent' \ --set='server.ha.enabled=true' \ --set='server.ha.raft.enabled=true' ``` diff --git a/website/content/docs/platform/k8s/helm/examples/enterprise-with-raft.mdx b/website/content/docs/platform/k8s/helm/examples/enterprise-with-raft.mdx index c6e3440043a0..fa84279e1621 100644 --- a/website/content/docs/platform/k8s/helm/examples/enterprise-with-raft.mdx +++ b/website/content/docs/platform/k8s/helm/examples/enterprise-with-raft.mdx @@ -15,7 +15,7 @@ Integrated Storage (raft) can be enabled using the `server.ha.raft.enabled` valu ```shell helm install vault hashicorp/vault \ --set='server.image.repository=hashicorp/vault-enterprise' \ - --set='server.image.tag=1.16.1-ent' \ + --set='server.image.tag=1.17.2-ent' \ --set='server.ha.enabled=true' \ --set='server.ha.raft.enabled=true' ``` diff --git a/website/content/docs/platform/k8s/helm/run.mdx b/website/content/docs/platform/k8s/helm/run.mdx index 49cd15362954..95184caaf18b 100644 --- a/website/content/docs/platform/k8s/helm/run.mdx +++ b/website/content/docs/platform/k8s/helm/run.mdx @@ -409,14 +409,14 @@ Next, list the Helm versions and choose the desired version to install. ```bash $ helm search repo hashicorp/vault NAME CHART VERSION APP VERSION DESCRIPTION -hashicorp/vault 0.28.0 1.16.1 Official HashiCorp Vault Chart +hashicorp/vault 0.28.1 1.17.2 Official HashiCorp Vault Chart ``` Next, test the upgrade with `--dry-run` first to verify the changes sent to the Kubernetes cluster. ```shell-session -$ helm upgrade vault hashicorp/vault --version=0.28.0 \ +$ helm upgrade vault hashicorp/vault --version=0.28.1 \ --set='server.image.repository=vault' \ --set='server.image.tag=123.456' \ --dry-run diff --git a/website/content/docs/platform/k8s/injector/annotations.mdx b/website/content/docs/platform/k8s/injector/annotations.mdx index 5e5514905222..1be2e3f577f7 100644 --- a/website/content/docs/platform/k8s/injector/annotations.mdx +++ b/website/content/docs/platform/k8s/injector/annotations.mdx @@ -28,7 +28,7 @@ them, optional commands to run, etc. - `vault.hashicorp.com/agent-image` - name of the Vault docker image to use. This value overrides the default image configured in the injector and is usually - not needed. Defaults to `hashicorp/vault:1.16.1`. + not needed. Defaults to `hashicorp/vault:1.17.2`. - `vault.hashicorp.com/agent-init-first` - configures the pod to run the Vault Agent init container first if `true` (last if `false`). This is useful when other init diff --git a/website/content/docs/platform/k8s/vso/api-reference.mdx b/website/content/docs/platform/k8s/vso/api-reference.mdx index cb2ccf98eb10..96c839c6bb8b 100644 --- a/website/content/docs/platform/k8s/vso/api-reference.mdx +++ b/website/content/docs/platform/k8s/vso/api-reference.mdx @@ -7,7 +7,7 @@ description: >- # API Reference @@ -27,6 +27,8 @@ Package v1beta1 contains API Schema definitions for the secrets v1beta1 API grou - [SecretTransformation](#secrettransformation) - [SecretTransformationList](#secrettransformationlist) - [VaultAuth](#vaultauth) +- [VaultAuthGlobal](#vaultauthglobal) +- [VaultAuthGlobalList](#vaultauthgloballist) - [VaultAuthList](#vaultauthlist) - [VaultConnection](#vaultconnection) - [VaultConnectionList](#vaultconnectionlist) @@ -200,6 +202,25 @@ _Appears in:_ +#### MergeStrategy + + + +MergeStrategy provides the configuration for merging HTTP headers and +parameters from the referring VaultAuth resource and its VaultAuthGlobal +resource. + + + +_Appears in:_ +- [VaultAuthGlobalRef](#vaultauthglobalref) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `headers` _string_ | Headers configures the merge strategy for HTTP headers that are included in
all Vault requests. Choices are `union`, `replace`, or `none`.

If `union` is set, the headers from the VaultAuthGlobal and VaultAuth
resources are merged. The headers from the VaultAuth always take precedence.

If `replace` is set, the first set of non-empty headers taken in order from:
VaultAuth, VaultAuthGlobal auth method, VaultGlobal default headers.

If `none` is set, the headers from the
VaultAuthGlobal resource are ignored and only the headers from the VaultAuth
resource are used. The default is `none`. | | Enum: [union replace none]
| +| `params` _string_ | Params configures the merge strategy for HTTP parameters that are included in
all Vault requests. Choices are `union`, `replace`, or `none`.

If `union` is set, the parameters from the VaultAuthGlobal and VaultAuth
resources are merged. The parameters from the VaultAuth always take
precedence.

If `replace` is set, the first set of non-empty parameters taken in order from:
VaultAuth, VaultAuthGlobal auth method, VaultGlobal default parameters.

If `none` is set, the parameters from the VaultAuthGlobal resource are ignored
and only the parameters from the VaultAuth resource are used. The default is
`none`. | | Enum: [union replace none]
| + + #### RolloutRestartTarget @@ -321,6 +342,22 @@ _Appears in:_ | `keyName` _string_ | KeyName to use for encrypt/decrypt operations via Vault Transit. | | | +#### SyncConfig + + + +SyncConfig configures sync behavior from Vault to VSO + + + +_Appears in:_ +- [VaultStaticSecretSpec](#vaultstaticsecretspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `instantUpdates` _boolean_ | InstantUpdates is a flag to indicate that event-driven updates are
enabled for this VaultStaticSecret | | | + + #### Template @@ -431,6 +468,7 @@ authenticate to Vault. _Appears in:_ +- [VaultAuthGlobalConfigAWS](#vaultauthglobalconfigaws) - [VaultAuthSpec](#vaultauthspec) | Field | Description | Default | Validation | @@ -455,6 +493,7 @@ Vault via an AppRole AuthMethod. _Appears in:_ +- [VaultAuthGlobalConfigAppRole](#vaultauthglobalconfigapprole) - [VaultAuthSpec](#vaultauthspec) | Field | Description | Default | Validation | @@ -473,6 +512,7 @@ authenticating to Vault via a GCP AuthMethod, using workload identity _Appears in:_ +- [VaultAuthGlobalConfigGCP](#vaultauthglobalconfiggcp) - [VaultAuthSpec](#vaultauthspec) | Field | Description | Default | Validation | @@ -493,6 +533,7 @@ VaultAuthConfigJWT provides VaultAuth configuration options needed for authentic _Appears in:_ +- [VaultAuthGlobalConfigJWT](#vaultauthglobalconfigjwt) - [VaultAuthSpec](#vaultauthspec) | Field | Description | Default | Validation | @@ -513,6 +554,7 @@ VaultAuthConfigKubernetes provides VaultAuth configuration options needed for au _Appears in:_ +- [VaultAuthGlobalConfigKubernetes](#vaultauthglobalconfigkubernetes) - [VaultAuthSpec](#vaultauthspec) | Field | Description | Default | Validation | @@ -523,6 +565,213 @@ _Appears in:_ | `tokenExpirationSeconds` _integer_ | TokenExpirationSeconds to set the ServiceAccount token. | 600 | Minimum: 600
| +#### VaultAuthGlobal + + + +VaultAuthGlobal is the Schema for the vaultauthglobals API + + + +_Appears in:_ +- [VaultAuthGlobalList](#vaultauthgloballist) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `secrets.hashicorp.com/v1beta1` | | | +| `kind` _string_ | `VaultAuthGlobal` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[VaultAuthGlobalSpec](#vaultauthglobalspec)_ | | | | + + +#### VaultAuthGlobalConfigAWS + + + + + + + +_Appears in:_ +- [VaultAuthGlobalSpec](#vaultauthglobalspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `role` _string_ | Vault role to use for authenticating | | | +| `region` _string_ | AWS Region to use for signing the authentication request | | | +| `headerValue` _string_ | The Vault header value to include in the STS signing request | | | +| `sessionName` _string_ | The role session name to use when creating a webidentity provider | | | +| `stsEndpoint` _string_ | The STS endpoint to use; if not set will use the default | | | +| `iamEndpoint` _string_ | The IAM endpoint to use; if not set will use the default | | | +| `secretRef` _string_ | SecretRef is the name of a Kubernetes Secret in the consumer's (VDS/VSS/PKI) namespace
which holds credentials for AWS. Expected keys include `access_key_id`, `secret_access_key`,
`session_token` | | | +| `irsaServiceAccount` _string_ | IRSAServiceAccount name to use with IAM Roles for Service Accounts
(IRSA), and should be annotated with "eks.amazonaws.com/role-arn". This
ServiceAccount will be checked for other EKS annotations:
eks.amazonaws.com/audience and eks.amazonaws.com/token-expiration | | | +| `namespace` _string_ | Namespace to auth to in Vault | | | +| `mount` _string_ | Mount to use when authenticating to auth method. | | | +| `params` _object (keys:string, values:string)_ | Params to use when authenticating to Vault | | | +| `headers` _object (keys:string, values:string)_ | Headers to be included in all Vault requests. | | | + + +#### VaultAuthGlobalConfigAppRole + + + + + + + +_Appears in:_ +- [VaultAuthGlobalSpec](#vaultauthglobalspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `roleId` _string_ | RoleID of the AppRole Role to use for authenticating to Vault. | | | +| `secretRef` _string_ | SecretRef is the name of a Kubernetes secret in the consumer's (VDS/VSS/PKI) namespace which
provides the AppRole Role's SecretID. The secret must have a key named `id` which holds the
AppRole Role's secretID. | | | +| `namespace` _string_ | Namespace to auth to in Vault | | | +| `mount` _string_ | Mount to use when authenticating to auth method. | | | +| `params` _object (keys:string, values:string)_ | Params to use when authenticating to Vault | | | +| `headers` _object (keys:string, values:string)_ | Headers to be included in all Vault requests. | | | + + +#### VaultAuthGlobalConfigGCP + + + + + + + +_Appears in:_ +- [VaultAuthGlobalSpec](#vaultauthglobalspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `role` _string_ | Vault role to use for authenticating | | | +| `workloadIdentityServiceAccount` _string_ | WorkloadIdentityServiceAccount is the name of a Kubernetes service
account (in the same Kubernetes namespace as the Vault*Secret referencing
this resource) which has been configured for workload identity in GKE.
Should be annotated with "iam.gke.io/gcp-service-account". | | | +| `region` _string_ | GCP Region of the GKE cluster's identity provider. Defaults to the region
returned from the operator pod's local metadata server. | | | +| `clusterName` _string_ | GKE cluster name. Defaults to the cluster-name returned from the operator
pod's local metadata server. | | | +| `projectID` _string_ | GCP project ID. Defaults to the project-id returned from the operator
pod's local metadata server. | | | +| `namespace` _string_ | Namespace to auth to in Vault | | | +| `mount` _string_ | Mount to use when authenticating to auth method. | | | +| `params` _object (keys:string, values:string)_ | Params to use when authenticating to Vault | | | +| `headers` _object (keys:string, values:string)_ | Headers to be included in all Vault requests. | | | + + +#### VaultAuthGlobalConfigJWT + + + + + + + +_Appears in:_ +- [VaultAuthGlobalSpec](#vaultauthglobalspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `role` _string_ | Role to use for authenticating to Vault. | | | +| `secretRef` _string_ | SecretRef is the name of a Kubernetes secret in the consumer's (VDS/VSS/PKI) namespace which
provides the JWT token to authenticate to Vault's JWT authentication backend. The secret must
have a key named `jwt` which holds the JWT token. | | | +| `serviceAccount` _string_ | ServiceAccount to use when creating a ServiceAccount token to authenticate to Vault's
JWT authentication backend. | | | +| `audiences` _string array_ | TokenAudiences to include in the ServiceAccount token. | | | +| `tokenExpirationSeconds` _integer_ | TokenExpirationSeconds to set the ServiceAccount token. | 600 | Minimum: 600
| +| `namespace` _string_ | Namespace to auth to in Vault | | | +| `mount` _string_ | Mount to use when authenticating to auth method. | | | +| `params` _object (keys:string, values:string)_ | Params to use when authenticating to Vault | | | +| `headers` _object (keys:string, values:string)_ | Headers to be included in all Vault requests. | | | + + +#### VaultAuthGlobalConfigKubernetes + + + + + + + +_Appears in:_ +- [VaultAuthGlobalSpec](#vaultauthglobalspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `role` _string_ | Role to use for authenticating to Vault. | | | +| `serviceAccount` _string_ | ServiceAccount to use when authenticating to Vault's
authentication backend. This must reside in the consuming secret's (VDS/VSS/PKI) namespace. | | | +| `audiences` _string array_ | TokenAudiences to include in the ServiceAccount token. | | | +| `tokenExpirationSeconds` _integer_ | TokenExpirationSeconds to set the ServiceAccount token. | 600 | Minimum: 600
| +| `namespace` _string_ | Namespace to auth to in Vault | | | +| `mount` _string_ | Mount to use when authenticating to auth method. | | | +| `params` _object (keys:string, values:string)_ | Params to use when authenticating to Vault | | | +| `headers` _object (keys:string, values:string)_ | Headers to be included in all Vault requests. | | | + + +#### VaultAuthGlobalList + + + +VaultAuthGlobalList contains a list of VaultAuthGlobal + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `secrets.hashicorp.com/v1beta1` | | | +| `kind` _string_ | `VaultAuthGlobalList` | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[VaultAuthGlobal](#vaultauthglobal) array_ | | | | + + +#### VaultAuthGlobalRef + + + +VaultAuthGlobalRef is a reference to a VaultAuthGlobal resource. A referring +VaultAuth resource can use the VaultAuthGlobal resource to share common +configuration across multiple VaultAuth resources. The VaultAuthGlobal +resource is used to store global configuration for VaultAuth resources. + + + +_Appears in:_ +- [VaultAuthSpec](#vaultauthspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name of the VaultAuthGlobal resource. | | Pattern: `^([a-z0-9.-]{1,253})$`
| +| `namespace` _string_ | Namespace of the VaultAuthGlobal resource. If not provided, the namespace of
the referring VaultAuth resource is used. | | Pattern: `^([a-z0-9.-]{1,253})$`
| +| `mergeStrategy` _[MergeStrategy](#mergestrategy)_ | MergeStrategy configures the merge strategy for HTTP headers and parameters
that are included in all Vault authentication requests. | | | +| `allowDefault` _boolean_ | AllowDefault when set to true will use the default VaultAuthGlobal resource
as the default if Name is not set. The 'allow-default-globals' option must be
set on the operator's '-global-vault-auth-options' flag

The default VaultAuthGlobal search is conditional.
When a ref Namespace is set, the search for the default
VaultAuthGlobal resource is constrained to that namespace.
Otherwise, the search order is:
1. The default VaultAuthGlobal resource in the referring VaultAuth resource's
namespace.
2. The default VaultAuthGlobal resource in the Operator's namespace. | | | + + +#### VaultAuthGlobalSpec + + + +VaultAuthGlobalSpec defines the desired state of VaultAuthGlobal + + + +_Appears in:_ +- [VaultAuthGlobal](#vaultauthglobal) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `allowedNamespaces` _string array_ | AllowedNamespaces Kubernetes Namespaces which are allow-listed for use with
this VaultAuthGlobal. This field allows administrators to customize which
Kubernetes namespaces are authorized to reference this resource. While Vault
will still enforce its own rules, this has the added configurability of
restricting which VaultAuthMethods can be used by which namespaces. Accepted
values: []{"*"} - wildcard, all namespaces. []{"a", "b"} - list of namespaces.
unset - disallow all namespaces except the Operator's and the referring
VaultAuthMethod's namespace, this is the default behavior. | | | +| `vaultConnectionRef` _string_ | VaultConnectionRef to the VaultConnection resource, can be prefixed with a namespace,
eg: `namespaceA/vaultConnectionRefB`. If no namespace prefix is provided it will default to
namespace of the VaultConnection CR. If no value is specified for VaultConnectionRef the
Operator will default to the `default` VaultConnection, configured in the operator's namespace. | | | +| `defaultVaultNamespace` _string_ | DefaultVaultNamespace to auth to in Vault, if not specified the namespace of the auth
method will be used. This can be used as a default Vault namespace for all
auth methods. | | | +| `defaultAuthMethod` _string_ | DefaultAuthMethod to use when authenticating to Vault. | | Enum: [kubernetes jwt appRole aws gcp]
| +| `defaultMount` _string_ | DefaultMount to use when authenticating to auth method. If not specified the mount of
the auth method configured in Vault will be used. | | | +| `params` _object (keys:string, values:string)_ | DefaultParams to use when authenticating to Vault | | | +| `headers` _object (keys:string, values:string)_ | DefaultHeaders to be included in all Vault requests. | | | +| `kubernetes` _[VaultAuthGlobalConfigKubernetes](#vaultauthglobalconfigkubernetes)_ | Kubernetes specific auth configuration, requires that the Method be set to `kubernetes`. | | | +| `appRole` _[VaultAuthGlobalConfigAppRole](#vaultauthglobalconfigapprole)_ | AppRole specific auth configuration, requires that the Method be set to `appRole`. | | | +| `jwt` _[VaultAuthGlobalConfigJWT](#vaultauthglobalconfigjwt)_ | JWT specific auth configuration, requires that the Method be set to `jwt`. | | | +| `aws` _[VaultAuthGlobalConfigAWS](#vaultauthglobalconfigaws)_ | AWS specific auth configuration, requires that Method be set to `aws`. | | | +| `gcp` _[VaultAuthGlobalConfigGCP](#vaultauthglobalconfiggcp)_ | GCP specific auth configuration, requires that Method be set to `gcp`. | | | + + + + #### VaultAuthList @@ -555,6 +804,7 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | | `vaultConnectionRef` _string_ | VaultConnectionRef to the VaultConnection resource, can be prefixed with a namespace,
eg: `namespaceA/vaultConnectionRefB`. If no namespace prefix is provided it will default to
namespace of the VaultConnection CR. If no value is specified for VaultConnectionRef the
Operator will default to the `default` VaultConnection, configured in the operator's namespace. | | | +| `vaultAuthGlobalRef` _[VaultAuthGlobalRef](#vaultauthglobalref)_ | VaultAuthGlobalRef. | | | | `namespace` _string_ | Namespace to auth to in Vault | | | | `allowedNamespaces` _string array_ | AllowedNamespaces Kubernetes Namespaces which are allow-listed for use with this AuthMethod.
This field allows administrators to customize which Kubernetes namespaces are authorized to
use with this AuthMethod. While Vault will still enforce its own rules, this has the added
configurability of restricting which VaultAuthMethods can be used by which namespaces.
Accepted values:
[]{"*"} - wildcard, all namespaces.
[]{"a", "b"} - list of namespaces.
unset - disallow all namespaces except the Operator's the VaultAuthMethod's namespace, this
is the default behavior. | | | | `method` _string_ | Method to use when authenticating to Vault. | | Enum: [kubernetes jwt appRole aws gcp]
| @@ -887,3 +1137,4 @@ _Appears in:_ | `hmacSecretData` _boolean_ | HMACSecretData determines whether the Operator computes the
HMAC of the Secret's data. The MAC value will be stored in
the resource's Status.SecretMac field, and will be used for drift detection
and during incoming Vault secret comparison.
Enabling this feature is recommended to ensure that Secret's data stays consistent with Vault. | true | | | `rolloutRestartTargets` _[RolloutRestartTarget](#rolloutrestarttarget) array_ | RolloutRestartTargets should be configured whenever the application(s) consuming the Vault secret does
not support dynamically reloading a rotated secret.
In that case one, or more RolloutRestartTarget(s) can be configured here. The Operator will
trigger a "rollout-restart" for each target whenever the Vault secret changes between reconciliation events.
All configured targets wil be ignored if HMACSecretData is set to false.
See RolloutRestartTarget for more details. | | | | `destination` _[Destination](#destination)_ | Destination provides configuration necessary for syncing the Vault secret to Kubernetes. | | | +| `syncConfig` _[SyncConfig](#syncconfig)_ | SyncConfig configures sync behavior from Vault to VSO | | | diff --git a/website/content/docs/platform/k8s/vso/helm.mdx b/website/content/docs/platform/k8s/vso/helm.mdx index ac29f51ca49b..3aa610d23488 100644 --- a/website/content/docs/platform/k8s/vso/helm.mdx +++ b/website/content/docs/platform/k8s/vso/helm.mdx @@ -23,6 +23,7 @@ Use these links to navigate to a particular top-level stanza. - [`defaultVaultConnection`](#h-defaultvaultconnection) - [`defaultAuthMethod`](#h-defaultauthmethod) - [`telemetry`](#h-telemetry) +- [`hooks`](#h-hooks) - [`tests`](#h-tests) ## All Values @@ -165,7 +166,7 @@ Use these links to navigate to a particular top-level stanza. - `repository` ((#v-controller-manager-image-repository)) (`string: hashicorp/vault-secrets-operator`) - - `tag` ((#v-controller-manager-image-tag)) (`string: 0.7.1`) + - `tag` ((#v-controller-manager-image-tag)) (`string: 0.8.0`) - `logging` ((#v-controller-manager-logging)) - logging @@ -196,11 +197,19 @@ Use these links to navigate to a particular top-level stanza. - `maxInterval` ((#v-controller-manager-backoffonsecretsourceerror-maxinterval)) (`duration: 60s`) - Maximum interval between retries. - - `maxElapsedTime` ((#v-controller-manager-backoffonsecretsourceerror-maxelapsedtime)) (`duration: 0s`) - Maximum elapsed time before giving up. + - `maxElapsedTime` ((#v-controller-manager-backoffonsecretsourceerror-maxelapsedtime)) (`duration: 0s`) - Maximum elapsed time without a successful sync from the secret's source. + It's important to note that setting this option to anything other than + its default will result in the secret sync no longer being retried after + reaching the max elapsed time. - - `randomizationFactor` ((#v-controller-manager-backoffonsecretsourceerror-randomizationfactor)) (`float: 0.5`) - Randomization factor to add jitter to the interval between retries. + - `randomizationFactor` ((#v-controller-manager-backoffonsecretsourceerror-randomizationfactor)) (`float: 0.5`) - Randomization factor randomizes the backoff interval between retries. + This helps to spread out the retries to avoid a thundering herd. + If the value is 0, then the backoff interval will not be randomized. + It is recommended to set this to a value that is greater than 0. - - `multiplier` ((#v-controller-manager-backoffonsecretsourceerror-multiplier)) (`float: 1.5`) - Sets the multiplier for increasing the interval between retries. + - `multiplier` ((#v-controller-manager-backoffonsecretsourceerror-multiplier)) (`float: 1.5`) - Sets the multiplier that is used to increase the backoff interval between retries. + This value should always be set to a value greater than 0. + The value must be greater than zero. - `clientCache` ((#v-controller-manager-clientcache)) - Configures the client cache which is used by the controller to cache (and potentially persist) vault tokens that are the result of using the VaultAuthMethod. This enables re-use of Vault Tokens @@ -581,6 +590,27 @@ Use these links to navigate to a particular top-level stanza. headers: X-vault-something1: "foo" + - `vaultAuthGlobalRef` ((#v-defaultauthmethod-vaultauthglobalref)) - VaultAuthGlobalRef + + - `enabled` ((#v-defaultauthmethod-vaultauthglobalref-enabled)) (`boolean: false`) - toggles the inclusion of the VaultAuthGlobal configuration in the + default VaultAuth CR. + + - `name` ((#v-defaultauthmethod-vaultauthglobalref-name)) (`string: ""`) - Name of the VaultAuthGlobal CR to reference. + + - `namespace` ((#v-defaultauthmethod-vaultauthglobalref-namespace)) (`string: ""`) - Namespace of the VaultAuthGlobal CR to reference. + + - `allowDefault` ((#v-defaultauthmethod-vaultauthglobalref-allowdefault)) (`boolean: ""`) - allow default globals + + - `mergeStrategy` ((#v-defaultauthmethod-vaultauthglobalref-mergestrategy)) + + - `headers` ((#v-defaultauthmethod-vaultauthglobalref-mergestrategy-headers)) (`string: none`) - merge strategy for headers + Valid values are: "replace", "merge", "none" + Default: "replace" + + - `params` ((#v-defaultauthmethod-vaultauthglobalref-mergestrategy-params)) (`string: none`) - merge strategy for params + Valid values are: "replace", "merge", "none" + Default: "replace" + ### telemetry ((#h-telemetry)) - `telemetry` ((#v-telemetry)) - Configures a Prometheus ServiceMonitor @@ -615,6 +645,35 @@ Use these links to navigate to a particular top-level stanza. - `scrapeTimeout` ((#v-telemetry-servicemonitor-scrapetimeout)) (`string: 10s`) - Timeout for Prometheus scrapes +### hooks ((#h-hooks)) + +- `hooks` ((#v-hooks)) - Configure the behaviour of Helm hooks. + + - `resources` ((#v-hooks-resources)) - Resources common to all hooks. + + - `limits` ((#v-hooks-resources-limits)) + + - `cpu` ((#v-hooks-resources-limits-cpu)) (`string: 500m`) + + - `memory` ((#v-hooks-resources-limits-memory)) (`string: 128Mi`) + + - `requests` ((#v-hooks-resources-requests)) + + - `cpu` ((#v-hooks-resources-requests-cpu)) (`string: 10m`) + + - `memory` ((#v-hooks-resources-requests-memory)) (`string: 64Mi`) + + - `upgradeCRDs` ((#v-hooks-upgradecrds)) - Configure the Helm pre-upgrade hook that handles custom resource definition (CRD) upgrades. + + - `enabled` ((#v-hooks-upgradecrds-enabled)) (`boolean: true`) - Set to true to automatically upgrade the CRDs. + Disabling this will require manual intervention to upgrade the CRDs, so it is recommended to + always leave it enabled. + + - `backoffLimit` ((#v-hooks-upgradecrds-backofflimit)) (`integer: 5`) - Limit the number of retries for the CRD upgrade. + + - `executionTimeout` ((#v-hooks-upgradecrds-executiontimeout)) (`string: 30s`) - Set the timeout for the CRD upgrade. The operation should typically take less than 5s + to complete. + ### tests ((#h-tests)) - `tests` ((#v-tests)) - # Used by unit tests, and will not be rendered except when using `helm template`, this can be safely ignored. diff --git a/website/content/docs/platform/k8s/vso/installation.mdx b/website/content/docs/platform/k8s/vso/installation.mdx index a2133d62e428..771d7018b144 100644 --- a/website/content/docs/platform/k8s/vso/installation.mdx +++ b/website/content/docs/platform/k8s/vso/installation.mdx @@ -4,6 +4,7 @@ page_title: Vault Secrets Operator Installation description: >- The Vault Secrets Operator can be installed using Helm. --- +@include 'vso/common-links.mdx' # Installing and upgrading the Vault Secrets Operator @@ -17,7 +18,7 @@ description: >- [Install Helm](https://helm.sh/docs/intro/install) before beginning. -The [Vault Secrets Operator Helm chart](/vault/docs/platform/k8s/vso/helm) is the recommended way of +The [Helm chart][helm] is the recommended way of installing and configuring the Vault Secrets Operator. To install a new instance of the Vault Secrets Operator, first add the @@ -31,13 +32,13 @@ $ helm repo add hashicorp https://helm.releases.hashicorp.com ```shell-session $ helm search repo hashicorp/vault-secrets-operator NAME CHART VERSION APP VERSION DESCRIPTION -hashicorp/vault-secrets-operator 0.7.1 0.7.1 Official HashiCorp Vault Secrets Operator Chart +hashicorp/vault-secrets-operator 0.8.0 0.8.0 Official HashiCorp Vault Secrets Operator Chart ``` Then install the Operator: ```shell-session -$ helm install --version 0.7.1 --create-namespace --namespace vault-secrets-operator vault-secrets-operator hashicorp/vault-secrets-operator +$ helm install --version 0.8.0 --create-namespace --namespace vault-secrets-operator vault-secrets-operator hashicorp/vault-secrets-operator ``` ## Upgrading using Helm @@ -54,57 +55,22 @@ Hang tight while we grab the latest from your chart repositories... Update Complete. ⎈Happy Helming!⎈ ``` - - You must update all CRDs manually before upgrading VSO. - Refer to Updating CRDs. - - -To upgrade your VSO release, replace `` with the VSO version you are upgrading to: -```shell-session -$ helm show crds --version hashicorp/vault-secrets-operator | kubectl apply -f - -$ helm upgrade --version --namespace vault-secrets-operator vault-secrets-operator hashicorp/vault-secrets-operator -``` - -For example, if you are upgrading to VSO 0.7.1: -```shell-session -$ helm show crds --version 0.7.1 hashicorp/vault-secrets-operator | kubectl apply -f - -$ helm upgrade --version 0.7.1 --namespace vault-secrets-operator vault-secrets-operator hashicorp/vault-secrets-operator -``` - ## Updating CRDs when using Helm -You must update the CRDs for VSO manually **before** you upgrade the - operator when the operator is managed by Helm. + -**Any `kubectl` warnings related to `last-applied-configuration` should be safe to ignore.** + As of VSO 0.8.0, VSO will automatically update its CRDs. + The manual upgrade step [Updating CRDs](#updating-crds-when-using-helm-prior-to-vso-0-8-0) below is no longer required when + upgrading to VSO 0.8.0+. -To update the VSO CRDs, replace `` with the VSO version you are upgrading to: -```shell-session -$ helm show crds --version hashicorp/vault-secrets-operator | kubectl apply -f - -``` - -For example, if you are upgrading to VSO 0.7.1: -```shell-session -$ helm show crds --version 0.7.1 hashicorp/vault-secrets-operator | kubectl apply -f - + -customresourcedefinition.apiextensions.k8s.io/hcpauths.secrets.hashicorp.com created -customresourcedefinition.apiextensions.k8s.io/hcpvaultsecretsapps.secrets.hashicorp.com created -Warning: resource customresourcedefinitions/vaultauths.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. -customresourcedefinition.apiextensions.k8s.io/vaultauths.secrets.hashicorp.com configured -Warning: resource customresourcedefinitions/vaultconnections.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. -customresourcedefinition.apiextensions.k8s.io/vaultconnections.secrets.hashicorp.com configured -Warning: resource customresourcedefinitions/vaultdynamicsecrets.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. -customresourcedefinition.apiextensions.k8s.io/vaultdynamicsecrets.secrets.hashicorp.com configured -Warning: resource customresourcedefinitions/vaultpkisecrets.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. -customresourcedefinition.apiextensions.k8s.io/vaultpkisecrets.secrets.hashicorp.com configured -Warning: resource customresourcedefinitions/vaultstaticsecrets.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. -customresourcedefinition.apiextensions.k8s.io/vaultstaticsecrets.secrets.hashicorp.com configured -``` +The VSO Helm chart will automatically upgrade the CRDs to match the VSO version being deployed. +There should be no need to manually update the CRDs prior to upgrading VSO using Helm. ## Chart values -Refer to the [VSO Helm chart](/vault/docs/platform/k8s/vso/helm) - overview for a full list of supported chart values. +Refer to the [Helm chart][helm] overview for a full list of supported chart values. ## Installation using Kustomize @@ -112,9 +78,9 @@ You can install and update your installation using `kustomize` which allows you To install using Kustomize, download and untar/unzip the latest release from the [Releases Page](https://github.com/hashicorp/vault-secrets-operator/releases). ```shell-session -$ wget -q https://github.com/hashicorp/vault-secrets-operator/archive/refs/tags/v0.7.1.tar.gz -$ tar -zxf v0.7.1.tar.gz -$ cd vault-secrets-operator-0.7.1/ +$ wget -q https://github.com/hashicorp/vault-secrets-operator/archive/refs/tags/v0.8.0.tar.gz +$ tar -zxf v0.8.0.tar.gz +$ cd vault-secrets-operator-0.8.0/ ``` Next install using `kustomize build`: @@ -162,3 +128,43 @@ vault-secrets-operator-system vault-secrets-operator-controller-manager-56754d Upgrading using Kustomize is similar to installation: simply download the new release from github and follow the same steps as outlined in [Installation using Kustomize](#installation-using-kustomize). No additional steps are required to update the CRDs. + +## Legacy notes + +The following notes provide guidance for installing/upgrading older versions of VSO. + +### Updating CRDs when using Helm prior to VSO 0.8.0 + +This step can be skipped if you are upgrading to VSO 0.8.0 or later. + + + You must update all CRDs manually before upgrading VSO to a version prior to 0.8.0. + + +You must update the CRDs for VSO manually **before** you upgrade the +operator when the operator is managed by Helm. + +**Any `kubectl` warnings related to `last-applied-configuration` should be safe to ignore.** + +To update the VSO CRDs, replace `` with the VSO version you are upgrading to: +```shell-session +$ helm show crds --version hashicorp/vault-secrets-operator | kubectl apply -f - +``` + +For example, if you are upgrading to VSO 0.7.1: +```shell-session +$ helm show crds --version 0.7.1 hashicorp/vault-secrets-operator | kubectl apply -f - + +customresourcedefinition.apiextensions.k8s.io/hcpauths.secrets.hashicorp.com created +customresourcedefinition.apiextensions.k8s.io/hcpvaultsecretsapps.secrets.hashicorp.com created +Warning: resource customresourcedefinitions/vaultauths.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. +customresourcedefinition.apiextensions.k8s.io/vaultauths.secrets.hashicorp.com configured +Warning: resource customresourcedefinitions/vaultconnections.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. +customresourcedefinition.apiextensions.k8s.io/vaultconnections.secrets.hashicorp.com configured +Warning: resource customresourcedefinitions/vaultdynamicsecrets.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. +customresourcedefinition.apiextensions.k8s.io/vaultdynamicsecrets.secrets.hashicorp.com configured +Warning: resource customresourcedefinitions/vaultpkisecrets.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. +customresourcedefinition.apiextensions.k8s.io/vaultpkisecrets.secrets.hashicorp.com configured +Warning: resource customresourcedefinitions/vaultstaticsecrets.secrets.hashicorp.com is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. +customresourcedefinition.apiextensions.k8s.io/vaultstaticsecrets.secrets.hashicorp.com configured +``` diff --git a/website/content/docs/platform/k8s/vso/openshift.mdx b/website/content/docs/platform/k8s/vso/openshift.mdx index 165c5f0c957a..610c3aab256b 100644 --- a/website/content/docs/platform/k8s/vso/openshift.mdx +++ b/website/content/docs/platform/k8s/vso/openshift.mdx @@ -26,13 +26,13 @@ Set the following environment variables [on the subscription](https://access.red ## Helm chart -The Vault Secrets Operator may also be installed in OpenShift using the Helm chart. (See [Installation](/vault/docs/platform/k8s/vso/installation) for an overview of installation using the [Helm chart](/vault/docs/platform/k8s/vso/helm).) The examples below show example [values.yaml files](https://helm.sh/docs/chart_template_guide/values_files/) for each configuration, which would be used with `helm install` as below: +The Vault Secrets Operator may also be installed in OpenShift using the Helm chart. (See [Helm chart][helm].) The examples below show example [values.yaml files](https://helm.sh/docs/chart_template_guide/values_files/) for each configuration, which would be used with `helm install` as below: ```shell-session $ helm install vault-secrets-operator hashicorp/vault-secrets-operator \ --create-namespace \ --namespace vault-secrets-operator \ - --version 0.7.1 \ + --version 0.8.0 \ --values values.yaml ``` @@ -65,7 +65,7 @@ controller: manager: image: repository: registry.connect.redhat.com/hashicorp/vault-secrets-operator - tag: 0.7.1-ubi + tag: 0.8.0-ubi resources: limits: memory: 256Mi diff --git a/website/content/docs/platform/k8s/vso/sources/vault/auth/index.mdx b/website/content/docs/platform/k8s/vso/sources/vault/auth/index.mdx new file mode 100644 index 000000000000..2dd96d9e13c9 --- /dev/null +++ b/website/content/docs/platform/k8s/vso/sources/vault/auth/index.mdx @@ -0,0 +1,502 @@ +--- +layout: docs +page_title: 'Vault Secrets Operator: Vault authentication details' +description: >- + Authenticate to Vault with the Vault Secrets Operator. +--- + +@include 'vso/common-links.mdx' + +# Vault authentication in detail + +## Auth configuration + +The Vault Secrets Operator (VSO) relies on `VaultAuth` resources to authenticate with Vault. It relies on credential +providers to generate the credentials necessary for authentication. For example, when VSO authenticates to a kubernetes +auth backend, it generates a token using the Kubernetes service account configured in the VaultAuth resource's defined +kubernetes auth method. The service account must be configured in the Kubernetes namespace of the requesting resource. +Meaning, if a resource like a `VaultStaticSecret` is created in the `apps` namespace, the service account must be in +the apps namespace. The rationale behind this approach is to ensure that cross namespace access is not possible. + +## Vault authentication globals + +The `VaultAuthGlobal` resource is a global configuration that allows you to share a single authentication configuration +across a set of VaultAuth resources. This is useful when you have multiple VaultAuth resources that share the +same base configuration. For example, if you have multiple VaultAuth resources that all authenticate to Vault +using the same auth backend, you can create a single VaultAuthGlobal resource that defines the configuration +common to all VaultAuth instances. Options like `mount`, `method`, `namespace`, and method specific configuration +can all be inherited from the VaultAuthGlobal resource. Any field in the VaultAuth resource can be inherited +from a VaultAuthGlobal instance. Typically, most fields are inherited from the VaultAuthGlobal, +fields like `role`, and credential provider specific fields like `serviceAccount` are usually set on the referring +VaultAuth instance, since they are more specific to the application that requires the VaultAuth resource. + +*See [VaultAuthGlobal spec][vag-spec] and [VaultAuth spec][va-spec] for the complete list of available fields.* + + +## VaultAuthGlobal configuration inheritance + +- The configuration in the VaultAuth resource takes precedence over the configuration in the VaultAuthGlobal resource. +- The VaultAuthGlobal can reside in any namespace, but must allow the namespace of the VaultAuth resource to reference it. +- Default VaultAuthGlobal resources are denoted by the name `default` and are automatically referenced by all VaultAuth resources + when `spec.vaultAuthGlobalRef.allowDefault` is set to `true` and VSO is running with the `allow-default-globals` + option set in the `-global-vault-auth-options` flag (the default). +- When a `spec.vaultAuthGlobalRef.namespace` is set, the search for the default VaultAuthGlobal resource is + constrained to that namespace. Otherwise, the search order is: + 1. The default VaultAuthGlobal resource in the referring VaultAuth resource's namespace. + 2. The default VaultAuthGlobal resource in the Operator's namespace. + + +## Sample use cases and configurations + +The following sections provide some sample use cases and configurations for the VaultAuthGlobal resource. These +examples demonstrate how to use the VaultAuthGlobal resource to share a common authentication configuration across a +set of VaultAuth resources. Like other namespaced VSO custom resource definitions, there can be many VaultAuthGlobal +resources configured in a single Kubernetes cluster. + +### Multiple applications with shared authentication backend + +A Vault admin has configured a Kubernetes auth backend in Vault mounted at `kubernetes`. The admin expects to have +two applications authenticate using their own roles, and service accounts. The admin creates the necessary roles in +Vault bound to the service accounts and namespaces of the applications. + +The admin creates a default VaultAuthGlobal with the following configuration: + +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuthGlobal +metadata: + name: default + namespace: admin +spec: + allowedNamespaces: + - apps + defaultAuthMethod: kubernetes + kubernetes: + audiences: + - vault + mount: kubernetes + role: default + serviceAccount: default + tokenExpirationSeconds: 600 +``` + +A developer creates a `VaultAuth` and VaultStaticSecret resource in their application's namespace with the following +configurations: + +Application 1 would have a configuration like this: +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuth +metadata: + name: app1 + namespace: apps +spec: + kubernetes: + role: app1 + serviceAccount: app1 + vaultAuthGlobalRef: + allowDefault: true + namespace: admin +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: app1-secret + namespace: apps +spec: + destination: + create: true + name: app1-secret + hmacSecretData: true + mount: apps + path: app1 + type: kv-v2 + vaultAuthRef: app1 +``` + +Application 2 would have a similar configuration: +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuth +metadata: + name: app2 + namespace: apps +spec: + kubernetes: + role: app2 + serviceAccount: app2 + vaultAuthGlobalRef: + allowDefault: true + namespace: admin +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: app2-secret + namespace: apps +spec: + destination: + create: true + name: app2-secret + hmacSecretData: true + mount: apps + path: app2 + type: kv-v2 + vaultAuthRef: app2 +``` + +#### Explanation + +- The default VaultAuthGlobal resource is created in the `admin` namespace. This resource defines the + common configuration for all VaultAuth resources that reference it. The `allowedNamespaces` field restricts the + VaultAuth resources that can reference this VaultAuthGlobal resource. In this case, only resources in the `apps` + namespace can reference this VaultAuthGlobal resource. +- The VaultAuth resources in the `apps` namespace reference the VaultAuthGlobal resource. This allows the VaultAuth + resources to inherit the configuration from the VaultAuthGlobal resource. The `role` and `serviceAccount` fields are + specific to the application and are not inherited from the VaultAuthGlobal resource. Since the + `.spec.vaultAuthGlobalRef.allowDefault` field is set to `true`, the VaultAuth resources will automatically reference the + `default` VaultAuthGlobal in defined namespace. +- The VaultStaticSecret resources in the `apps` namespace reference the VaultAuth resources. This allows the + VaultStaticSecret resources to authenticate to Vault in order to sync the KV secrets to the destination Kubernetes + Secret. + +### Multiple applications with shared authentication backend and role + +A Vault admin has configured a Kubernetes auth backend in Vault mounted at `kubernetes`. The admin expects to have +two applications authenticate using a single role, and service account. The admin creates the necessary role in +Vault bound to the same service account and namespace of the applications. + +The admin or developer creates a default VaultAuthGlobal in the application's namespace with the following +configuration: + +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuthGlobal +metadata: + name: default + namespace: apps +spec: + defaultAuthMethod: kubernetes + kubernetes: + audiences: + - vault + mount: kubernetes + role: apps + serviceAccount: apps + tokenExpirationSeconds: 600 +``` + +A developer creates single VaultAuth and the necessary VaultStatic secrets in their application's namespace with the +following: + +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuth +metadata: + name: apps + namespace: apps +spec: + vaultAuthGlobalRef: + allowDefault: true +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: app1-secret + namespace: apps +spec: + destination: + create: true + name: app1-secret + hmacSecretData: true + mount: apps + path: app1 + type: kv-v2 + vaultAuthRef: apps +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: app2-secret + namespace: apps +spec: + destination: + create: true + name: app2-secret + hmacSecretData: true + mount: apps + path: app2 + type: kv-v2 + vaultAuthRef: apps +``` + +#### Explanation + +- The default VaultAuthGlobal resource is created in the `apps` namespace. It provides all the necessary configuration + for the VaultAuth resources that reference it. +- A single VaultAuth resource is created in the `apps` namespace. This resource references the VaultAuthGlobal resource + and inherits the configuration from it. +- The VaultStaticSecret resources in the `apps` namespace reference the VaultAuth resource. This allows the VaultStaticSecret + resources to authenticate to Vault in order to sync the KV secrets to the destination Kubernetes Secret. + +### Multiple applications with multiple authentication backends and roles + +A Vault admin has configured a Kubernetes auth backend in Vault mounted at `kubernetes`. In addition, the Vault +admin has configured a JWT auth backend mounted at `jwt`. The admin creates the necessary roles in Vault for each +auth method. The admin expects to have two applications authenticate, one using `kubernetes` auth and the other using `jwt` auth. + +The admin or developer creates a default VaultAuthGlobal in the application's namespace with the following +configuration: + +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuthGlobal +metadata: + name: default + namespace: apps +spec: + defaultAuthMethod: kubernetes + kubernetes: + audiences: + - vault + mount: kubernetes + role: apps + serviceAccount: apps-k8s + tokenExpirationSeconds: 600 + jwt: + audiences: + - vault + mount: jwt + role: apps + serviceAccount: apps-jwt +``` + +A developer creates a VaultAuth and VaultStaticSecret resource in their application's namespace with the following +configurations: + +Application 1 would have a configuration like this which will be using the kubernetes auth method: +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuth +metadata: + name: apps-default + namespace: apps +spec: + # uses the default kubernetes auth method as defined in + # the VaultAuthGlobal .spec.defaultAuthMethod + vaultAuthGlobalRef: + allowDefault: true +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: app1-secret + namespace: apps +spec: + destination: + create: true + name: app1-secret + hmacSecretData: true + mount: apps + path: app1 + type: kv-v2 + vaultAuthRef: apps-default +``` + +Application 2 would have a similar configuration, except it will be using the JWT auth method: +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuth +metadata: + name: apps-jwt + namespace: apps +spec: + method: jwt + vaultAuthGlobalRef: + allowDefault: true +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: app2-secret + namespace: apps +spec: + destination: + create: true + name: app2-secret + hmacSecretData: true + mount: apps + path: app2 + type: kv-v2 + vaultAuthRef: apps-jwt +``` + +#### Explanation + +- The default VaultAuthGlobal resource is created in the `apps` namespace. It provides all the necessary configuration + for the VaultAuth resources that reference it. The `defaultAuthMethod` field defines the default auth method to use + when authenticating to Vault. The `kubernetes` and `jwt` fields define the configuration for the respective auth + method. +- Application 1 uses the default kubernetes auth method defined in the VaultAuthGlobal resource. The VaultAuth resource + references the VaultAuthGlobal resource and inherits the kubernetes auth configuration from it. +- Application 2 uses the JWT auth method defined in the VaultAuthGlobal resource. The VaultAuth resource references the + VaultAuthGlobal resource and inherits the JWT auth configuration from it. +- Neither VaultAuth resource has a `role` or `serviceAccount` field set. This is because the `role` and `serviceAccount` + fields are defined in the VaultAuthGlobal resource and are inherited by the VaultAuth resources. + +## VaultAuthGlobal common errors and troubleshooting + +There are few sources for tracking down issues with VaultAuthGlobal resources: +- Vault Secrets Operator logs +- Kubernetes events +- Resource status + +Below are examples of errors from each source and how to resolve them: + + Sample output sync failures from the Vault Secrets Operator logs: + ```json + { + "level": "error", + "ts": "2024-07-16T17:35:20Z", + "logger": "cachingClientFactory", + "msg": "Failed to get cacheKey from obj", + "controller": "vaultstaticsecret", + "controllerGroup": "secrets.hashicorp.com", + "controllerKind": "VaultStaticSecret", + "VaultStaticSecret": { + "name": "app1", + "namespace": "apps" + }, + "namespace": "apps", + "name": "app1", + "reconcileID": "5201f597-6c5d-4d07-ae8f-30a39c80dc54", + "error": "failed getting admin/default, err=VaultAuthGlobal.secrets.hashicorp.com \"default\" not found" + } + ``` + + Check for related Kubernetes events: + + ```shell + $ kubectl events --types=Warning -n admin --for vaultauths.secrets.hashicorp.com/default -o json + ``` + + Sample output from the Kubernetes event for the VaultAuth resource: + + ```json + { + "kind": "Event", + "apiVersion": "v1", + "metadata": { + "name": "default.17e2c0da7b0e36b5", + "namespace": "admin", + "uid": "3ca6088e-7391-4b76-9443-a790ccae02c0", + "resourceVersion": "634396", + "creationTimestamp": "2024-07-16T17:14:12Z" + }, + "involvedObject": { + "kind": "VaultAuth", + "namespace": "admin", + "name": "default", + "uid": "1dabe3a5-5479-4f5d-ac48-5db7eff7f822", + "apiVersion": "secrets.hashicorp.com/v1beta1", + "resourceVersion": "631994" + }, + "reason": "Accepted", + "message": "Failed to handle VaultAuth resource request: err=failed getting admin/default, err=VaultAuthGlobal.secrets.hashicorp.com \"default\" not found", + "source": { + "component": "VaultAuth" + }, + "firstTimestamp": "2024-07-16T17:14:12Z", + "lastTimestamp": "2024-07-16T17:15:53Z", + "count": 25, + "type": "Warning", + "eventTime": null, + "reportingComponent": "VaultAuth", + "reportingInstance": "" + } + ``` + +Check the conditions on the VaultAuth resource: + + ```shell + $ kubectl get vaultauths.secrets.hashicorp.com -n admin default -o jsonpath='{.status}' + ``` + +Sample output of the VaultAuth's status (prettified). The `valid` field will be `false` for the condition reason +`VaultAuthGlobalRef`: + ```json + { + "conditions": [ + { + "lastTransitionTime": "2024-07-16T15:35:43Z", + "message": "failed getting admin/default, err=VaultAuthGlobal.secrets.hashicorp.com \"default\" not found", + "observedGeneration": 3, + "reason": "VaultAuthGlobalRef", + "status": "False", + "type": "Available" + } + ], + "specHash": "e264f241cb4ad776802924b6ad2aa272b11cffd570382605d1c2ddbdfd661ad3", + "valid": false + } + ``` +- **Situation**: The VaultAuthGlobal resource is not found or is invalid for some reason, denoted by error messages like +`not found...`. + + **Resolution**: Ensure that the VaultAuthGlobal resource exists in the referring VaultAuth's namespace or a default + VaultAuthGlobal resource exists per [VaultAuthGlobal configuration inheritance] + (#vaultauthglobal-configuration-inheritance) + +- **Situation**: The VaultAuthGlobal is not allowed to be referenced by the VaultAuth resource, denoted by error + messages like `target namespace "apps" is not allowed...`. + + **Resolution**: Ensure that the VaultAuthGlobal resource's `spec.allowedNamespaces` field includes the namespace of the + VaultAuth resource. + +- **Situation**: The VaultAuth resource is not valid due to missing required fields, denoted by error messages like + `invalid merge: empty role`. + + **Resolution**: Ensure all required fields are set either on the VaultAuth resource or on the inherited + VaultAuthGlobal. + + A successfully merged VaultAuth resource will have the `valid` field set to `true` and the `conditions` will look + something like: + + ```json + { + "conditions": [ + { + "lastTransitionTime": "2024-07-17T13:46:43Z", + "message": "VaultAuthGlobal successfully merged, key=admin/default, uid=6aeb3559-8f42-48bf-b16a-2305bc9a9bed, generation=7", + "observedGeneration": 1, + "reason": "VaultAuthGlobalRef", + "status": "True", + "type": "Available" + } + ], + "specHash": "5cbe5544d0557926e00002514871b95c49903a9d4496ef9b794c84f1e54db1a0", + "valid": true + } + ``` + + + + The value for the key in the message field is the namespace/name of the VaultAuthGlobal object that was successfully merged. + This is useful if you want to know which VaultAuthGlobal object was used to merge the VaultAuth object. + + + + +## Some authentication engines in detail + +- [AWS](/vault/docs/auth/aws) + +- [GCP](/vault/docs/auth/gcp) diff --git a/website/content/docs/platform/k8s/vso/sources/vault/index.mdx b/website/content/docs/platform/k8s/vso/sources/vault/index.mdx index 9957123d2653..12d0ddf5e719 100644 --- a/website/content/docs/platform/k8s/vso/sources/vault/index.mdx +++ b/website/content/docs/platform/k8s/vso/sources/vault/index.mdx @@ -4,6 +4,7 @@ page_title: Vault Secrets Operator description: >- The Vault Secrets Operator allows Pods to consume Vault secrets natively from Kubernetes Secrets. --- +@include 'vso/common-links.mdx' # Vault Secrets Operator @@ -29,6 +30,8 @@ Vault Secrets Operator supports the following Vault features: during drift remediation. - Cross Vault namespace authentication for Vault Enterprise 1.13+. - [Encrypted Vault client cache storage](/vault/docs/platform/k8s/vso/sources/vault#vault-client-cache) for improved performance and security. +- [Instant updates](/vault/docs/platform/k8s/vso/sources/vault#instant-updates) + for VaultStaticSecret's with Vault Enterprise 1.16.3+. ### Supported Vault authentication methods @@ -112,6 +115,76 @@ spec: # headers: [] ``` +### VaultAuthGlobal custom resource + + + +VSO v0.8.0 + + + +Namespaced resource that provides shared Vault authentication configuration that can be inherited by multiple +`VaultAuth` custom resources. It supports multiple authentication methods and allows you to define a default +authentication method that can be overridden by individual VaultAuth custom resources. See `vaultAuthGlobalRef` in +the [VaultAuth spec][va-spec] for more details. The `VaultAuthGlobal` custom resource is optional and can be used to +simplify the configuration of multiple VaultAuth custom resources by reducing config duplication. Like other +namespaced VSO custom resources, there can be many VaultAuthGlobal resources configured in a single Kubernetes cluster. + +For more details on how to integrate VaultAuthGlobals into your workflow, see the detailed [Authentication][auth] +docs. + + + + The VaultAuthGlobal resources shares many of the same fields as the VaultAuth custom resource, but cannot be used + for authentication directly. It is only used to define shared Vault authentication configuration within a Kubernetes + cluster. + + + +The example below demonstrates how to define a VaultAuthGlobal custom resource with a default authentication method of +`kubernetes`, along with a VaultAuth custom resource that inherits its global configuration. + +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuthGlobal +metadata: + namespace: vso-example + name: vault-auth-global +spec: + defaultAuthMethod: kubernetes + kubernetes: + audiences: + - vault + mount: kubernetes + namespace: example-ns + role: auth-role + serviceAccount: default + tokenExpirationSeconds: 600 +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuth +metadata: + namespace: vso-example + name: vault-auth +spec: + vaultAuthGlobalRef: + name: vault-auth-global + kubernetes: + role: local-role +``` + +#### Explanation + +- The VaultAuthGlobal custom resource defines a default authentication method of kubernetes with the `defaultAuthMethod` + field. +- The VaultAuth custom resource inherits the global configuration by referencing the VaultAuthGlobal custom + resource with the `vaultAuthGlobalRef` field. +- The `kubernetes.role` field in the VaultAuth custom resource spec overrides the value of the corresponding field in + the VaultAuthGlobal custom resource. All other fields are inherited from the VaultAuthGlobal custom resource + `spec.kubernetes` field, e.g., `audiences`, `mount`, `serviceAccount`, `namespace`, etc. + + ## Vault secret custom resource definitions Provide the configuration necessary for the Operator to replicate a single Vault Secret to a single Kubernetes Secret. @@ -305,6 +378,30 @@ The Vault Secrets Operator can optionally cache Vault client information such as The [Encrypted client cache](/vault/docs/platform/k8s/vso/sources/vault/client-cache) guide will walk you through the steps to enable and configure client cache encryption. +## Instant updates + +The Vault Secrets Operator can instantly update Kubernetes Secrets when changes +are made in Vault, by subscribing to [Vault Events][vault-events] for change +notification. Setting a refresh interval (e.g. [refreshAfter][vss-spec]) is +still recommended since event message delivery is not guaranteed. + +**Supported secret types:** +- [VaultStaticSecret](#vaultstaticsecret-custom-resource) ([kv-v1](/vault/docs/secrets/kv/kv-v2), + [kv-v2](/vault/docs/secrets/kv/kv-v1)) + + + +The instant updates option requires [Vault Enterprise](/vault/docs/enterprise) +1.16.3+ due to the use of [Vault Event Notifications][vault-events]. + + + +The [Instant updates](/vault/docs/platform/k8s/vso/sources/vault/instant-updates) guide +will walk you through the steps to enable instant updates for a VaultStaticSecret. + +[vss-spec]: /vault/docs/platform/k8s/vso/api-reference#vaultstaticsecretspec +[vault-events]: /vault/docs/concepts/events + ## Tutorial Refer to the [Vault Secrets Operator on diff --git a/website/content/docs/platform/k8s/vso/sources/vault/instant-updates.mdx b/website/content/docs/platform/k8s/vso/sources/vault/instant-updates.mdx new file mode 100644 index 000000000000..a6f739988e6c --- /dev/null +++ b/website/content/docs/platform/k8s/vso/sources/vault/instant-updates.mdx @@ -0,0 +1,102 @@ +--- +layout: docs +page_title: Instant updates with Vault Secrets Operator +description: >- + Enable instant updates with Vault Secrets Operator. +--- + +# Instant updates for a VaultStaticSecret + +Vault Secrets Operator (VSO) supports instant updates for +[VaultStaticSecrets][vss-spec] by subscribing to event notifications from Vault. + +## Before you start + +- **You must have [Vault Secrets Operator](/vault/docs/platform/k8s/vso/sources/vault) installed**. +- **You must use [Vault Enterprise](/vault/docs/enterprise) version 1.16.3 or later**. + +## Step 1: Set event permissions + +Grant these permissions in the policy associated with the VaultAuth role: + + ```hcl + path "/" { + capabilities = ["read", "list", "subscribe"] + subscribe_event_types = ["*"] + } + + path "sys/events/subscribe/kv*" { + capabilities = ["read"] + } + ``` + + + +See [Event Notifications Policies][events-policies] for more information on +Vault event notification permissions. + + + +## Step 2: Enable instant updates on the VaultStaticSecret + +Set `syncConfig.instantUpdates=true` in the [VaultStaticSecret spec][vss-spec]: + +```yaml +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + namespace: vso-example + name: vault-static-secret-v2 +spec: + vaultAuthRef: vault-auth + mount: + type: kv-v2 + path: + version: 2 + refreshAfter: 1h + destination: + create: true + name: static-secret2 + syncConfig: + instantUpdates: true +``` + +## Debugging + +Check Kubernetes events on the VaultStaticSecret resource to see if VSO +subscribed to Vault event notifications. + +### Example: VSO is subscribed to Vault event notifications for the secret + +```shell-session +$ kubectl describe vaultstaticsecret vault-static-secret-v2 -n vso-example +... +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal SecretSynced 2s VaultStaticSecret Secret synced + Normal EventWatcherStarted 2s (x2 over 2s) VaultStaticSecret Started watching events + Normal SecretRotated 2s VaultStaticSecret Secret synced +``` + +### Example: The VaultAuth role policy lacks the required event permissions + +```shell-session +$ kubectl describe vaultstaticsecret vault-static-secret-v2 -n vso-example +... +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal SecretSynced 2s VaultStaticSecret Secret synced + Warning EventWatcherError 2s VaultStaticSecret Error while watching events: + failed to connect to vault websocket: error returned when opening event stream + web socket to wss://vault.vault.svc.cluster.local:8200/v1/sys/events/subscribe/kv%2A?json=true, + ensure VaultAuth role has correct permissions and Vault is Enterprise version + 1.16 or above: {"errors":["1 error occurred:\n\t* permission denied\n\n"]} + Normal SecretRotated 2s VaultStaticSecret Secret synced +``` + +[vss-spec]: /vault/docs/platform/k8s/vso/api-reference#vaultstaticsecretspec +[vault-events]: /vault/docs/concepts/events +[events-policies]: /vault/docs/concepts/events#policies diff --git a/website/content/partials/helm/install.mdx b/website/content/partials/helm/install.mdx index f555c290dacf..24b738a05221 100644 --- a/website/content/partials/helm/install.mdx +++ b/website/content/partials/helm/install.mdx @@ -2,6 +2,7 @@ # List the available releases $ helm search repo hashicorp/vault -l NAME CHART VERSION APP VERSION DESCRIPTION +hashicorp/vault 0.28.1 1.17.2 Official HashiCorp Vault Chart hashicorp/vault 0.28.0 1.16.1 Official HashiCorp Vault Chart hashicorp/vault 0.27.0 1.15.2 Official HashiCorp Vault Chart hashicorp/vault 0.26.1 1.15.1 Official HashiCorp Vault Chart @@ -9,9 +10,8 @@ hashicorp/vault 0.26.0 1.15.1 Official HashiCorp Vault Chart hashicorp/vault 0.25.0 1.14.0 Official HashiCorp Vault Chart hashicorp/vault 0.24.0 1.13.1 Official HashiCorp Vault Chart hashicorp/vault 0.23.0 1.12.1 Official HashiCorp Vault Chart -hashicorp/vault 0.22.1 1.12.0 Official HashiCorp Vault Chart ... -# Install version 0.28.0 -$ helm install vault hashicorp/vault --version 0.28.0 +# Install version 0.28.1 +$ helm install vault hashicorp/vault --version 0.28.1 ``` diff --git a/website/content/partials/helm/repo.mdx b/website/content/partials/helm/repo.mdx index 7d76bf67d8d8..31fdd5da6f6d 100644 --- a/website/content/partials/helm/repo.mdx +++ b/website/content/partials/helm/repo.mdx @@ -4,5 +4,5 @@ $ helm repo add hashicorp https://helm.releases.hashicorp.com $ helm search repo hashicorp/vault NAME CHART VERSION APP VERSION DESCRIPTION -hashicorp/vault 0.28.0 1.16.1 Official HashiCorp Vault Chart +hashicorp/vault 0.28.1 1.17.2 Official HashiCorp Vault Chart ``` diff --git a/website/content/partials/vso/common-links.mdx b/website/content/partials/vso/common-links.mdx new file mode 100644 index 000000000000..bc034f392ae5 --- /dev/null +++ b/website/content/partials/vso/common-links.mdx @@ -0,0 +1,4 @@ +[va-spec]: /vault/docs/platform/k8s/vso/api-reference#vaultauthspec +[vag-spec]: /vault/docs/platform/k8s/vso/api-reference#vaultauthglobalspec +[helm]: /vault/docs/platform/k8s/vso/helm +[auth]: /vault/docs/platform/k8s/vso/sources/vault/auth diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index 5974bcfc6694..b76afd4215e1 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -376,7 +376,7 @@ }, { "title": "TCP", - "routes": [ + "routes": [ { "title": "Overview", "path": "configuration/listener/tcp" @@ -1116,7 +1116,7 @@ "path": "commands/transform/import" } ] - }, + }, { "title": "unwrap", "path": "commands/unwrap" @@ -2208,8 +2208,12 @@ "path": "platform/k8s/vso/sources/vault" }, { - "title": "Auth Methods", + "title": "Authentication", "routes": [ + { + "title": "Overview", + "path": "platform/k8s/vso/sources/vault/auth" + }, { "title": "AWS", "path": "platform/k8s/vso/sources/vault/auth/aws" @@ -2223,6 +2227,10 @@ { "title": "Encrypted client cache", "path": "platform/k8s/vso/sources/vault/client-cache" + }, + { + "title": "Instant updates", + "path": "platform/k8s/vso/sources/vault/instant-updates" } ] },