mirror of
https://github.com/pgsty/minio.git
synced 2026-11-11 01:55:30 +03:00
fix(batch): keep cached authorization available during batch policy loads
Batch authorization evaluates the submitter's mapped policies from one IAM cache revision. It took the cache write lock for the whole evaluation and performed the lazy loads it needed under that lock: the mapping of a user whose policies come from a group is never cached, so every authorization of such a submitter (and of an LDAP or STS parent user) read storage twice with the write lock held, and an evicted policy document was read under it too. While a read lasted, every reader of the cache waited: request authentication (GetUser, CheckKey) and PolicyDBGet on the whole node. An expire job authorizes each version several times, so a large job with a group-mapped submitter serialized node authentication behind IAM storage latency, and a mapping load had no deadline at all. batchPolicySnapshot now holds the store's writer mutex and the cache read lock, and releases the read lock around each storage read, as MergePolicies releases the cache lock around a document load. The writer mutex still excludes cache writers, so the mapping and the documents of one evaluation still come from one revision; the read lock is enough because the batch path writes nothing to the cache except lazily loaded mappings, which the request path stores under the read lock as well, and taking the write lock back after each read would have made readers queue behind it. Each read is bounded by the job's context and the same 5s MergePolicies grants a document load. Concurrent reads of the group fallback release the lock once and take it back after the last. policyDBGet and policyDBGetGroups take the loads they need through the iamMappingLoader interface, which *IAMStoreSys satisfies unchanged. Unreadable policies still end the attempt as unavailable, and the error classification is unchanged. TestBatchAuthorizeSlowLoadKeepsCachedAuthorizationAvailable holds the lazy load of a group-mapped user's mapping, and of an evicted document, and requires that GetUser and IsAllowed of a cached user return within a second and that a load ends with the job's context. Before this change both cases timed out on the blocked cache. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
+13
-2
@@ -372,7 +372,18 @@ func (c *iamCache) removeGroupFromMembershipsMap(group string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *iamCache) policyDBGetGroups(store *IAMStoreSys, userPolicyPresent bool, groups ...string) ([]string, error) {
|
||||
// iamMappingLoader is what policyDBGet and policyDBGetGroups need of the
|
||||
// store: the identity backend in use and the loads of a mapping or a group
|
||||
// the cache does not hold. *IAMStoreSys loads under the lock its caller
|
||||
// holds; a caller that must not hold the cache lock across a storage read
|
||||
// wraps it (see batchPolicySnapshot).
|
||||
type iamMappingLoader interface {
|
||||
getUsersSysType() UsersSysType
|
||||
loadGroup(ctx context.Context, group string, m map[string]GroupInfo) error
|
||||
loadMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool, m *xsync.MapOf[string, MappedPolicy]) error
|
||||
}
|
||||
|
||||
func (c *iamCache) policyDBGetGroups(store iamMappingLoader, userPolicyPresent bool, groups ...string) ([]string, error) {
|
||||
var policies []string
|
||||
for _, group := range groups {
|
||||
if store.getUsersSysType() == MinIOUsersSysType {
|
||||
@@ -444,7 +455,7 @@ func (c *iamCache) policyDBGetGroups(store *IAMStoreSys, userPolicyPresent bool,
|
||||
// information in IAM (i.e sys.iam*Map) - this info is stored only in the STS
|
||||
// generated credentials. Thus we skip looking up group memberships, user map,
|
||||
// and group map and check the appropriate policy maps directly.
|
||||
func (c *iamCache) policyDBGet(store *IAMStoreSys, name string, isGroup bool, policyPresent bool) ([]string, time.Time, error) {
|
||||
func (c *iamCache) policyDBGet(store iamMappingLoader, name string, isGroup bool, policyPresent bool) ([]string, time.Time, error) {
|
||||
if isGroup {
|
||||
if store.getUsersSysType() == MinIOUsersSysType {
|
||||
g, ok := c.iamGroupsMap[name]
|
||||
|
||||
Reference in New Issue
Block a user