Skip to content

Commit

Permalink
Prepare for 1.17.4 release (#28220)
Browse files Browse the repository at this point in the history
* backport of commit 78e1cce

* Revert "backport of commit a5262e0 (#28210)"

This reverts commit ff2e104.

* Revert "UI: remove renew self call after login (#28204) (#28211)"

This reverts commit d2d7958.

---------

Co-authored-by: Ryan Cragun <[email protected]>
  • Loading branch information
1 parent d2d7958 commit 1c8d1ad
Show file tree
Hide file tree
Showing 12 changed files with 69 additions and 603 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ ENV VERSION=$VERSION
# Copy the license file as per Legal requirement
COPY LICENSE /usr/share/doc/$NAME/LICENSE.txt

# We must have a copy of the license in this directory to comply with the HasLicense Redhat requirement
COPY LICENSE /licenses/LICENSE.txt

# Set up certificates, our base tools, and Vault. Unlike the other version of
# this (https://github.com/hashicorp/docker-vault/blob/master/ubi/Dockerfile),
# we copy in the Vault binary from CRT.
Expand Down
3 changes: 0 additions & 3 deletions changelog/28204.txt

This file was deleted.

3 changes: 0 additions & 3 deletions changelog/28207.txt

This file was deleted.

2 changes: 1 addition & 1 deletion command/agentproxyshared/cache/cachememdb/cache_memdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ func (c *CacheMemDB) SetCapabilitiesIndex(index *CapabilitiesIndex) error {
// EvictCapabilitiesIndex removes a capabilities index from the cache based on index name and value.
func (c *CacheMemDB) EvictCapabilitiesIndex(indexName string, indexValues ...interface{}) error {
index, err := c.GetCapabilitiesIndex(indexName, indexValues...)
if errors.Is(err, ErrCacheItemNotFound) {
if err == ErrCacheItemNotFound {
return nil
}
if err != nil {
Expand Down
9 changes: 0 additions & 9 deletions command/agentproxyshared/cache/cachememdb/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,6 @@ type Index struct {
// 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
Expand Down
154 changes: 12 additions & 142 deletions command/agentproxyshared/cache/lease_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"io"
"net/http"
"net/url"
"strconv"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -221,7 +220,6 @@ func (c *LeaseCache) PersistentStorage() *cacheboltdb.BoltStorage {
// checkCacheForDynamicSecretRequest checks the cache for a particular request based on its
// computed ID. It returns a non-nil *SendResponse if an entry is found.
func (c *LeaseCache) checkCacheForDynamicSecretRequest(id string) (*SendResponse, error) {
c.logger.Trace("checking cache for dynamic secret request", "id", id)
return c.checkCacheForRequest(id, nil)
}

Expand All @@ -231,7 +229,6 @@ func (c *LeaseCache) checkCacheForDynamicSecretRequest(id string) (*SendResponse
// cache entry, and return nil if it isn't. It will also evict the cache if this is a non-GET
// request.
func (c *LeaseCache) checkCacheForStaticSecretRequest(id string, req *SendRequest) (*SendResponse, error) {
c.logger.Trace("checking cache for static secret request", "id", id)
return c.checkCacheForRequest(id, req)
}

Expand Down Expand Up @@ -272,28 +269,15 @@ func (c *LeaseCache) checkCacheForRequest(id string, req *SendRequest) (*SendRes
}
}

var response []byte
version := getStaticSecretVersionFromRequest(req)
if version == 0 {
response = index.Response
} else {
response = index.Versions[version]
}

// We don't have this response as either a current or older version.
if response == nil {
return nil, nil
}

// Cached request is found, deserialize the response
reader := bufio.NewReader(bytes.NewReader(response))
reader := bufio.NewReader(bytes.NewReader(index.Response))
resp, err := http.ReadResponse(reader, nil)
if err != nil {
c.logger.Error("failed to deserialize response", "error", err)
return nil, err
}

sendResp, err := NewSendResponse(&api.Response{Response: resp}, response)
sendResp, err := NewSendResponse(&api.Response{Response: resp}, index.Response)
if err != nil {
c.logger.Error("failed to create new send response", "error", err)
return nil, err
Expand Down Expand Up @@ -498,8 +482,8 @@ func (c *LeaseCache) Send(ctx context.Context, req *SendRequest) (*SendResponse,
// included in the request path.
index.RequestPath = getStaticSecretPathFromRequest(req)

c.logger.Trace("attempting to cache static secret with following request path", "request path", index.RequestPath, "version", getStaticSecretVersionFromRequest(req))
err := c.cacheStaticSecret(ctx, req, resp, index, secret)
c.logger.Trace("attempting to cache static secret with following request path", "request path", index.RequestPath)
err := c.cacheStaticSecret(ctx, req, resp, index)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -633,19 +617,16 @@ func (c *LeaseCache) Send(ctx context.Context, req *SendRequest) (*SendResponse,
return resp, nil
}

func (c *LeaseCache) cacheStaticSecret(ctx context.Context, req *SendRequest, resp *SendResponse, index *cachememdb.Index, secret *api.Secret) error {
func (c *LeaseCache) cacheStaticSecret(ctx context.Context, req *SendRequest, resp *SendResponse, index *cachememdb.Index) error {
// If a cached version of this secret exists, we now have access, so
// we don't need to re-cache, just update index.Tokens
indexFromCache, err := c.db.Get(cachememdb.IndexNameID, index.ID)
if err != nil && !errors.Is(err, cachememdb.ErrCacheItemNotFound) {
if err != nil && err != cachememdb.ErrCacheItemNotFound {
return err
}

version := getStaticSecretVersionFromRequest(req)

// The index already exists, so all we need to do is add our token
// to the index's allowed token list, and if necessary, the new version,
// then re-store it.
// to the index's allowed token list, then re-store it.
if indexFromCache != nil {
// We must hold a lock for the index while it's being updated.
// We keep the two locking mechanisms distinct, so that it's only writes
Expand All @@ -654,45 +635,6 @@ func (c *LeaseCache) cacheStaticSecret(ctx context.Context, req *SendRequest, re
defer indexFromCache.IndexLock.Unlock()
indexFromCache.Tokens[req.Token] = struct{}{}

// Are we looking for a version that's already cached?
haveVersion := false
if version != 0 {
_, ok := indexFromCache.Versions[version]
if ok {
haveVersion = true
}
} else {
if indexFromCache.Response != nil {
haveVersion = true
}
}

if !haveVersion {
var respBytes bytes.Buffer
err = resp.Response.Write(&respBytes)
if err != nil {
c.logger.Error("failed to serialize response", "error", err)
return err
}

// Reset the response body for upper layers to read
if resp.Response.Body != nil {
resp.Response.Body.Close()
}
resp.Response.Body = io.NopCloser(bytes.NewReader(resp.ResponseBody))

// Set the index's Response
if version == 0 {
indexFromCache.Response = respBytes.Bytes()
// For current KVv2 secrets, see if we can add the version that the secret is
// to the versions map, too. If we got the latest version and the version is #2,
// also update Versions[2]
c.addToVersionListForCurrentVersionKVv2Secret(indexFromCache, secret)
} else {
indexFromCache.Versions[version] = respBytes.Bytes()
}
}

return c.storeStaticSecretIndex(ctx, req, indexFromCache)
}

Expand All @@ -710,73 +652,21 @@ func (c *LeaseCache) cacheStaticSecret(ctx context.Context, req *SendRequest, re
}
resp.Response.Body = io.NopCloser(bytes.NewReader(resp.ResponseBody))

// Initialize the versions
index.Versions = map[int][]byte{}

// Set the index's Response
if version == 0 {
index.Response = respBytes.Bytes()
// For current KVv2 secrets, see if we can add the version that the secret is
// to the versions map, too. If we got the latest version and the version is #2,
// also update Versions[2]
c.addToVersionListForCurrentVersionKVv2Secret(index, secret)
} else {
index.Versions[version] = respBytes.Bytes()
}
index.Response = respBytes.Bytes()

// Initialize the token map and add this token to it.
index.Tokens = map[string]struct{}{req.Token: {}}

// Set the index type
index.Type = cacheboltdb.StaticSecretType

// Store the index:
return c.storeStaticSecretIndex(ctx, req, index)
}

// addToVersionListForCurrentVersionKVv2Secret takes a secret index and, if it's
// a KVv2 secret, adds the given response to the corresponding version for it.
// This function fails silently, as we could be parsing arbitrary JSON.
// This function can store a version for a KVv1 secret iff:
// - It has 'data' in the path
// - It has a numerical 'metadata.version' field
// However, this risk seems very small, and the negatives of such a secret being
// stored in the cache aren't worth additional mitigations to check if it's a KVv1
// or KVv2 mount (such as doing a 'preflight' request like the CLI).
// There's no way to access it and it's just a couple of extra bytes, in the
// case that this does happen to a KVv1 secret.
func (c *LeaseCache) addToVersionListForCurrentVersionKVv2Secret(index *cachememdb.Index, secret *api.Secret) {
if secret != nil {
// First do an imperfect but lightweight check. This saves parsing the secret in the case that the secret isn't KVv2.
// KVv2 secrets always contain /data/, but KVv1 secrets can too, so we can't rely on this.
if strings.Contains(index.RequestPath, "/data/") {
metadata, ok := secret.Data["metadata"]
if ok {
metaDataAsMap, ok := metadata.(map[string]interface{})
if ok {
versionJson, ok := metaDataAsMap["version"].(json.Number)
if ok {
versionInt64, err := versionJson.Int64()
if err == nil {
version := int(versionInt64)
c.logger.Trace("adding response for current KVv2 secret to index's Versions map", "path", index.RequestPath, "version", version)

if index.Versions == nil {
index.Versions = map[int][]byte{}
}

index.Versions[version] = index.Response
}
}
}
}
}
}
}

func (c *LeaseCache) storeStaticSecretIndex(ctx context.Context, req *SendRequest, index *cachememdb.Index) error {
// Store the index in the cache
c.logger.Debug("storing static secret response into the cache", "path", index.RequestPath, "id", index.ID)
c.logger.Debug("storing static secret response into the cache", "method", req.Request.Method, "path", index.RequestPath, "id", index.ID)
err := c.Set(ctx, index)
if err != nil {
c.logger.Error("failed to cache the proxied response", "error", err)
Expand Down Expand Up @@ -805,7 +695,7 @@ func (c *LeaseCache) storeStaticSecretIndex(ctx context.Context, req *SendReques
return err
}

// Lastly, ensure that we start renewing this index, if it's new.
// Lastly, ensure that we start renewing this index, if it's new.
// We require the 'created' check so that we don't renew the same
// index multiple times.
if c.capabilityManager != nil && created {
Expand All @@ -822,7 +712,7 @@ func (c *LeaseCache) retrieveOrCreateTokenCapabilitiesEntry(token string) (*cach
// The index ID is a hash of the token.
indexId := hashStaticSecretIndex(token)
indexFromCache, err := c.db.GetCapabilitiesIndex(cachememdb.IndexNameID, indexId)
if err != nil && !errors.Is(err, cachememdb.ErrCacheItemNotFound) {
if err != nil && err != cachememdb.ErrCacheItemNotFound {
return nil, false, err
}

Expand Down Expand Up @@ -995,25 +885,6 @@ func canonicalizeStaticSecretPath(requestPath string, ns string) string {
return path
}

// getStaticSecretVersionFromRequest gets the version of a secret
// from a request. For the latest secret and for KVv1 secrets,
// this will return 0.
func getStaticSecretVersionFromRequest(req *SendRequest) int {
if req == nil || req.Request == nil {
return 0
}
version := req.Request.FormValue("version")
if version == "" {
return 0
}
versionInt, err := strconv.Atoi(version)
if err != nil {
// It's not a valid version.
return 0
}
return versionInt
}

// getStaticSecretPathFromRequest gets the canonical path for a
// request, taking into account intricacies relating to /v1/ and namespaces
// in the header.
Expand Down Expand Up @@ -1052,7 +923,6 @@ func computeStaticSecretCacheIndex(req *SendRequest) string {
if path == "" {
return path
}

return hashStaticSecretIndex(path)
}

Expand Down Expand Up @@ -1094,7 +964,7 @@ func (c *LeaseCache) HandleCacheClear(ctx context.Context) http.Handler {
// Default to 500 on error, unless the user provided an invalid type,
// which would then be a 400.
httpStatus := http.StatusInternalServerError
if errors.Is(err, errInvalidType) {
if err == errInvalidType {
httpStatus = http.StatusBadRequest
}
logical.RespondError(w, httpStatus, fmt.Errorf("failed to clear cache: %w", err))
Expand Down
4 changes: 2 additions & 2 deletions command/agentproxyshared/cache/lease_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ func TestLeaseCache_StoreCacheableStaticSecret(t *testing.T) {
// We expect two entries to be stored by this:
// 1. The actual static secret
// 2. The capabilities index
err := lc.cacheStaticSecret(context.Background(), request, response, index, nil)
err := lc.cacheStaticSecret(context.Background(), request, response, index)
if err != nil {
return
}
Expand Down Expand Up @@ -577,7 +577,7 @@ func TestLeaseCache_StaticSecret_CacheClear_All(t *testing.T) {
// We expect two entries to be stored by this:
// 1. The actual static secret
// 2. The capabilities index
err := lc.cacheStaticSecret(context.Background(), request, response, index, nil)
err := lc.cacheStaticSecret(context.Background(), request, response, index)
if err != nil {
return
}
Expand Down
Loading

0 comments on commit 1c8d1ad

Please sign in to comment.