AWS Storage Blog
Design patterns for multi-tenant access control on Amazon S3
Large organizations and software as a service (SaaS) platforms often share storage resources across multiple users, groups, or tenants. The design pattern chosen to implement this shared storage can significantly impact how access permissions are managed at scale. This decision is key because it directly affects platforms’ security and ease of scale. A well thought design choice leads to easier management of user permissions, improved data isolation, security and operational efficiency. Conversely, misaligned design decision may result in potential security vulnerabilities, or challenges in maintaining and scaling the system as the number of users or tenants grow.
Amazon S3 provides the foundation for secure multi-tenant storage implementations. Through comprehensive access control mechanisms, organizations can enforce strict isolation between tenants while maintaining operational efficiency. On top of using dedicated or shared S3 buckets, using features such as S3 Access Points and S3 Access Grants enable you to implement robust security controls that scale with your business requirements.
In this post, we examine several design patterns for maintaining data isolation, consistent access control, and comprehensive monitoring, while also highlighting the trade-offs of each approach. We start by looking at the challenges of implementing multi-tenant storage solution. Then, we explore three key design patterns for managing access to Amazon S3: Using a dedicated S3 bucket per tenant, using a shared bucket with prefix-based isolation, and using S3 Access Points. Finally, we introduce the concept of a “session broker” using Amazon S3 Access Grants. Throughout the post, we provide IAM policy examples and architectural diagrams to illustrate the key design patterns and considerations. By the end, you will have a better understanding of the tradeoffs involved in implementing secure and scalable multi-tenant storage solution on Amazon S3.
Challenges of building multi-tenant storage solutions
When architecting multi-tenant storage solutions, organizations face several key challenges that impact security, scalability, and operational efficiency. Some of these challenges are:
- Data isolation: ensure complete tenant data segregation while leveraging centralized storage infrastructure. This requires implementing security controls that prevent cross-tenant access while maintaining operational efficiency.
- Identity management and authentication: design authentication mechanisms that scale to support millions of users with different access patterns. This includes integrating with identity providers and implementing fine-grained authorization.
- Access control: implement least-privilege access policies that provide granular control over storage resources. These policies must support tenant-specific requirements while maintaining security best practices across the platform.
- Operational scale: handle growing complexity as tenant count increases. This includes managing IAM policies, bucket configurations, and access patterns without introducing security vulnerabilities or degrading performance.
- Visibility and governance: maintain comprehensive audit trails and monitoring capabilities across tenant activities. This enables quick detection of security events and ensures compliance requirements are met at scale.
Let’s examine a few architectural patterns that help address these challenges using Amazon S3 as the foundation for multi-tenant storage.
Data isolation design patterns
In this section, we explore three key design patterns for managing access to Amazon S3 storage:
- Using a dedicated S3 bucket per tenant
- Using a shared S3 bucket with prefix-based isolation: This method allows you to host thousands of tenants within a single bucket, while still maintaining data segregation. We will cover how to use bucket policies and IAM user policies to control access.
- Using Amazon S3 Access Points: This approach provides a more scalable and dynamic way to manage permissions, where each access point can have its own customized policy. We will dive into the mechanics of how access points work and how they can be used to simplify multi- tenant access control.
Using a dedicated S3 bucket per tenant
All customer accounts now have a quota of 10,000 buckets, with the capability to request a quota increase up to 1 million buckets. This can make it easy to opt for a single S3 bucket per tenant approach. Using dedicated bucket per tenant provides strong natural isolation boundaries and clear access control management. You can manage each tenant’s data and configurations independently, making it easier to implement tenant-specific requirements like encryption, audit, S3 Lifecycle policies, or cross-account access.
This approach also allows for clearer cost allocation and usage tracking per tenant. Although this approach offers simplicity, it may not be the most suitable choice for large-scale multi-tenant applications or applications with complex data management requirements. Some of the challenges associated with bucket per tenant are:
- Management overhead: Tasks such as monitoring, logging, and applying security policies need to be managed across multiple buckets, potentially leading to increased complexity. It also mandates IaC (Infrastructure as a Code) procedures to provision/modify/remove tenant resources and configurations.
- Cross-tenant access: Having multiple buckets means managing access, logging, and alerts per bucket. This creates a challenge to co-ordinate access logging and alerts, as compared to other approaches described in the post.
- Query complexity: If you need to query across multiple tenants or perform operations that involve aggregating data from multiple tenants, then having data partitioned into separate buckets can introduce operational complexity overhead because of the need for cross-bucket operations.
Use a single S3 bucket per tenant when strong data isolation, simplified access control, and clear tenant boundaries are top priorities, and the number of tenants is manageable; however, as the tenant count grows into the thousands or tens of thousands, one should consider alternative approaches to mitigate increased operational complexity and management overhead.
Using a shared S3 bucket with prefix-based isolation
Many organizations find that a shared bucket approach may offer better scalability and manageability.
Let’s explore how these kinds of solutions work.
One approach to overcome the challenge of managing multiple tenants’ data is to use a shared bucket and segregate each tenant’s data by prefixes within that bucket (for example shared-bucket/tenant-a/, and shared-bucket/tenant-b/). This method allows you to hold thousands or more tenants under the same bucket while still maintaining each tenant’s data under a dedicated prefix with the necessary access controls. Having the ability to create thousands and more of prefixes within a single S3 bucket provides flexibility and scalability when implementing a multi-tenant storage solution.
The shared bucket approach has several caveats. These primarily relate to bucket configurations and quotas that cannot be limited or scaled down to individual prefixes or tenants. S3 Versioning is one example – since it’s a bucket-level configuration, it applies to all tenants even when you might want different versioning settings for different tenants. Another example would be the maximum of 1,000 Lifecycle rules along with limitation such as max number of replication rules. You should carefully consider these limitations when pursuing this approach.
When working with a shared bucket, the resource policy is usually the starting point for managing and isolating data access. Data access management should be handled accordingly, making sure that each tenant’s data is properly secured and accessible only to authorized parties. In the following sections we explore a couple of options.
The following naïve example demonstrates a bucket policy that explicitly allows different tenants access to their data only:
However, managing and updating the bucket policy at scale, when using a single S3 bucket, quickly becomes complex. Hitting the bucket policy size-limit in a multi-tenant environment becomes an issue, and extra care should be taken when making changes to the policy because it is shared across tenants in the bucket.
One method to avoid hitting the policy size-limit is using AWS Identity and Access Management (IAM) variables that reference the calling principal.
The following is an example of a bucket policy allowing access between a user and their dedicated S3 bucket prefix using IAM user policy. Observe the strong binding of the user name and user prefix. You can find more details in the IAM documentation.
This approach is still limited because of account users-limits and when requirements are more versatile than allowing a specific user access to their directory in the shared bucket. Modern applications and multiple AWS services use roles as opposed to users, because roles offer a more versatile approach. Furthermore, organizations can have more employees than user quota in the account.
Use a shared S3 bucket with prefix-based isolation for scenarios with a moderate number of tenants and static user-to-prefix mappings, keeping in mind bucket policy size limits; for larger scales or more dynamic access patterns, consider advanced options like Amazon S3 Access Points or Amazon S3 Access Grants to overcome these limitations and provide more flexible, granular control.
Using Amazon S3 Access Points for tenant isolation
As organizations grow and the number of applications and users increases, managing access to shared datasets becomes cumbersome. There is a need for a more direct method of statically mapping users and teams to their respective dataset in the shared bucket.
As we move towards more sophisticated access control patterns, Amazon S3 Access Points provide an elegant solution that combines the benefits of shared storage with granular access control.
They address the need for separate access policies. These policies, like bucket policies, can be for a user or a group of users. The approach allows changes made to a specific policy to remain isolated to its associated dataset within a shared bucket. Let’s take a look into how this works.
S3 Access Points direct data access for any user, AWS service, or user application that stores data in S3. They are network endpoints that are attached to buckets, and each has distinct permissions and network controls that S3 applies for any request that is made through that access point.
Figure 1: Amazon S3 Access Points Illustration – providing fine grained policy per team
Each access point enforces a customized access point policy that works in conjunction with the bucket policy that is attached to the underlying bucket. The principal policy (IAM policy) defines the allowed actions that a principal (user, role, or application) can perform on the resource. The access point policy (and the bucket policy) defines the resources that the principal can access and the actions they can perform on those resources.
In S3, the principal and resource policies are evaluated together to determine access permissions. When a principal attempts to access an S3 resource, both the principal policy and the resource policy are evaluated. The principal must have the necessary permissions granted by both policies to gain access to the resource.
In the context of S3 Access Points, the access point policy acts as another layer of security and control on top of the bucket policy. Although the bucket policy applies to the entire bucket, the access point policy allows you to define granular permissions specific to that access point.
Figure 2: S3 Access Point IAM evaluation – User, access point, and resource policy are evaluated together
Example
We have a shared bucket, ”my-bucket”, that holds multiple tenants’ objects, and each object resides under the respective tenant’s prefix:
my-bucket/tenant-a/object-a my-bucket/tenant-a/object-b .... .. my-bucket/tenant-n/object-a my-bucket/tenant-n/object-b .... .. my-bucket/tenant-n/object-n
The following is an example structure for allowing “tenant-a” access only to their data residing inside the bucket under their designated prefix using an access point.
One best practice would be to delegate access control from the bucket level to the access point level. Either the bucket owner, or a delegated account can own the access point.
The preceding bucket policy should be coupled with a strict S3 Access Point policy, as follows. You can observe a further example in this S3 User Guide.
Then, we add an access point with the following policy. The preceding permissive policy isn’t recommended on its own without the following access point policy.
In the preceding IAM statement example, we allow access to all objects in the bucket that “tenant-a-ap” is attached to (“my-bucket”). We can be more granular and give access to one or more prefixes or objects, as described in the following example:
The access points allow access to multiple resources, and they are dependent on the assigned policy (and as mentioned previously, evaluated together with the principal’s policy). Therefore, you should keep this in mind when allocating permissions inside the AP policy.
The outcome of the preceding setup is explicit permission for the principal (tenant-a-role) to access only tenant-a data through a dedicated access point (tenant-a-ap). This provides better isolation and security.
When we need to change the access pattern for tenant-a-role to tenant-a data we need to change only the access point policy and no other tenant is affected.
You can now repeat this iterative process and create an access point for a tenant, user, or group, as you need. This scales well for static configurations to the tens of thousands of tenants, while maintaining a manageable bucket policy.
A few important notes for S3 Access Point implementation:
- Application design using bucket style alias will support faster and easy integration with more AWS Services.
- Observe the special Amazon Resource Name (ARN) structure when working with access points. You can learn more about it in this S3 User Guide.
- Remember that access to data using S3 Access Points involves evaluating the policy of the principal and that of the S3 Access Point. Therefore, it is recommended to manage the policies from where you determine which policy is more hardened, and which is the one where you tend to make changes when needed (preferably the access point policy).
- A principal with a permissive policy (for example allowing s3:* on a bucket) might give that principal access to more data than listed in the AP policy.
S3 Access Points method balances the need for data isolation with the efficiency of a shared storage infrastructure, making it particularly suitable for organizations with well-defined team structures and data access patterns.
The case for session broker: Amazon S3 Access Grants
While S3 Access Points solve multiple challenges, modern organizations often need even more dynamic and identity-aware access control. For example, what happens when a user is a member in multiple groups with different permissions? Or what if users change teams frequently and their access permissions change as well? This is where the concept of a session broker becomes valuable.
IAM roles and access points provide a good method for managing static mapping at scale with the necessary guardrails. However, this may not be sufficient when handling complex access control patterns that need an external identity provider. As these use-cases grow larger and access requirements become more diverse, the static mechanisms of IAM roles and access points become insufficient.
Furthermore, users are looking for methods to associate data access with their identity provider users and groups.
Building a robust session broker needs significant custom development effort, which leads us to develop Amazon S3 Access Grants to provide that session broker service for these kinds of patterns.
Figure 3: Design pattern for a session broker (S3 Access Grants)
The motivation and need for a session broker:
- Mapping users/groups to data paths: Applications need to map authenticated end-users or roles to specific dataset paths to which they should have access. This dynamic mapping is difficult to express directly in IAM roles or resource policies (of both the bucket and access point).
- Dynamic access requirements: Access requirements can change as user’s change or move teams, and new projects start. IAM roles and access points may need to adapt quickly to these changes. These changes need to be reviewed and adjusted accordingly.
- Scale of mappings: With many users, groups, and data paths, the combinations become too complex for pre-configured IAM policies to handle.
The session broker pattern addresses these challenges by providing a separate application component that makes access decisions in real-time for each user or role request. It works by obtaining short-term, scoped STS credentials from the broker, which evaluates the user’s access privileges based on the principal/prefix access privileges defined. This allows implementing complex access mapping logic in a central, scalable component, rather than in static policies configurations.
The session broker model offers multiple benefits such as the ability to centrally manage and update access logic, the use of short-lived and minimally-privileged credentials, and the scalability based on credential vending rate (serving the clients at scale in a timely method).
Figure 4: S3 Access Grants – providing IAM and IdP users temporary credentials for accessing resources in the bucket
S3 Access Grants was introduced with the goal to address the challenges that organizations face in managing complex access control for large data lakes or complex access pattern needs stored in Amazon S3, such as permissions to end-users based on their corporate identity. S3 Access Grants provides a more intuitive method for expressing the mapping of users or groups in the organization’s IdP/Directory to specific datasets, without having to implement this logic directly in application code or to build your session broker.
It offers the ability to audit end-user access to data, going beyond logging the application role used to access the data. When using Identity providers, S3 Access Grants integrates with AWS IAM Identity Center to understand the identities of end-users from corporate directories based on group membership alongside IAM roles and users. This gives organizations flexibility when it comes to mapping principals to data-sets dynamically.
When an application needs access, it can request temporary, scoped credentials from the S3 Access Grants service. Then, this propagates the end-user identity through the session broker access flow, while saving the session record in AWS CloudTrail logs.
S3 Access Grants works on top of and integrates with existing IAM bucket policies, access point policies, and other access control mechanisms. It provides a simplified method for managing data access permissions at scale, while maintaining a consistent and auditable approach to mapping users to datasets across applications.
Conclusion
As seen throughout the blog, multi-tenant or user-storage architecture on Amazon S3 offers several implementation patterns to suit the organization architectural needs. Each approach provides distinct tradeoffs: bucket-per-tenant delivers strong isolation but requires careful management at scale, while shared buckets with prefix-based segregation optimize resource utilization through centralized management. For more dynamic needs, S3 Access Points provide scalable solutions for static access patterns, and S3 Access Grants enable granular, short-lived, identity-aware access control that adapts to evolving organizational changes and structure.
Understanding these tradeoffs enables organizations to build secure, scalable storage solutions that directly address key business challenges. With proper implementation, you can support millions of users while maintaining data isolation, reduce operational overhead through centralized management, and ensure comprehensive audit capabilities across all access patterns. This becomes particularly valuable for SaaS platforms and large enterprises, where implementing the most suitable access control patterns while maintaining tenant-specific isolation controls is crucial.
For more details, explore the S3 User Guides on S3 Access Points and S3 Access Grants. To learn more about these patterns in action, check out the following blog posts:
- Scaling data access with Amazon S3 Access Grants
- How to develop a user-facing data application with IAM Identity Center and S3 Access Grants
You can also watch the re:Invent 2023 breakout session recording: