mirror of
https://github.com/hashicorp/vault.git
synced 2026-02-03 20:40:45 -05:00
Backport Fix cert auth role quotas into ce/main (#9246)
This commit is contained in:
parent
9eb24c2eb2
commit
a70bc7c3cf
6 changed files with 48 additions and 38 deletions
|
|
@ -69,6 +69,13 @@ func (b *backend) loginPathWrapper(wrappedOp func(ctx context.Context, req *logi
|
|||
}
|
||||
|
||||
func (b *backend) pathLoginResolveRole(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
// Quota role rule creates send a probe to test if the backend returns
|
||||
// ErrUnsupportedOperation for ResolveRole, and there's no req.Storage populated
|
||||
// for these. So just return a non-ErrUnsupportedOperation error.
|
||||
if req.Storage == nil {
|
||||
return logical.ErrorResponse("no storage"), logical.ErrMissingRequiredState
|
||||
}
|
||||
|
||||
config, err := b.Config(ctx, req.Storage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
3
changelog/_9201.txt
Normal file
3
changelog/_9201.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
```release-note:bug
|
||||
core: Role based quotas now work for cert auth
|
||||
```
|
||||
|
|
@ -153,7 +153,7 @@ func rateLimitQuotaWrapping(handler http.Handler, core *vault.Core) http.Handler
|
|||
if requiresResolveRole {
|
||||
buf := bytes.Buffer{}
|
||||
teeReader := io.TeeReader(r.Body, &buf)
|
||||
role := core.DetermineRoleFromLoginRequestFromReader(r.Context(), mountPath, teeReader)
|
||||
role := core.DetermineRoleFromLoginRequestFromReader(r.Context(), mountPath, teeReader, getConnection(r), r.Header)
|
||||
|
||||
// Reset the body if it was read
|
||||
if buf.Len() > 0 {
|
||||
|
|
|
|||
|
|
@ -4422,48 +4422,53 @@ func (c *Core) LoadNodeID() (string, error) {
|
|||
|
||||
// DetermineRoleFromLoginRequest will determine the role that should be applied to a quota for a given
|
||||
// login request
|
||||
func (c *Core) DetermineRoleFromLoginRequest(ctx context.Context, mountPoint string, data map[string]interface{}) string {
|
||||
func (c *Core) DetermineRoleFromLoginRequest(ctx context.Context, mountPoint string, data map[string]interface{}, conn *logical.Connection, headers map[string][]string) string {
|
||||
c.authLock.RLock()
|
||||
defer c.authLock.RUnlock()
|
||||
matchingBackend := c.router.MatchingBackend(ctx, mountPoint)
|
||||
if matchingBackend == nil || matchingBackend.Type() != logical.TypeCredential {
|
||||
// Role based quotas do not apply to this request
|
||||
return ""
|
||||
}
|
||||
return c.doResolveRoleLocked(ctx, mountPoint, matchingBackend, data)
|
||||
return c.doResolveRoleLocked(ctx, mountPoint, data, conn, headers)
|
||||
}
|
||||
|
||||
// DetermineRoleFromLoginRequestFromReader will determine the role that should
|
||||
// be applied to a quota for a given login request. The reader will only be
|
||||
// consumed if the matching backend for the mount point exists and is a secret
|
||||
// backend
|
||||
func (c *Core) DetermineRoleFromLoginRequestFromReader(ctx context.Context, mountPoint string, reader io.Reader) string {
|
||||
func (c *Core) DetermineRoleFromLoginRequestFromReader(ctx context.Context, mountPoint string, reader io.Reader, conn *logical.Connection, header http.Header) string {
|
||||
c.authLock.RLock()
|
||||
defer c.authLock.RUnlock()
|
||||
matchingBackend := c.router.MatchingBackend(ctx, mountPoint)
|
||||
if matchingBackend == nil || matchingBackend.Type() != logical.TypeCredential {
|
||||
// Role based quotas do not apply to this request
|
||||
return ""
|
||||
}
|
||||
|
||||
data := make(map[string]interface{})
|
||||
err := jsonutil.DecodeJSONFromReader(reader, &data)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return c.doResolveRoleLocked(ctx, mountPoint, matchingBackend, data)
|
||||
return c.doResolveRoleLocked(ctx, mountPoint, data, conn, header)
|
||||
}
|
||||
|
||||
// doResolveRoleLocked does a login and resolve role request on the matching
|
||||
// backend. Callers should have a read lock on c.authLock
|
||||
func (c *Core) doResolveRoleLocked(ctx context.Context, mountPoint string, matchingBackend logical.Backend, data map[string]interface{}) string {
|
||||
resp, err := matchingBackend.HandleRequest(ctx, &logical.Request{
|
||||
// doResolveRoleLocked does a resolve role request on the matching backend.
|
||||
// Callers should have a read lock on c.authLock.
|
||||
func (c *Core) doResolveRoleLocked(ctx context.Context, mountPoint string, data map[string]interface{}, conn *logical.Connection, headers http.Header) string {
|
||||
be, me := c.router.MatchingBackendAndMountEntry(ctx, mountPoint)
|
||||
if be == nil || be.Type() != logical.TypeCredential {
|
||||
// Role based quotas do not apply to this request
|
||||
return ""
|
||||
}
|
||||
|
||||
var passthroughRequestHeaders []string
|
||||
if rawVal, ok := me.synthesizedConfigCache.Load("passthrough_request_headers"); ok {
|
||||
passthroughRequestHeaders = rawVal.([]string)
|
||||
}
|
||||
|
||||
req := &logical.Request{
|
||||
MountPoint: mountPoint,
|
||||
Path: "login",
|
||||
Operation: logical.ResolveRoleOperation,
|
||||
Data: data,
|
||||
Storage: c.router.MatchingStorageByAPIPath(ctx, mountPoint+"login"),
|
||||
})
|
||||
Connection: conn,
|
||||
}
|
||||
if len(passthroughRequestHeaders) > 0 {
|
||||
req.Headers = filteredHeaders(headers, passthroughRequestHeaders, deniedPassthroughRequestHeaders)
|
||||
}
|
||||
resp, err := be.HandleRequest(ctx, req)
|
||||
if err != nil || resp.Data["role"] == nil {
|
||||
return ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1928,7 +1928,7 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
|
|||
// for new role-based quotas upon creation, rather than counting old leases toward
|
||||
// the total.
|
||||
if reqRole == nil && requiresLease && !c.impreciseLeaseRoleTracking {
|
||||
role = c.DetermineRoleFromLoginRequest(ctx, req.MountPoint, req.Data)
|
||||
role = c.DetermineRoleFromLoginRequest(ctx, req.MountPoint, req.Data, req.Connection, req.Headers)
|
||||
}
|
||||
|
||||
leaseGen, respTokenCreate, errCreateToken := c.LoginCreateToken(ctx, ns, req.Path, source, role, resp)
|
||||
|
|
|
|||
|
|
@ -474,26 +474,20 @@ func (r *Router) matchingStorage(ctx context.Context, path string, apiPath bool)
|
|||
|
||||
// MatchingMountEntry returns the MountEntry used for a path
|
||||
func (r *Router) MatchingMountEntry(ctx context.Context, path string) *MountEntry {
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
path = ns.Path + path
|
||||
|
||||
r.l.RLock()
|
||||
_, raw, ok := r.root.LongestPrefix(path)
|
||||
r.l.RUnlock()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return raw.(*routeEntry).mountEntry
|
||||
_, mountEntry := r.MatchingBackendAndMountEntry(ctx, path)
|
||||
return mountEntry
|
||||
}
|
||||
|
||||
// MatchingBackend returns the backend used for a path
|
||||
func (r *Router) MatchingBackend(ctx context.Context, path string) logical.Backend {
|
||||
be, _ := r.MatchingBackendAndMountEntry(ctx, path)
|
||||
return be
|
||||
}
|
||||
|
||||
func (r *Router) MatchingBackendAndMountEntry(ctx context.Context, path string) (logical.Backend, *MountEntry) {
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
path = ns.Path + path
|
||||
|
||||
|
|
@ -501,14 +495,15 @@ func (r *Router) MatchingBackend(ctx context.Context, path string) logical.Backe
|
|||
_, raw, ok := r.root.LongestPrefix(path)
|
||||
r.l.RUnlock()
|
||||
if !ok {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
re := raw.(*routeEntry)
|
||||
|
||||
re.l.RLock()
|
||||
defer re.l.RUnlock()
|
||||
|
||||
return re.backend
|
||||
return re.backend, re.mountEntry
|
||||
}
|
||||
|
||||
// MatchingSystemView returns the SystemView used for a path
|
||||
|
|
|
|||
Loading…
Reference in a new issue