Only create new batch tokens if we're on at least 1.10.0 (#14370)

This commit is contained in:
Josh Black 2022-03-04 14:16:51 -08:00 committed by GitHub
parent 423f1b949b
commit 5c43bf4864
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 184 additions and 4 deletions

View File

@ -402,6 +402,112 @@ func TestCore_Seal_BadToken(t *testing.T) {
}
}
func TestCore_PreOneTen_BatchTokens(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
// load up some versions and ensure that 1.9 is the most recent one by timestamp (even though this isn't realistic)
upgradeTimePlusEpsilon := time.Now().UTC()
versionEntries := []struct {
version string
ts time.Time
}{
{"1.10.1", upgradeTimePlusEpsilon.Add(-4 * time.Hour)},
{"1.9.2", upgradeTimePlusEpsilon.Add(2 * time.Hour)},
}
for _, entry := range versionEntries {
_, err := c.storeVersionTimestamp(context.Background(), entry.version, entry.ts, false)
if err != nil {
t.Fatalf("failed to write version entry %#v, err: %s", entry, err.Error())
}
}
err := c.loadVersionTimestamps(c.activeContext)
if err != nil {
t.Fatalf("failed to populate version history cache, err: %s", err.Error())
}
// double check that we're working with 1.9
v, _, err := c.FindNewestVersionTimestamp()
if err != nil {
t.Fatal(err)
}
if v != "1.9.2" {
t.Fatalf("expected 1.9.2, found: %s", v)
}
// generate a batch token
te := &logical.TokenEntry{
NumUses: 1,
Policies: []string{"root"},
NamespaceID: namespace.RootNamespaceID,
Type: logical.TokenTypeBatch,
}
err = c.tokenStore.create(namespace.RootContext(nil), te)
if err != nil {
t.Fatal(err)
}
// verify it uses the legacy prefix
if !strings.HasPrefix(te.ID, consts.LegacyBatchTokenPrefix) {
t.Fatalf("expected 1.9 batch token IDs to start with b. but it didn't: %s", te.ID)
}
}
func TestCore_OneTenPlus_BatchTokens(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
// load up some versions and ensure that 1.10 is the most recent version
upgradeTimePlusEpsilon := time.Now().UTC()
versionEntries := []struct {
version string
ts time.Time
}{
{"1.9.2", upgradeTimePlusEpsilon.Add(-4 * time.Hour)},
{"1.10.1", upgradeTimePlusEpsilon.Add(2 * time.Hour)},
}
for _, entry := range versionEntries {
_, err := c.storeVersionTimestamp(context.Background(), entry.version, entry.ts, false)
if err != nil {
t.Fatalf("failed to write version entry %#v, err: %s", entry, err.Error())
}
}
err := c.loadVersionTimestamps(c.activeContext)
if err != nil {
t.Fatalf("failed to populate version history cache, err: %s", err.Error())
}
// double check that we're working with 1.10
v, _, err := c.FindNewestVersionTimestamp()
if err != nil {
t.Fatal(err)
}
if v != "1.10.1" {
t.Fatalf("expected 1.10.1, found: %s", v)
}
// generate a batch token
te := &logical.TokenEntry{
NumUses: 1,
Policies: []string{"root"},
NamespaceID: namespace.RootNamespaceID,
Type: logical.TokenTypeBatch,
}
err = c.tokenStore.create(namespace.RootContext(nil), te)
if err != nil {
t.Fatal(err)
}
// verify it uses the legacy prefix
if !strings.HasPrefix(te.ID, consts.BatchTokenPrefix) {
t.Fatalf("expected 1.10 batch token IDs to start with hvb. but it didn't: %s", te.ID)
}
}
// GH-3497
func TestCore_Seal_SingleUse(t *testing.T) {
c, keys, _ := TestCoreUnsealed(t)

View File

@ -24,6 +24,7 @@ import (
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/go-version"
"github.com/hashicorp/vault/helper/identity"
"github.com/hashicorp/vault/helper/metricsutil"
"github.com/hashicorp/vault/helper/namespace"
@ -991,10 +992,23 @@ func (ts *TokenStore) create(ctx context.Context, entry *logical.TokenEntry) err
}
bEntry := base64.RawURLEncoding.EncodeToString(eEntry)
if ts.core.DisableSSCTokens() {
entry.ID = fmt.Sprintf("b.%s", bEntry)
ver, _, err := ts.core.FindNewestVersionTimestamp()
if err != nil {
return err
}
newestVersion, err := version.NewVersion(ver)
if err != nil {
return err
}
oneTen, err := version.NewVersion("1.10.0")
if err != nil {
return err
}
if ts.core.DisableSSCTokens() || newestVersion.LessThan(oneTen) {
entry.ID = consts.LegacyBatchTokenPrefix + bEntry
} else {
entry.ID = fmt.Sprintf("hvb.%s", bEntry)
entry.ID = consts.BatchTokenPrefix + bEntry
}
if tokenNS.ID != namespace.RootNamespaceID {

View File

@ -70,7 +70,7 @@ func (c *Core) storeVersionTimestamp(ctx context.Context, version string, timest
// FindOldestVersionTimestamp searches for the vault version with the oldest
// upgrade timestamp from storage. The earliest version this can be is 1.9.0.
func (c *Core) FindOldestVersionTimestamp() (string, time.Time, error) {
if c.versionTimestamps == nil || len(c.versionTimestamps) == 0 {
if len(c.versionTimestamps) == 0 {
return "", time.Time{}, fmt.Errorf("version timestamps are not initialized")
}
@ -86,6 +86,24 @@ func (c *Core) FindOldestVersionTimestamp() (string, time.Time, error) {
return oldestVersion, oldestUpgradeTime, nil
}
func (c *Core) FindNewestVersionTimestamp() (string, time.Time, error) {
if len(c.versionTimestamps) == 0 {
return "", time.Time{}, fmt.Errorf("version timestamps are not initialized")
}
var newestUpgradeTime time.Time
var newestVersion string
for version, upgradeTime := range c.versionTimestamps {
if upgradeTime.After(newestUpgradeTime) {
newestVersion = version
newestUpgradeTime = upgradeTime
}
}
return newestVersion, newestUpgradeTime, nil
}
// loadVersionTimestamps loads all the vault versions and associated upgrade
// timestamps from storage. Version timestamps were originally stored in local
// time. A timestamp that is not in UTC will be rewritten to storage as UTC.

View File

@ -68,6 +68,48 @@ func TestVersionStore_GetOldestVersion(t *testing.T) {
}
}
// TestVersionStore_GetNewestVersion verifies that FindNewestVersionTimestamp finds the newest
// (in time) vault version stored.
func TestVersionStore_GetNewestVersion(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
upgradeTimePlusEpsilon := time.Now().UTC()
// 1.6.1 is stored after 1.6.2, so even though it is a lower number, it should be returned.
versionEntries := []struct {
version string
ts time.Time
}{
{"1.6.2", upgradeTimePlusEpsilon.Add(-4 * time.Hour)},
{"1.6.1", upgradeTimePlusEpsilon.Add(2 * time.Hour)},
}
for _, entry := range versionEntries {
_, err := c.storeVersionTimestamp(context.Background(), entry.version, entry.ts, false)
if err != nil {
t.Fatalf("failed to write version entry %#v, err: %s", entry, err.Error())
}
}
err := c.loadVersionTimestamps(c.activeContext)
if err != nil {
t.Fatalf("failed to populate version history cache, err: %s", err.Error())
}
if len(c.versionTimestamps) != 3 {
t.Fatalf("expected 3 entries in timestamps map after refresh, found: %d", len(c.versionTimestamps))
}
v, tm, err := c.FindNewestVersionTimestamp()
if err != nil {
t.Fatal(err)
}
if v != "1.6.1" {
t.Fatalf("expected 1.6.1, found: %s", v)
}
if tm.Before(upgradeTimePlusEpsilon.Add(1*time.Hour)) || tm.After(upgradeTimePlusEpsilon.Add(3*time.Hour)) {
t.Fatalf("incorrect upgrade time logged: %v", tm)
}
}
func TestVersionStore_SelfHealUTC(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
estLoc, err := time.LoadLocation("EST")