s3tables: Use policy framework for table creation authorization
Replace strict ownership check in CreateTable with policy-based authorization. Now checks both namespace and bucket policies for CreateTable permission, allowing delegation via resource policies while still respecting owner bypass. Authorization logic: - Namespace policy grants CreateTable → allowed - Bucket policy grants CreateTable → allowed - Otherwise → denied (even if same owner) This enables cross-principal table creation via policies while maintaining security through explicit allow/deny semantics.
This commit is contained in:
@@ -85,8 +85,42 @@ func (h *S3TablesHandler) handleCreateTable(w http.ResponseWriter, r *http.Reque
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check ownership
|
// Authorize table creation using policy framework (namespace + bucket policies)
|
||||||
if accountID := h.getAccountID(r); accountID != namespaceMetadata.OwnerAccountID {
|
accountID := h.getAccountID(r)
|
||||||
|
bucketPath := getTableBucketPath(bucketName)
|
||||||
|
namespacePolicy := ""
|
||||||
|
bucketPolicy := ""
|
||||||
|
|
||||||
|
err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
|
||||||
|
// Fetch namespace policy if it exists
|
||||||
|
policyData, err := h.getExtendedAttribute(r.Context(), client, namespacePath, ExtendedKeyPolicy)
|
||||||
|
if err == nil {
|
||||||
|
namespacePolicy = string(policyData)
|
||||||
|
} else if !errors.Is(err, ErrAttributeNotFound) {
|
||||||
|
return fmt.Errorf("failed to fetch namespace policy: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch bucket policy if it exists
|
||||||
|
policyData, err = h.getExtendedAttribute(r.Context(), client, bucketPath, ExtendedKeyPolicy)
|
||||||
|
if err == nil {
|
||||||
|
bucketPolicy = string(policyData)
|
||||||
|
} else if !errors.Is(err, ErrAttributeNotFound) {
|
||||||
|
return fmt.Errorf("failed to fetch bucket policy: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to fetch policies: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check authorization: namespace policy OR bucket policy OR ownership
|
||||||
|
nsAllowed := CanCreateTable(accountID, namespaceMetadata.OwnerAccountID, namespacePolicy)
|
||||||
|
bucketAllowed := CanCreateTable(accountID, namespaceMetadata.OwnerAccountID, bucketPolicy)
|
||||||
|
|
||||||
|
if !nsAllowed && !bucketAllowed {
|
||||||
h.writeError(w, http.StatusForbidden, ErrCodeAccessDenied, "not authorized to create table in this namespace")
|
h.writeError(w, http.StatusForbidden, ErrCodeAccessDenied, "not authorized to create table in this namespace")
|
||||||
return ErrAccessDenied
|
return ErrAccessDenied
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user