fix(iam): accept bare "*" resource in PutUserPolicy (#9209) (#9210)

AWS IAM treats a bare "*" in a statement's Resource as "any resource",
but the embedded IAM resource parser required a 6-segment S3 ARN and
silently skipped anything else. With a policy like
{Action: "s3:*", Resource: "*"}, every resource was dropped and the
statement produced no actions, so PutUserPolicy rejected the document
with "no valid actions found in policy document".

Short-circuit Resource == "*" to the same full-wildcard path that
"arn:aws:s3:::*" already takes.
This commit is contained in:
Chris Lu
2026-04-23 22:14:41 -07:00
committed by GitHub
parent da2e90aefd
commit 88c2f3c34d
2 changed files with 39 additions and 4 deletions
+12 -4
View File
@@ -819,9 +819,18 @@ func (e *EmbeddedIamApi) getActions(policy *policy_engine.PolicyDocument) ([]str
return nil, fmt.Errorf("not a valid effect: '%s'. Only 'Allow' is possible", statement.Effect)
}
for _, resource := range statement.Resource.Strings() {
res := strings.Split(resource, ":")
if len(res) != 6 || res[0] != "arn" || res[1] != "aws" || res[2] != "s3" {
continue
// AWS IAM treats a bare "*" as "any resource". Normalize it to the
// full-wildcard S3 ARN so it flows through the same path as
// "arn:aws:s3:::*" instead of being dropped as malformed.
var resourcePath string
if resource == "*" {
resourcePath = "*"
} else {
res := strings.Split(resource, ":")
if len(res) != 6 || res[0] != "arn" || res[1] != "aws" || res[2] != "s3" {
continue
}
resourcePath = res[5]
}
for _, action := range statement.Action.Strings() {
act := strings.Split(action, ":")
@@ -833,7 +842,6 @@ func (e *EmbeddedIamApi) getActions(policy *policy_engine.PolicyDocument) ([]str
return nil, fmt.Errorf("not a valid action: '%s'", act[1])
}
resourcePath := res[5]
if resourcePath == "*" {
// Wildcard - applies to all buckets
actions = append(actions, statementAction)
+27
View File
@@ -1814,6 +1814,33 @@ func TestEmbeddedIamGetActionsFromPolicy(t *testing.T) {
assert.Contains(t, actions, "Write:mybucket")
}
// TestEmbeddedIamPutUserPolicyAllResourceWildcard reproduces issue #9209:
// an AWS-style policy using "Action":"s3:*" with a bare "Resource":"*" is
// valid AWS IAM syntax (meaning "any resource") but was rejected with
// "no valid actions found in policy document" because the resource parser
// required a full ARN.
func TestEmbeddedIamPutUserPolicyAllResourceWildcard(t *testing.T) {
api := NewEmbeddedIamApiForTest()
// From issue #9209: bare "*" resource and bare "s3:*" action.
policyDoc := `{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowS3Admin",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}]
}`
policy, err := api.GetPolicyDocument(&policyDoc)
require.NoError(t, err)
actions, err := api.getActions(&policy)
require.NoError(t, err, "getActions must accept bare \"*\" resource")
assert.Contains(t, actions, ACTION_ADMIN, "s3:* should map to admin action")
}
// TestEmbeddedIamSetUserStatus tests enabling/disabling a user
func TestEmbeddedIamSetUserStatus(t *testing.T) {
api := NewEmbeddedIamApiForTest()