s3tables: reject s3vectors resources in every ARN partition (#12215)

* s3tables: reject s3vectors resources in bucket policies

An arn:aws:s3vectors: Resource is as dead as an s3vectors action: the
evaluator compares against the generated s3tables ARN, so the rule the
writer believes enforced never matches.

* s3tables: reject s3vectors resources in every ARN partition

* s3tables: test wildcard-partition and mixed-list s3vectors resources
This commit is contained in:
Chris Lu authored and GitHub committed 2026-10-29 13:38:53 -07:00
1 parent 8a2fec8610
commit 229ad84e2d
2 files changed
+24 -1

No files matched your search

+12 -1
View File
@@ -157,7 +157,7 @@ func validatePolicyDocument(raw string) error {
}
}
for _, resource := range statementActions(stmt.Resource) {
if strings.HasPrefix(resource, "arn:aws:s3vectors:") {
if arnService(resource) == "s3vectors" {
return fmt.Errorf("resource %q is not enforceable in a resource policy", resource)
}
}
@@ -165,6 +165,17 @@ func validatePolicyDocument(raw string) error {
return nil
}
// arnService returns the service field of an ARN in any partition, so a
// resource naming s3vectors is caught for aws-cn, aws-us-gov, and friends —
// not just the commercial partition.
func arnService(resource string) string {
parts := strings.SplitN(resource, ":", 4)
if len(parts) == 4 && parts[0] == "arn" {
return parts[2]
}
return ""
}
func statementActions(spec interface{}) []string {
switch a := spec.(type) {
case string:
+12
View File
@@ -476,6 +476,18 @@ func TestValidatePolicyDocument(t *testing.T) {
if err := validatePolicyDocument(deadResource); err == nil {
t.Fatal("s3vectors resource should be rejected")
}
deadPartition := `{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Principal":"*","Action":"s3tables:*","Resource":"arn:aws-cn:s3vectors:cn-1:a:bucket/b"}]}`
if err := validatePolicyDocument(deadPartition); err == nil {
t.Fatal("s3vectors resource in another partition should be rejected")
}
deadWildcard := `{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Principal":"*","Action":"s3tables:*","Resource":"arn:*:s3vectors:r:a:bucket/b"}]}`
if err := validatePolicyDocument(deadWildcard); err == nil {
t.Fatal("s3vectors resource in a wildcard partition should be rejected")
}
deadMixed := `{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Principal":"*","Action":"s3tables:*","Resource":["arn:aws:s3tables:r:a:bucket/b","arn:aws:s3vectors:r:a:bucket/b"]}]}`
if err := validatePolicyDocument(deadMixed); err == nil {
t.Fatal("resource list containing s3vectors should be rejected")
}
}
// An ARN-scoped statement reaches a caller recorded under the ARN's trailing