Question

Allow object operations only under a certain prefix inside a DO Space

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.


Submit an answer


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!

Sign In or Sign Up to Answer

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.

Bobby Iliev
Site Moderator
Site Moderator badge
May 13, 2025
Accepted Answer

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 allowing ListBucket 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

alexdo
Site Moderator
Site Moderator badge
May 13, 2025

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!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.