mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-23 07:31:09 +02:00
235 lines
6.8 KiB
Go
235 lines
6.8 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package cachememdb
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Index holds the response to be cached along with multiple other values that
|
|
// serve as pointers to refer back to this index.
|
|
type Index struct {
|
|
// ID is a value that uniquely represents the request held by this
|
|
// index. This is computed by serializing and hashing the response object.
|
|
// Required: true, Unique: true
|
|
ID string
|
|
|
|
// Token is the token that fetched the response held by this index
|
|
// Required: true, Unique: true
|
|
Token string
|
|
|
|
// Tokens is a set of tokens that can access this cached response,
|
|
// which is used for static secret caching, and enabling multiple
|
|
// tokens to be able to access the same cache entry for static secrets.
|
|
// Implemented as a map so that all values are unique.
|
|
// Required: false, Unique: false
|
|
Tokens map[string]struct{}
|
|
|
|
// TokenParent is the parent token of the token held by this index
|
|
// Required: false, Unique: false
|
|
TokenParent string
|
|
|
|
// TokenAccessor is the accessor of the token being cached in this index
|
|
// Required: true, Unique: true
|
|
TokenAccessor string
|
|
|
|
// Namespace is the namespace that was provided in the request path as the
|
|
// Vault namespace to query
|
|
Namespace string
|
|
|
|
// RequestPath is the path of the request that resulted in the response
|
|
// held by this index.
|
|
// For dynamic secrets, this will be the actual path sent to the request,
|
|
// e.g. /v1/foo/bar (which will not include the namespace if it was included
|
|
// in the headers).
|
|
// For static secrets, this will be the canonical path to the secret (i.e.
|
|
// after calling getStaticSecretPathFromRequest--see its godocs for more
|
|
// information).
|
|
// Required: true, Unique: false
|
|
RequestPath string
|
|
|
|
// Versions are the versions of the secret for KVv2 static secrets only. This is
|
|
// a map of version to response, where version is the version number and response is the
|
|
// serialized cached response for that secret version.
|
|
// We could have chosen to put index.Response as Versions[0], but opted not to for consistency,
|
|
// and also to elevate the fact that the current version/representation of the path being
|
|
// cached here is stored there, not here.
|
|
// Required: false, Unique: false
|
|
Versions map[int][]byte
|
|
|
|
// Lease is the identifier of the lease in Vault, that belongs to the
|
|
// response held by this index.
|
|
// Required: false, Unique: true
|
|
Lease string
|
|
|
|
// LeaseToken is the identifier of the token that created the lease held by
|
|
// this index.
|
|
// Required: false, Unique: false
|
|
LeaseToken string
|
|
|
|
// Response is the serialized response object that the agent is caching.
|
|
Response []byte
|
|
|
|
// RenewCtxInfo holds the context and the corresponding cancel func for the
|
|
// goroutine that manages the renewal of the secret belonging to the
|
|
// response in this index.
|
|
RenewCtxInfo *ContextInfo
|
|
|
|
// RequestMethod is the HTTP method of the request
|
|
RequestMethod string
|
|
|
|
// RequestToken is the token used in the request
|
|
RequestToken string
|
|
|
|
// RequestHeader is the header used in the request
|
|
RequestHeader http.Header
|
|
|
|
// LastRenewed is the timestamp of last renewal
|
|
LastRenewed time.Time
|
|
|
|
// Type is the index type (token, auth-lease, secret-lease, static-secret)
|
|
Type string
|
|
|
|
// IndexLock is a lock held for some indexes to prevent data
|
|
// races upon update.
|
|
IndexLock sync.RWMutex
|
|
}
|
|
|
|
// CapabilitiesIndex holds the capabilities for cached static secrets.
|
|
// This type of index does not represent a response.
|
|
type CapabilitiesIndex struct {
|
|
// ID is a value that uniquely represents the request held by this
|
|
// index. This is computed by hashing the token that this capabilities
|
|
// index represents the capabilities of.
|
|
// Required: true, Unique: true
|
|
ID string
|
|
|
|
// Token is the token that fetched the response held by this index
|
|
// Required: true, Unique: true
|
|
Token string
|
|
|
|
// ReadablePaths is a set of paths with read capabilities for the given token.
|
|
// Implemented as a map for uniqueness. The key to the map is a path (such as
|
|
// `foo/bar` that we've demonstrated we can read.
|
|
ReadablePaths map[string]struct{}
|
|
|
|
// IndexLock is a lock held for some indexes to prevent data
|
|
// races upon update.
|
|
IndexLock sync.RWMutex
|
|
}
|
|
|
|
type IndexName uint32
|
|
|
|
const (
|
|
// IndexNameID is the ID of the index constructed from the serialized request.
|
|
IndexNameID = "id"
|
|
|
|
// IndexNameLease is the lease of the index.
|
|
IndexNameLease = "lease"
|
|
|
|
// IndexNameRequestPath is the request path of the index.
|
|
IndexNameRequestPath = "request_path"
|
|
|
|
// IndexNameToken is the token of the index.
|
|
IndexNameToken = "token"
|
|
|
|
// IndexNameTokenAccessor is the token accessor of the index.
|
|
IndexNameTokenAccessor = "token_accessor"
|
|
|
|
// IndexNameTokenParent is the token parent of the index.
|
|
IndexNameTokenParent = "token_parent"
|
|
|
|
// IndexNameLeaseToken is the token that created the lease.
|
|
IndexNameLeaseToken = "lease_token"
|
|
|
|
// CapabilitiesIndexNameID is the ID of the capabilities index.
|
|
CapabilitiesIndexNameID = "id"
|
|
)
|
|
|
|
func validIndexName(indexName string) bool {
|
|
switch indexName {
|
|
case IndexNameID:
|
|
case IndexNameLease:
|
|
case IndexNameRequestPath:
|
|
case IndexNameToken:
|
|
case IndexNameTokenAccessor:
|
|
case IndexNameTokenParent:
|
|
case IndexNameLeaseToken:
|
|
default:
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func validCapabilitiesIndexName(indexName string) bool {
|
|
switch indexName {
|
|
case CapabilitiesIndexNameID:
|
|
default:
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
type ContextInfo struct {
|
|
Ctx context.Context
|
|
CancelFunc context.CancelFunc
|
|
DoneCh chan struct{}
|
|
}
|
|
|
|
func NewContextInfo(ctx context.Context) *ContextInfo {
|
|
if ctx == nil {
|
|
return nil
|
|
}
|
|
|
|
ctxInfo := new(ContextInfo)
|
|
ctxInfo.Ctx, ctxInfo.CancelFunc = context.WithCancel(ctx)
|
|
ctxInfo.DoneCh = make(chan struct{})
|
|
return ctxInfo
|
|
}
|
|
|
|
// Serialize returns a json marshal'ed Index object, without the RenewCtxInfo
|
|
func (i Index) Serialize() ([]byte, error) {
|
|
i.RenewCtxInfo = nil
|
|
|
|
indexBytes, err := json.Marshal(i)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return indexBytes, nil
|
|
}
|
|
|
|
// Deserialize converts json bytes to an Index object
|
|
// Note: RenewCtxInfo will need to be reconstructed elsewhere.
|
|
func Deserialize(indexBytes []byte) (*Index, error) {
|
|
index := new(Index)
|
|
if err := json.Unmarshal(indexBytes, index); err != nil {
|
|
return nil, err
|
|
}
|
|
return index, nil
|
|
}
|
|
|
|
// SerializeCapabilitiesIndex returns a json marshal'ed CapabilitiesIndex object
|
|
func (i CapabilitiesIndex) SerializeCapabilitiesIndex() ([]byte, error) {
|
|
indexBytes, err := json.Marshal(i)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return indexBytes, nil
|
|
}
|
|
|
|
// DeserializeCapabilitiesIndex converts json bytes to an CapabilitiesIndex object
|
|
func DeserializeCapabilitiesIndex(indexBytes []byte) (*CapabilitiesIndex, error) {
|
|
index := new(CapabilitiesIndex)
|
|
if err := json.Unmarshal(indexBytes, index); err != nil {
|
|
return nil, err
|
|
}
|
|
return index, nil
|
|
}
|