/
version_store.go
170 lines (138 loc) · 4.88 KB
/
version_store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package vault
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/logical"
)
const (
vaultVersionPath string = "core/versions/"
)
// storeVersionEntry will store the version, timestamp, and build date to storage
// only if no entry for that version already exists in storage. Version
// timestamps were initially stored in local time. UTC should be used. Existing
// entries can be overwritten via the force flag. A bool will be returned
// denoting whether the entry was updated
func (c *Core) storeVersionEntry(ctx context.Context, vaultVersion *VaultVersion, force bool) (bool, error) {
key := vaultVersionPath + vaultVersion.Version
if vaultVersion.TimestampInstalled.Location() != time.UTC {
vaultVersion.TimestampInstalled = vaultVersion.TimestampInstalled.UTC()
}
marshalledVaultVersion, err := json.Marshal(vaultVersion)
if err != nil {
return false, err
}
newEntry := &logical.StorageEntry{
Key: key,
Value: marshalledVaultVersion,
}
if force {
// avoid storage lookup and write immediately
err = c.barrier.Put(ctx, newEntry)
if err != nil {
return false, err
}
return true, nil
}
existingEntry, err := c.barrier.Get(ctx, key)
if err != nil {
return false, err
}
if existingEntry != nil {
return false, nil
}
err = c.barrier.Put(ctx, newEntry)
if err != nil {
return false, err
}
return true, nil
}
// 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.versionHistory == nil {
return "", time.Time{}, fmt.Errorf("version history is not initialized")
}
oldestUpgradeTime := time.Now().UTC()
var oldestVersion string
for versionStr, versionEntry := range c.versionHistory {
if versionEntry.TimestampInstalled.Before(oldestUpgradeTime) {
oldestVersion = versionStr
oldestUpgradeTime = versionEntry.TimestampInstalled
}
}
return oldestVersion, oldestUpgradeTime, nil
}
func (c *Core) FindNewestVersionTimestamp() (string, time.Time, error) {
if c.versionHistory == nil {
return "", time.Time{}, fmt.Errorf("version history is not initialized")
}
var newestUpgradeTime time.Time
var newestVersion string
for versionStr, versionEntry := range c.versionHistory {
if versionEntry.TimestampInstalled.After(newestUpgradeTime) {
newestVersion = versionStr
newestUpgradeTime = versionEntry.TimestampInstalled
}
}
return newestVersion, newestUpgradeTime, nil
}
// loadVersionHistory loads all the vault versions entries from storage.
// Version timestamps were originally stored in local time. A timestamp
// that is not in UTC will be rewritten to storage as UTC.
func (c *Core) loadVersionHistory(ctx context.Context) error {
vaultVersions, err := c.barrier.List(ctx, vaultVersionPath)
if err != nil {
return fmt.Errorf("unable to retrieve vault versions from storage: %w", err)
}
for _, versionPath := range vaultVersions {
version, err := c.barrier.Get(ctx, vaultVersionPath+versionPath)
if err != nil {
return fmt.Errorf("unable to read vault version at path %s: err %w", versionPath, err)
}
if version == nil {
return fmt.Errorf("nil version stored at path %s", versionPath)
}
var vaultVersion VaultVersion
err = json.Unmarshal(version.Value, &vaultVersion)
if err != nil {
return fmt.Errorf("unable to unmarshal vault version for path %s: err %w", versionPath, err)
}
if vaultVersion.Version == "" || vaultVersion.TimestampInstalled.IsZero() {
return fmt.Errorf("found empty serialized vault version at path %s", versionPath)
}
// self-heal entries that were not stored in UTC
if vaultVersion.TimestampInstalled.Location() != time.UTC {
vaultVersion.TimestampInstalled = vaultVersion.TimestampInstalled.UTC()
isUpdated, err := c.storeVersionEntry(ctx, &vaultVersion, true)
if err != nil {
c.logger.Warn("failed to rewrite vault version timestamp as UTC", "error", err)
}
if isUpdated {
c.logger.Info("self-healed pre-existing vault version in UTC",
"vault version", vaultVersion.Version, "UTC time", vaultVersion.TimestampInstalled)
}
}
c.versionHistory[vaultVersion.Version] = vaultVersion
}
return nil
}
func IsJWT(token string) bool {
return len(token) > 3 && strings.Count(token, ".") == 2 &&
(token[3] != '.' && token[1] != '.')
}
func IsSSCToken(token string) bool {
return len(token) > MaxNsIdLength+TokenLength+TokenPrefixLength &&
strings.HasPrefix(token, consts.ServiceTokenPrefix)
}
func IsServiceToken(token string) bool {
return strings.HasPrefix(token, consts.ServiceTokenPrefix) ||
strings.HasPrefix(token, consts.LegacyServiceTokenPrefix)
}
func IsBatchToken(token string) bool {
return strings.HasPrefix(token, consts.LegacyBatchTokenPrefix) ||
strings.HasPrefix(token, consts.BatchTokenPrefix)
}