diff options
Diffstat (limited to 'weed/s3api/s3api_bucket_handlers.go')
| -rw-r--r-- | weed/s3api/s3api_bucket_handlers.go | 49 |
1 files changed, 43 insertions, 6 deletions
diff --git a/weed/s3api/s3api_bucket_handlers.go b/weed/s3api/s3api_bucket_handlers.go index 80d29547b..6ccf82e27 100644 --- a/weed/s3api/s3api_bucket_handlers.go +++ b/weed/s3api/s3api_bucket_handlers.go @@ -577,25 +577,62 @@ func isPublicReadGrants(grants []*s3.Grant) bool { return false } +// buildResourceARN builds a resource ARN from bucket and object +// Used by the policy engine wrapper +func buildResourceARN(bucket, object string) string { + if object == "" || object == "/" { + return fmt.Sprintf("arn:aws:s3:::%s", bucket) + } + // Remove leading slash if present + object = strings.TrimPrefix(object, "/") + return fmt.Sprintf("arn:aws:s3:::%s/%s", bucket, object) +} + // AuthWithPublicRead creates an auth wrapper that allows anonymous access for public-read buckets func (s3a *S3ApiServer) AuthWithPublicRead(handler http.HandlerFunc, action Action) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - bucket, _ := s3_constants.GetBucketAndObject(r) + bucket, object := s3_constants.GetBucketAndObject(r) authType := getRequestAuthType(r) isAnonymous := authType == authTypeAnonymous - glog.V(4).Infof("AuthWithPublicRead: bucket=%s, authType=%v, isAnonymous=%v", bucket, authType, isAnonymous) + glog.V(4).Infof("AuthWithPublicRead: bucket=%s, object=%s, authType=%v, isAnonymous=%v", bucket, object, authType, isAnonymous) - // For anonymous requests, check if bucket allows public read + // For anonymous requests, check if bucket allows public read via ACLs or bucket policies if isAnonymous { + // First check ACL-based public access isPublic := s3a.isBucketPublicRead(bucket) - glog.V(4).Infof("AuthWithPublicRead: bucket=%s, isPublic=%v", bucket, isPublic) + glog.V(4).Infof("AuthWithPublicRead: bucket=%s, isPublicACL=%v", bucket, isPublic) if isPublic { - glog.V(3).Infof("AuthWithPublicRead: allowing anonymous access to public-read bucket %s", bucket) + glog.V(3).Infof("AuthWithPublicRead: allowing anonymous access to public-read bucket %s (ACL)", bucket) handler(w, r) return } - glog.V(3).Infof("AuthWithPublicRead: bucket %s is not public-read, falling back to IAM auth", bucket) + + // Check bucket policy for anonymous access using the policy engine + principal := "*" // Anonymous principal + allowed, evaluated, err := s3a.policyEngine.EvaluatePolicy(bucket, object, string(action), principal) + if err != nil { + // SECURITY: Fail-close on policy evaluation errors + // If we can't evaluate the policy, deny access rather than falling through to IAM + glog.Errorf("AuthWithPublicRead: error evaluating bucket policy for %s/%s: %v - denying access", bucket, object, err) + s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied) + return + } else if evaluated { + // A bucket policy exists and was evaluated with a matching statement + if allowed { + // Policy explicitly allows anonymous access + glog.V(3).Infof("AuthWithPublicRead: allowing anonymous access to bucket %s (bucket policy)", bucket) + handler(w, r) + return + } else { + // Policy explicitly denies anonymous access + glog.V(3).Infof("AuthWithPublicRead: bucket policy explicitly denies anonymous access to %s/%s", bucket, object) + s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied) + return + } + } + // No matching policy statement - fall through to check ACLs and then IAM auth + glog.V(3).Infof("AuthWithPublicRead: no bucket policy match for %s, checking ACLs", bucket) } // For all authenticated requests and anonymous requests to non-public buckets, |
