Setting Up Object Storage Access Policies (IAM/Bucket Policies)

Excessive access rights to object storage are a typical cause of leaks and endless approvals within a team. We set up strict access policies turnkey: inventory, role-based segregation, closing public paths, and transfer of regulations to your specialists. We speed up access issuance and verification many times over, and remove excessive rights completely.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Excessive access rights: where S3 IAM policies break

Rights granted for a task “temporarily” are almost never revoked. A service account is granted s3:GetObject on the entire bucket to export a report once: the report is delivered, the task is closed — but the rule remains in the policy.

After several releases there are dozens of such “temporary” entries, and no one remembers what each one is for.

Ordinary monitoring will not catch this: it looks at response codes, latency, and availability, while excessive access produces neither errors nor spikes.

Requests are valid, responses are successful, graphs are flat — no alerts, even though data has long been read by someone it was not intended for. Public access to objects is dangerous precisely because of this: the storage operates normally, but the failure has already occurred.

Breakage occurs in three common places. A wildcard in Resource or Action — the policy looks narrow by name but covers the entire bucket. No Condition on the request source: the rule is tied neither to a network nor to a specific role.

And an ACL at the individual object level that expands access contrary to the bucket policy if no explicit deny is set anywhere.

This is treated not with a one-time cleanup but with an operating model: least privilege plus regular audit of access to storage — comparing granted rights with those actually used according to access logs. We explain how to set this up so that “temporary” stops becoming permanent.

What stops breaking after strict access policies

An explicit deny in a bucket policy overrides any permission, so the perimeter is first closed entirely, and access is granted selectively. A bucket policy is responsible for what can be done with objects: by prefix, from which networks, only over a secure channel.

IAM rules determine who can access it. While the levels are mixed, rights hang on the account rather than on the role.

Failure class How it arose What changed after policies
Access persists after termination rights on a personal account role removed from the group — access closed
Data leaves the closed perimeter public access flag on an object public access prohibited at the bucket level
Reading of others’ prefixes one broad policy for everyone access granted by prefix and role

Granting access becomes a minutes-long operation: the role with the required set of rights is described as code in Terraform; it only needs to be assigned to an employee.

Revoking rights upon termination is one removal from the group; both long-lived keys and temporary tokens are closed. Changing an employee’s role within the team no longer requires a new request: rights are reassembled during the transfer.

The share of data in the closed perimeter grows not through manual checks but because public access is prohibited on the bucket itself and cannot be bypassed with an accidental flag.

The following disappear entirely: reading others’ prefixes, access after termination, an object publicly accessible due to a script error.

Access control approaches: comparison of options

Access control in object storage is addressed at four levels — from provider IAM policies to your own check before issuing a link. The choice depends on who requests the object: an internal service, an external partner, or the end user’s browser.

No single level solves the task entirely. Provider rules do not know your business logic, and your own check does not protect against bypass via a direct address. Therefore, levels are combined: a rigid foundation below, targeted exceptions above.

Option When it fits Limitations
Provider rules (IAM) Service accounts within the platform, read or write access as a whole No application context; rights are distributed in broad groups
Bucket-level rules Public or partner exchange, one set of conditions for the entire container Granularity down to an individual object is limited; isolation is achieved by splitting buckets
Object-level rules and temporary file links Issuing a file to a specific user for a short period without exposing keys A link cannot be revoked before expiry: if leaked, it works for anyone
Your own authorization layer before issuing a link Roles, owners, tenants, audit of every request An additional service in the critical path — fault-tolerance capacity is needed

How to choose a level

If a rule is described by a single condition, keep it on the provider side. If the decision depends on data in your database, move the check to your own layer and make the temporary link short-lived.

Implementation procedure: from inventory to handover

We start with facts, not a template: inventory shows who actually accesses the storage — services, analytics, external contractors. Without this map, the role scheme is built at random, and switching policies turns into searching for failed access in logs.

  1. Access rights inventory. We export current bucket policies, IAM roles, public ACLs, and active object links, and compare them with access logs. The output is a map of “who, to which bucket, which operations” and a list of redundant permissions.
  2. Role scheme. We design roles for functions — analytics reading, service writing, exchange with a contractor via a separate prefix — not for specific people. Each role has a minimal set of actions and a condition of use.
  3. Policy configuration. Restriction by prefixes, condition on the request source, mandatory encryption, prohibition of public access. An explicit deny overrides accidentally granted permissions.
  4. Testing on a data copy. A test environment on an anonymized copy: we run read, write, delete, and link generation. Separately, negative checks: access is closed where it should be closed.
  5. Migration without downtime. Old and new policies run in parallel; we switch service by service with an observation window based on failure logs. Each step is rolled back by restoring the previous configuration version.
  6. Regulations. We record who grants access, for what term, how review is performed, and what to do upon termination or contractor change. Rules are stored in the repository; changes go through review.
  7. Handover. Documentation, role schemes, configurations in the repository, and monitoring of access failures — so the team can continue independently.

What you keep: configurations and regulations

We transfer not an archive of settings but a working access perimeter that your team can read and change without us.

Configurations of IAM policies and bucket policies are stored in the repository alongside infrastructure code: a change goes through review and remains in history — you can see who expanded rights and when.

  • Access matrix — a table “subject → resource → action → condition”: it shows why a specific service or employee has rights to the required bucket prefix and where the boundary of their authority lies.
  • Role scheme — which roles exist, how they differ, which are issued to people through federation and which to services; roles with the right to change policies themselves are marked separately.
  • Working configurations — versioned policy files with meaningful names and comments instead of console exports.
  • Rights granting regulations — procedure: request, approval by the data owner, validity period, automatic revocation; for permanent roles — periodic review.
  • Access documentation — bucket names, entry points, credential rotation procedure, and typical access errors.
  • Integration description — which systems access the storage, with what rights, and what will happen to them when the policy changes.
  • Verification procedure — the set of requests that should pass and the set that should be denied.

The result is a managed system, not a one-time setup: access for a new contractor is granted according to regulations, and during incident investigation there is a change log and a clear rollback point.

Case study: how public access to object storage was closed

What it was before the changes

The audit began with inventory: we went through all buckets in all accounts and compared bucket policies, ACLs, and public access block settings.

The result: 17% of buckets served objects anonymously; some were opened for a quick launch and not closed, others when contractors were given “temporary” links.

A separate problem was inheritance: editing one bucket’s policy imperceptibly opened neighboring ones, and in the S3-compatible storage MinIO this was caught only by manual comparison.

Processes added their own issues. Rights were granted via tickets: 2–3 days from request to working access, and revocation upon termination dragged on for up to a week — keys remained active the entire time.

Support received several dozen requests per month just for access, and half were “give me the same as my colleague.”

What was changed and what was achieved

Public exposure was closed at two levels: public policy blocking was enabled on the account, and for services with a real external audience, targeted conditions were left — an explicit list of sources and a short link lifetime.

Rights were moved to roles with attributes: access is determined by user and bucket tags rather than manual enumeration. A new team receives the required set automatically; when a role changes, old permissions are removed along with the tag.

Granting was made self-service through a role catalog. Metrics afterward: the share of anonymously accessible buckets is zero, a full rights audit takes one script run instead of a week of manual comparison, and access-related support requests decreased fivefold.

How S3 IAM policies differ from bucket rules

Object storage, such as Amazon S3, has two independent access levels. An IAM policy is attached to a subject — a user, role, or service account — and determines what that subject is allowed to do: which actions and on which resources.

A bucket rule is attached to the bucket itself, contains a reference to the subject, and describes the other side — who accesses the data from outside, including other accounts.

When they overlap, the models combine by logic: allowed if allowed somewhere, denied if denied anywhere.

Permissions are combined, and an explicit deny has the highest priority: a single Deny in an IAM policy or bucket rule overrides any number of Allows, including those granted through a group. This is the deny precedence — a barrier that cannot be bypassed by adding a new permission.

Hence the practical separation. Within a single account, IAM roles are sufficient: teams and internal services gain access through a role, not through static keys.

A bucket rule is needed where access comes from outside — a partner account, an external service, static content delivery. In a mixed scheme, organization-level restrictions serve as an upper boundary that neither model can expand.

We configure starting from denies: first we close public access and export without channel encryption, then we add permissions by prefixes and roles.

Failure analysis follows the same order — IAM, bucket rule, organization restrictions; most often access is blocked not by a missing Allow but by an explicit Deny in one of the layers.

Technical concerns about access control

Concerns about access control usually relate not to the policy itself but to how it will coexist with already working integrations and what will happen if there is an error in the rules. Below are five technical questions most often asked before starting.

Will the new IAM policy break existing integrations?

First we capture current requests and build a map: who accesses which prefixes. Then we issue explicit permissions and enable default deny — a service not included in the map fails during testing, not in production.

Can access be granted to individual objects rather than the entire storage?

Yes: a policy describes both prefixes and specific keys. For targeted granting, we allow one object; for selections, a prefix with a condition on the name. The contractor receives exactly the files needed.

How can access be given to external contractors without distributing a shared key?

For external parties, we issue a separate user or role with restrictions by term and IP range. Access is revoked with one edit, and the request history remains in the logs.

How can you verify that the rules work exactly as intended?

After applying, we run scenarios: service keys, contractor keys, an anonymous request, a request to a neighboring prefix. The expected response — allowed or denied — is recorded so that regressions are caught on the next change.

What will happen to the data if the rule revokes the necessary rights?

The data will not be affected: only the response to the request changes. Rollback is restoring the previous policy version; it takes minutes, with no re-export or re-upload of objects.

Let’s discuss your task: storage access control

Estimating storage access work is based not on a general description but on the actual state of the policies.

Until it is clear who reads data today and through which role, any timelines will be guesswork — so we ask you to send several artifacts, and based on them we build a plan:

  • an export of current rules: bucket policies, IAM policies for roles and users, and ACLs if they are still in use;
  • a storage map: buckets, their purpose, which datasets and how sensitive they contain;
  • a list of services and applications indicating the roles under which they access the storage, including external integrations;
  • access control requirements: who needs access and to which prefix, where restrictions by network, time, or request source matter;
  • access logging settings: where access events are written and how long they are stored;
  • constraints on your side: maintenance windows, approval procedure for edits, who confirms changes in production.

In response, we come back with an implementation plan: an access inheritance scheme, role separation for the real tasks of services, ready policy drafts alongside the service configuration, and a rollout procedure with rollback points.

The first step takes little time and immediately produces a result:

  • Inventory: we consolidate all rules into a single table “who — what — from where”.
  • Recording excessive accesses and places where rights are broader than necessary.
  • Setting up logging and a test environment where edits are verified without risk to production.
  • Handover of the implementation plan and approval of the rollout procedure.

Describe your task and attach what you have at hand — we will come back with an estimate and a plan.