s3api: cache parsed IAM policy engines for fallback auth

Previously, evaluateIAMPolicies created a new PolicyEngine and re-parsed
the JSON policy document for every policy on every request. This adds a
shared iamPolicyEngine field that caches compiled policies, kept in sync
by PutPolicy, DeletePolicy, and bulk config reload paths.

- PutPolicy deletes the old cache entry before setting the new one, so a
  parse failure on update does not leave a stale allow.
- Log warnings when policy compilation fails instead of silently
  discarding errors.
- Add test for valid-to-invalid policy update regression.
This commit is contained in:
Chris Lu
2026-03-05 14:27:48 -08:00
parent 4eb45ecc5e
commit 1b6e96614d
2 changed files with 70 additions and 10 deletions

View File

@@ -374,6 +374,28 @@ func TestVerifyActionPermissionPolicyFallback(t *testing.T) {
assert.Equal(t, s3err.ErrNone, errCode)
})
t.Run("valid policy updated to invalid denies access", func(t *testing.T) {
iam := &IdentityAccessManagement{}
err := iam.PutPolicy("myPolicy", `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::test-bucket/*"}]}`)
assert.NoError(t, err)
identity := &Identity{
Name: "policy-user",
Account: &AccountAdmin,
PolicyNames: []string{"myPolicy"},
}
errCode := iam.VerifyActionPermission(buildRequest(t, http.MethodGet), identity, Action(ACTION_READ), "test-bucket", "test-object")
assert.Equal(t, s3err.ErrNone, errCode)
// Update to invalid JSON — should revoke access.
err = iam.PutPolicy("myPolicy", "{broken")
assert.NoError(t, err)
errCode = iam.VerifyActionPermission(buildRequest(t, http.MethodGet), identity, Action(ACTION_READ), "test-bucket", "test-object")
assert.Equal(t, s3err.ErrAccessDenied, errCode)
})
t.Run("actions based path still works", func(t *testing.T) {
iam := &IdentityAccessManagement{}
identity := &Identity{