I’m trying to use the bucket policies to allow certain operations only if they are performed under a certain prefix.
Unfortunately it seems like the support for prefix conditions in DO Spaces is broken/only partially implemented. It seems like it is not possible to prevent operations from the root of the bucket while allowing them on a prefix.
For example I wish to apply a policy like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:ListBucket",
],
"Condition": {
"StringLike": {
"s3:prefix": "????????-????-????-????-????????????/*",
},
},
"Resource": "arn:aws:s3:::my-bucket",
},
],
}
The idea here is that of multi-tenacy: I assign one UUID to each “client”, they should be able to list the objects available under their own context by specifying the UUID as prefix, however they shouldn’t be able to list objects from the root of the Space by omitting Prefix
or specifying an empty Prefix
string. AWS S3 given this policy will return AccessDenied
for any ListObjects
operation that either doesn’t provide a Prefix
or for which the Prefix
does not start with a UUID plus /
, which is what I want.
Currently this policy is accepted by DO Spaces, but no error is given if trying to call ListObjects
without a Prefix
parameter and it does return all objects from the root.
Switching from Allow
to Deny
seem to work, in the sense that I can list from the root, but trying to specify a Prefix
matching the condition fails with AccessDenied
.
I tried to then use Deny
+ StringNotLike
:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:ListBucket",
],
"Condition": {
"StringNotLike": {
"s3:prefix": "????????-????-????-????-????????????/*",
},
},
"Resource": f"arn:aws:s3:::{name}",
},
],
}
This “works” in the sense that it does allow ListObjects
specifying a Prefix
using a UUID as prefix, it prevents specifying a different non-empty prefix (e.g. trying a
as Prefix
fails with AccessDenied
), but crucially it still allows an empty or missing Prefix
argument to list all objects from the root!
Is there a way to write a DO Spaces policy that would achieve what can be done in AWS S3 with the first policy listed here? I.e. only allow ListObjects
if a Prefix
is provided and that Prefix
matches the given condition?
Moreover is there some Spaces-specific documentation for the supported conditions in a Bucket Policy (since the behaviour is different from AWS S3)?
Note that this is not restricted to s3:ListBucket
permission and ListObjects
API. It seems like all permissions don’t really work well with prefixes. To give a different example, if you want to limit s3:GetObject
to fetching object under a prefix it doesn’t work:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
],
"Resource": f"arn:aws:s3:::my-bucket/prefix/*",
},
],
}
This will still allow calling GetObject
outside the given prefix. Switching to using Deny
will correctly deny operations for the specified prefix, but there seem to be no way to allowing the operation only in a prefix, you either prevent the operation completely or it is always allowed from the root.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.
Hey!
I think you’re right that this doesn’t fully work as expected in Spaces. From what I’ve seen, even though the platform accepts S3-style policies, conditions like
s3:prefix
don’t seem to be properly enforced. So things like allowingListBucket
only under a certain prefix or blocking root-level access don’t behave like they would on AWS S3.There’s no official list of supported condition keys, but here’s the API reference: https://docs.digitalocean.com/reference/api/spaces/
If this kind of fine-grained control is critical, it might need to be handled at the app layer, or consider submitting this as a feature request here: https://ideas.digitalocean.com/
- Bobby
Heya @f5aa01f2dc09435f8c123c941640ef
If you need dynamic access, implement a simple API endpoint in your app that generates valid pre-signed URLs on demand after validating the client’s UUID and permissions.
You can use
boto3
to share quick pre-singed URLs. This URL can be safely shared with clients and will expire automatically after 1 hour (or whatever time you set). They don’t need any credentials to use it!Hope that this helps!