mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-24 23:10:41 +02:00
* s3: resolve versionId ACL requests to the version ACL actions A request for an object's ACL carrying versionId acted on the historical version but authorized against the current-object action (s3:GetObjectAcl/s3:PutObjectAcl), because the acl block in resolveFromQueryParameters returned before versionId was considered - the same gap closed for tagging. An identity granted only current-object ACL access - or explicitly denied s3:*ObjectVersionAcl - could still read and modify ACLs on noncurrent versions. ?acl&versionId=<id> on an object now resolves to s3:GetObjectVersionAcl/s3:PutObjectVersionAcl; ?acl alone keeps the current-object actions and bucket ACL is unaffected. s3:PutObjectVersionAcl is mapped onto the WriteAcp identity action so policies can name it. * s3: resolve versionId attributes requests to the version attributes action GET /bucket/key?attributes&versionId=<id> fetched the historical version's attributes but authorized against s3:GetObjectAttributes, so a grant limited to the current-object attributes action could reach noncurrent versions. The request now resolves to s3:GetObjectVersionAttributes, and both attributes actions map onto the Read identity action so policies can name them (s3:GetObjectAttributes was previously rejected as an unmapped action). * s3api: recheck the version action on versioned ACL/attributes requests The phase-2 policy recheck inside GetObjectAclHandler, PutObjectAclHandler, and GetObjectAttributesHandler passed the current-object action even when the request carried versionId and phase 1 had resolved the version action. A Deny scoped to s3:*VersionAcl or s3:GetObjectVersionAttributes could never fire in the recheck, and an Allow limited to the version action went unevaluated. Select the action the same way the resolver does — versioned whenever versionId is present. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * s3api: recheck the version action on versioned tagging requests The same phase-2 gap exists in the tagging handlers left by the earlier version-tagging resolution change: versioned GetObjectTagging / PutObjectTagging / DeleteObjectTagging rechecks evaluated the current-object tagging action, so a Deny on s3:*VersionTagging could not fire. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * s3api: resolve HEAD ?acl as the head-object action, not an ACL action No HEAD acl route exists, so HEAD /bucket/key?acl lands on HeadObjectHandler — which serves object headers, not the ACL. Resolving it to an ACL action denied readers who hold only GetObject(Version) and let ACL grants reach a head-object read. Dropping HEAD from the acl branch lets the request fall through to GetObject/GetObjectVersion, matching how the tagging branch already treats HEAD. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * s3api: require the version read grant for versioned attributes AWS asks for s3:GetObjectVersion alongside s3:GetObjectVersionAttributes when a GetObjectAttributes request names a versionId; the resolved version-scoped action on its own left a lone s3:GetObjectVersion Deny unable to cover the attributes read. Check the version read grant too: the identity side through VerifyActionPermission, the bucket-policy side through the same recheck that evaluates the scoped action. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * s3api: check the version read grant on a synthesized versioned GET The versioned attributes check passed the literal s3:GetObjectVersion action, but both policy paths re-resolve the action from the request, so the attributes query parameter mapped it back to s3:GetObjectVersionAttributes and a lone version-read Deny never fired. The literal action also reached the legacy CanDo path, where a plain Read grant no longer matched. Evaluate the grant on a request shaped like a plain versioned GET instead. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * s3api: reject a named versionId on buckets without versioning Tagging, ACL, and attributes handlers answered versionId requests on never-versioned buckets as the current object while evaluating the version-scoped action, so a grant limited to the version action could authorize changes to the live entry. Reject the request up front through the existing checkVersionIdConfigured gate. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * s3api: carry presign params onto synthesized policy requests objectKeyPolicyRequest rebuilt the query with only versionId and the STS token, so a presigned request's s3:authType condition value silently changed from REST-QUERY-STRING to unset during phase-2 rechecks (version read grant, copy source, delete keys, post-policy writes). A policy conditioned on s3:authType would then deny a request it already allowed. Carry the SigV2/SigV4 presign keys through; none of them steer ResolveS3Action. --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
183 lines
8.1 KiB
Go
183 lines
8.1 KiB
Go
package s3_constants
|
|
|
|
// S3 action strings for bucket policy evaluation
|
|
// These match the official AWS S3 action format used in IAM and bucket policies
|
|
const (
|
|
// Object operations
|
|
S3_ACTION_GET_OBJECT = "s3:GetObject"
|
|
S3_ACTION_PUT_OBJECT = "s3:PutObject"
|
|
S3_ACTION_DELETE_OBJECT = "s3:DeleteObject"
|
|
S3_ACTION_DELETE_OBJECT_VERSION = "s3:DeleteObjectVersion"
|
|
S3_ACTION_GET_OBJECT_VERSION = "s3:GetObjectVersion"
|
|
S3_ACTION_GET_OBJECT_ATTRIBUTES = "s3:GetObjectAttributes"
|
|
S3_ACTION_GET_OBJECT_VERSION_ATTRIBUTES = "s3:GetObjectVersionAttributes"
|
|
|
|
// Object ACL operations
|
|
S3_ACTION_GET_OBJECT_ACL = "s3:GetObjectAcl"
|
|
S3_ACTION_PUT_OBJECT_ACL = "s3:PutObjectAcl"
|
|
|
|
// Version-specific ACL operations (?acl&versionId)
|
|
S3_ACTION_GET_OBJECT_VERSION_ACL = "s3:GetObjectVersionAcl"
|
|
S3_ACTION_PUT_OBJECT_VERSION_ACL = "s3:PutObjectVersionAcl"
|
|
|
|
// Object tagging operations
|
|
S3_ACTION_GET_OBJECT_TAGGING = "s3:GetObjectTagging"
|
|
S3_ACTION_PUT_OBJECT_TAGGING = "s3:PutObjectTagging"
|
|
S3_ACTION_DELETE_OBJECT_TAGGING = "s3:DeleteObjectTagging"
|
|
|
|
// Version-specific tagging operations (?tagging&versionId)
|
|
S3_ACTION_GET_OBJECT_VERSION_TAGGING = "s3:GetObjectVersionTagging"
|
|
S3_ACTION_PUT_OBJECT_VERSION_TAGGING = "s3:PutObjectVersionTagging"
|
|
S3_ACTION_DELETE_OBJECT_VERSION_TAGGING = "s3:DeleteObjectVersionTagging"
|
|
|
|
// Object retention and legal hold
|
|
S3_ACTION_GET_OBJECT_RETENTION = "s3:GetObjectRetention"
|
|
S3_ACTION_PUT_OBJECT_RETENTION = "s3:PutObjectRetention"
|
|
S3_ACTION_GET_OBJECT_LEGAL_HOLD = "s3:GetObjectLegalHold"
|
|
S3_ACTION_PUT_OBJECT_LEGAL_HOLD = "s3:PutObjectLegalHold"
|
|
S3_ACTION_BYPASS_GOVERNANCE = "s3:BypassGovernanceRetention"
|
|
|
|
// Multipart upload operations
|
|
S3_ACTION_CREATE_MULTIPART = "s3:CreateMultipartUpload"
|
|
S3_ACTION_UPLOAD_PART = "s3:UploadPart"
|
|
S3_ACTION_COMPLETE_MULTIPART = "s3:CompleteMultipartUpload"
|
|
S3_ACTION_ABORT_MULTIPART = "s3:AbortMultipartUpload"
|
|
S3_ACTION_UPLOAD_PART_COPY = "s3:UploadPartCopy"
|
|
S3_ACTION_LIST_PARTS = "s3:ListMultipartUploadParts"
|
|
S3_ACTION_LIST_MULTIPART_UPLOADS = "s3:ListBucketMultipartUploads"
|
|
|
|
// Bucket operations
|
|
S3_ACTION_CREATE_BUCKET = "s3:CreateBucket"
|
|
S3_ACTION_DELETE_BUCKET = "s3:DeleteBucket"
|
|
S3_ACTION_LIST_BUCKET = "s3:ListBucket"
|
|
S3_ACTION_LIST_BUCKET_VERSIONS = "s3:ListBucketVersions"
|
|
|
|
// Bucket ACL operations
|
|
S3_ACTION_GET_BUCKET_ACL = "s3:GetBucketAcl"
|
|
S3_ACTION_PUT_BUCKET_ACL = "s3:PutBucketAcl"
|
|
|
|
// Bucket policy operations
|
|
S3_ACTION_GET_BUCKET_POLICY = "s3:GetBucketPolicy"
|
|
S3_ACTION_PUT_BUCKET_POLICY = "s3:PutBucketPolicy"
|
|
S3_ACTION_DELETE_BUCKET_POLICY = "s3:DeleteBucketPolicy"
|
|
|
|
// Bucket tagging operations
|
|
S3_ACTION_GET_BUCKET_TAGGING = "s3:GetBucketTagging"
|
|
S3_ACTION_PUT_BUCKET_TAGGING = "s3:PutBucketTagging"
|
|
S3_ACTION_DELETE_BUCKET_TAGGING = "s3:DeleteBucketTagging"
|
|
|
|
// Bucket CORS operations
|
|
S3_ACTION_GET_BUCKET_CORS = "s3:GetBucketCors"
|
|
S3_ACTION_PUT_BUCKET_CORS = "s3:PutBucketCors"
|
|
S3_ACTION_DELETE_BUCKET_CORS = "s3:DeleteBucketCors"
|
|
|
|
// Bucket lifecycle operations
|
|
// Note: Both PUT and DELETE lifecycle operations use s3:PutLifecycleConfiguration
|
|
S3_ACTION_GET_BUCKET_LIFECYCLE = "s3:GetLifecycleConfiguration"
|
|
S3_ACTION_PUT_BUCKET_LIFECYCLE = "s3:PutLifecycleConfiguration"
|
|
|
|
// Bucket versioning operations
|
|
S3_ACTION_GET_BUCKET_VERSIONING = "s3:GetBucketVersioning"
|
|
S3_ACTION_PUT_BUCKET_VERSIONING = "s3:PutBucketVersioning"
|
|
|
|
// Bucket location
|
|
S3_ACTION_GET_BUCKET_LOCATION = "s3:GetBucketLocation"
|
|
|
|
// Bucket notification
|
|
S3_ACTION_GET_BUCKET_NOTIFICATION = "s3:GetBucketNotification"
|
|
S3_ACTION_PUT_BUCKET_NOTIFICATION = "s3:PutBucketNotification"
|
|
|
|
// Bucket object lock operations
|
|
S3_ACTION_GET_BUCKET_OBJECT_LOCK = "s3:GetBucketObjectLockConfiguration"
|
|
S3_ACTION_PUT_BUCKET_OBJECT_LOCK = "s3:PutBucketObjectLockConfiguration"
|
|
|
|
// Bucket encryption operations
|
|
// Note: DELETE bucket encryption uses s3:PutEncryptionConfiguration, matching AWS
|
|
S3_ACTION_GET_BUCKET_ENCRYPTION = "s3:GetEncryptionConfiguration"
|
|
S3_ACTION_PUT_BUCKET_ENCRYPTION = "s3:PutEncryptionConfiguration"
|
|
|
|
// Bucket request payment operations
|
|
S3_ACTION_GET_BUCKET_REQUEST_PAYMENT = "s3:GetBucketRequestPayment"
|
|
S3_ACTION_PUT_BUCKET_REQUEST_PAYMENT = "s3:PutBucketRequestPayment"
|
|
|
|
// Bucket public access block operations
|
|
// Note: DELETE uses s3:PutBucketPublicAccessBlock, matching AWS
|
|
S3_ACTION_GET_BUCKET_PUBLIC_ACCESS_BLOCK = "s3:GetBucketPublicAccessBlock"
|
|
S3_ACTION_PUT_BUCKET_PUBLIC_ACCESS_BLOCK = "s3:PutBucketPublicAccessBlock"
|
|
|
|
// Bucket ownership controls operations
|
|
// Note: DELETE uses s3:PutBucketOwnershipControls, matching AWS
|
|
S3_ACTION_GET_BUCKET_OWNERSHIP_CONTROLS = "s3:GetBucketOwnershipControls"
|
|
S3_ACTION_PUT_BUCKET_OWNERSHIP_CONTROLS = "s3:PutBucketOwnershipControls"
|
|
|
|
// SeaweedFS extension: bucket quota operations
|
|
// PUT /{bucket}?seaweedfs-quota and GET /{bucket}?seaweedfs-quota
|
|
// These are SeaweedFS-specific subresources, not part of the AWS S3 API.
|
|
S3_ACTION_PUT_BUCKET_QUOTA = "s3:PutBucketQuota"
|
|
S3_ACTION_GET_BUCKET_QUOTA = "s3:GetBucketQuota"
|
|
|
|
// Wildcard for all S3 actions
|
|
S3_ACTION_ALL = "s3:*"
|
|
)
|
|
|
|
// S3 Tables action strings for policy evaluation.
|
|
// Source of truth for the operation names: the dispatch switch in
|
|
// weed/s3api/s3tables/handler.go. Keep this list in sync with that switch
|
|
// when operations are added, renamed, or removed.
|
|
const (
|
|
// Table bucket operations
|
|
S3TABLES_ACTION_CREATE_TABLE_BUCKET = "s3tables:CreateTableBucket"
|
|
S3TABLES_ACTION_GET_TABLE_BUCKET = "s3tables:GetTableBucket"
|
|
S3TABLES_ACTION_LIST_TABLE_BUCKETS = "s3tables:ListTableBuckets"
|
|
S3TABLES_ACTION_DELETE_TABLE_BUCKET = "s3tables:DeleteTableBucket"
|
|
|
|
// Table bucket policy operations
|
|
S3TABLES_ACTION_PUT_TABLE_BUCKET_POLICY = "s3tables:PutTableBucketPolicy"
|
|
S3TABLES_ACTION_GET_TABLE_BUCKET_POLICY = "s3tables:GetTableBucketPolicy"
|
|
S3TABLES_ACTION_DELETE_TABLE_BUCKET_POLICY = "s3tables:DeleteTableBucketPolicy"
|
|
|
|
// Namespace operations
|
|
S3TABLES_ACTION_CREATE_NAMESPACE = "s3tables:CreateNamespace"
|
|
S3TABLES_ACTION_GET_NAMESPACE = "s3tables:GetNamespace"
|
|
S3TABLES_ACTION_UPDATE_NAMESPACE = "s3tables:UpdateNamespace"
|
|
S3TABLES_ACTION_LIST_NAMESPACES = "s3tables:ListNamespaces"
|
|
S3TABLES_ACTION_DELETE_NAMESPACE = "s3tables:DeleteNamespace"
|
|
|
|
// Table operations
|
|
S3TABLES_ACTION_CREATE_TABLE = "s3tables:CreateTable"
|
|
S3TABLES_ACTION_REGISTER_TABLE = "s3tables:RegisterTable"
|
|
S3TABLES_ACTION_GET_TABLE = "s3tables:GetTable"
|
|
S3TABLES_ACTION_LIST_TABLES = "s3tables:ListTables"
|
|
S3TABLES_ACTION_UPDATE_TABLE = "s3tables:UpdateTable"
|
|
S3TABLES_ACTION_DELETE_TABLE = "s3tables:DeleteTable"
|
|
S3TABLES_ACTION_RENAME_TABLE = "s3tables:RenameTable"
|
|
|
|
// View operations
|
|
S3TABLES_ACTION_CREATE_VIEW = "s3tables:CreateView"
|
|
S3TABLES_ACTION_GET_VIEW = "s3tables:GetView"
|
|
S3TABLES_ACTION_LIST_VIEWS = "s3tables:ListViews"
|
|
S3TABLES_ACTION_UPDATE_VIEW = "s3tables:UpdateView"
|
|
S3TABLES_ACTION_DELETE_VIEW = "s3tables:DeleteView"
|
|
S3TABLES_ACTION_RENAME_VIEW = "s3tables:RenameView"
|
|
|
|
// Table policy operations
|
|
S3TABLES_ACTION_PUT_TABLE_POLICY = "s3tables:PutTablePolicy"
|
|
S3TABLES_ACTION_GET_TABLE_POLICY = "s3tables:GetTablePolicy"
|
|
S3TABLES_ACTION_DELETE_TABLE_POLICY = "s3tables:DeleteTablePolicy"
|
|
|
|
// Maintenance configuration operations
|
|
S3TABLES_ACTION_PUT_TABLE_BUCKET_MAINTENANCE_CONFIGURATION = "s3tables:PutTableBucketMaintenanceConfiguration"
|
|
S3TABLES_ACTION_GET_TABLE_BUCKET_MAINTENANCE_CONFIGURATION = "s3tables:GetTableBucketMaintenanceConfiguration"
|
|
S3TABLES_ACTION_PUT_TABLE_MAINTENANCE_CONFIGURATION = "s3tables:PutTableMaintenanceConfiguration"
|
|
S3TABLES_ACTION_GET_TABLE_MAINTENANCE_CONFIGURATION = "s3tables:GetTableMaintenanceConfiguration"
|
|
S3TABLES_ACTION_GET_TABLE_MAINTENANCE_JOB_STATUS = "s3tables:GetTableMaintenanceJobStatus"
|
|
|
|
// Tagging operations
|
|
S3TABLES_ACTION_TAG_RESOURCE = "s3tables:TagResource"
|
|
S3TABLES_ACTION_LIST_TAGS_FOR_RESOURCE = "s3tables:ListTagsForResource"
|
|
S3TABLES_ACTION_UNTAG_RESOURCE = "s3tables:UntagResource"
|
|
|
|
// Wildcard for all S3 Tables actions
|
|
S3TABLES_ACTION_ALL = "s3tables:*"
|
|
)
|