Add AWS IAM integration tests and refactor admin authorization (#8098)

* Add AWS IAM integration tests and refactor admin authorization
- Added AWS IAM management integration tests (User, AccessKey, Policy)
- Updated test framework to support IAM client creation with JWT/OIDC
- Refactored s3api authorization to be policy-driven for IAM actions
- Removed hardcoded role name checks for admin privileges
- Added new tests to GitHub Actions basic test matrix

* test(s3/iam): add UpdateUser and UpdateAccessKey tests and fix nil pointer dereference

* feat(s3api): add DeletePolicy and update tests with cleanup logic

* test(s3/iam): use t.Cleanup for managed policy deletion in CreatePolicy test
This commit is contained in:
Chris Lu
2026-01-23 16:41:51 -08:00
committed by GitHub
parent 25a4691135
commit 535be3096b
9 changed files with 396 additions and 52 deletions

View File

@@ -289,8 +289,8 @@ func resolveBucketLevelAction(method string, baseAction string) string {
// mapBaseActionToS3Format converts coarse-grained base actions to S3 format
// This is the fallback when no specific resolution is found
func mapBaseActionToS3Format(baseAction string) string {
// Handle actions that already have s3: prefix
if strings.HasPrefix(baseAction, "s3:") {
// Handle actions that already have s3: or iam: prefix
if strings.HasPrefix(baseAction, "s3:") || strings.HasPrefix(baseAction, "iam:") {
return baseAction
}

View File

@@ -341,6 +341,11 @@ type MockAssumedRoleUser struct {
// buildS3ResourceArn builds an S3 resource ARN from bucket and object
func buildS3ResourceArn(bucket string, objectKey string) string {
// If bucket is already an ARN, return it as-is
if strings.HasPrefix(bucket, "arn:") {
return bucket
}
if bucket == "" {
return "arn:aws:s3:::*"
}

View File

@@ -1003,16 +1003,20 @@ func (e *EmbeddedIamApi) AuthIam(f http.HandlerFunc, _ Action) http.HandlerFunc
f(w, r)
return
}
// Operating on another user: require admin
// Operating on another user: require admin or permission
if !identity.isAdmin() {
s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
return
if e.iam.VerifyActionPermission(r, identity, Action("iam:"+action), "arn:aws:iam:::*", "") != s3err.ErrNone {
s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
return
}
}
} else {
// All other IAM actions require admin (CreateUser, DeleteUser, PutUserPolicy, etc.)
// All other IAM actions require admin or permission
if !identity.isAdmin() {
s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
return
if e.iam.VerifyActionPermission(r, identity, Action("iam:"+action), "arn:aws:iam:::*", "") != s3err.ErrNone {
s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
return
}
}
}
@@ -1094,8 +1098,10 @@ func (e *EmbeddedIamApi) DoActions(w http.ResponseWriter, r *http.Request) {
s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
return
}
// CreatePolicy only validates the policy document and returns metadata.
// Policies are not stored separately; they are attached inline via PutUserPolicy.
case "DeletePolicy":
// Managed policies are not stored separately, so deletion is a no-op.
// Returns success for AWS compatibility.
response = struct{}{}
changed = false
case "PutUserPolicy":
response, iamErr = e.PutUserPolicy(s3cfg, values)