/
version_store.go
172 lines (140 loc) · 4.87 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
171
172
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/"
)
// storeVersionTimestamp will store the version and timestamp pair 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) storeVersionTimestamp(ctx context.Context, version string, timestampInstalled time.Time, force bool) (bool, error) {
key := vaultVersionPath + version
vaultVersion := VaultVersion{
TimestampInstalled: timestampInstalled.UTC(),
Version: version,
}
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.versionTimestamps == nil {
return "", time.Time{}, fmt.Errorf("version timestamps are not initialized")
}
oldestUpgradeTime := time.Now().UTC()
var oldestVersion string
for version, upgradeTime := range c.versionTimestamps {
if upgradeTime.Before(oldestUpgradeTime) {
oldestVersion = version
oldestUpgradeTime = upgradeTime
}
}
return oldestVersion, oldestUpgradeTime, nil
}
func (c *Core) FindNewestVersionTimestamp() (string, time.Time, error) {
if c.versionTimestamps == nil {
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.
func (c *Core) loadVersionTimestamps(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)
}
timestampInstalled := vaultVersion.TimestampInstalled
// self-heal entries that were not stored in UTC
if timestampInstalled.Location() != time.UTC {
timestampInstalled = timestampInstalled.UTC()
isUpdated, err := c.storeVersionTimestamp(ctx, vaultVersion.Version, timestampInstalled, 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", timestampInstalled)
}
}
c.versionTimestamps[vaultVersion.Version] = timestampInstalled
}
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)
}