Previously, I answered ‘How many AWS accounts do I need?’ with:

Create however many accounts your organization needs to establish safe security and fault boundaries that enable your organization’s primary use cases and expected level of team/application autonomy.

Today, we’ll explore the tradeoffs of AWS account organization methods using an example that covers one approach to partitioning enterprise-wide and business unit-specific application delivery use cases. AWS Accounts are the strongest security and fault partition mechanism, so we need to use them judiciously to achieve our delivery goals rather than hinder them.

Update: We built k9 Security to help Cloud engineers understand and improve their AWS Security policies quickly and continuously. Check out how k9 can help you Go Fast, Safely.

Partitioning Accounts by Use Case

Enterprise Wide Use Cases

There are several use cases that every Enterprise (green) must support in their Cloud deployment, particularly for security functions. Many organizations adopt a single implementation of the use case and enforce its use across the enterprise. Each Enterprise use case gets its own account because the security requirements and data flows have important differences.

In this architecture, there are three accounts dedicated to managing enterprise-wide use cases:

Identity

Centralize the authentication of users within the organization by defining IAM users in a dedicated account and permitting those users to assume roles in other accounts. The security of the Identity account is so important that you should not deploy anything else in there and ensure only security administrators and automation have the ability to modify IAM. You can even use service control policy to disable the use of anything that is not IAM-related.

Note: Many organizations will integrate an Identity Provider like Active Directory, Okta, or AWS SSO instead of using an Identity account, but this is still a good example of use-case specific account.

Shared Services

Centralize hosting of logging, monitoring, and sometimes security services such as vulnerability and audit tools. Telemetry from AWS, infrastructure, and applications will be sent or pulled into the Shared Services account by agents deployed in other accounts. The hosted data and services will be consumed by people that may have high privileges in other accounts, but should not be able to modify operational telemetry. This account’s nickname might be “Hotel Audit” since data flows into this account, can’t be modified, and provides a critical building block for governance and compliance processes.

Delivery

The Delivery account hosts CI/CD systems that build applications and manage infrastructure. This might be the trickiest of the three. CI/CD systems operate in a position of great power. They create and manage the organization’s canonical artifacts. They also execute delivery pipelines that have privileges to read valuable secrets and change critical infrastructure and software deployments. CI/CD systems also need to be accessed by many people for legitimate reasons.

Operating CI/CD systems in a dedicated account simplifies the task of securing the function. Account-level isolation does this by enabling (forcing) you to let people interact with the application, but not the highly-trusted compute, storage, and secret resources supporting the CI/CD function that those same people might be authorized to manage in e.g. a dev environment. An alternative is for each business unit to have its own delivery account.

Runtime Use Cases

Accounts that host deployments of a Business Unit’s applications are called ‘Runtime’ accounts (blue) in this architecture. Further, this architecture uses an ‘Accounts by Delivery Phase and Business Unit’ pattern.

In this pattern, each of the enterprise’s business units gets its own set of accounts for developing, testing, and running its production applications. Some organizations will also deploy sandbox and disaster recovery accounts for each business unit as well. The accounts will have names like <org>-retail-dev and <org>-bi-prod.

Let’s analyze the effects of partitioning Runtime accounts by business unit first.

Partition by Business Unit

Most organizations have multiple business units that own major functions of the business. Provisioning a set of AWS accounts for each Business Unit preserves and enforces the existing relationships between people in the enterprise.

Here’s how splitting accounts by business unit will likely affect autonomy, safety, and cost management:

Autonomy

Business Units don’t need to agree, especially in lock-step, about how to use AWS. Architectures, deployment methods, operational practices and all of the team structures that actually do the work to delivery and operate applications may vary across business units. A Retail business unit is different from Business Intelligence, which is different from a newly acquired startup. My advice is to recognize, accept, and plan to accommodate the differences. This really helps business units co-exist and adopt AWS in harmony instead of battling over standards.

But what about ‘standards’? Standards can be a valuable tool, but be careful about what you’re trying to standardize and when you do it. If you start with the business outcome, e.g. “We’d like to identify data stores with sensitive data,” and work backwards, then you have a good chance of creating a standard that answers the question without restricting autonomy unduly.

Security and Safety

Since the IAM roles and policies are distinct between accounts, an application engineer in the Retail business unit can be given the freedom to manage AWS resources without the risk of affecting any of the Business Intelligence’s resources.

Account-level partitions also help contain compromises. Suppose a vulnerability is exploited in the new acquisition’s web application. The account-level partition prevents the web application from reading data in the Retail unit’s ‘orders’ S3 bucket, even if the webapp has full read privileges in the startup’s account and knows the bucket name. This is because accounts provide a security boundary that limits access to the resources inside it to only the IAM users/roles of that account. Cross-account access can be enabled, but must be done so explicitly.

Tradeoff: If you have many applications that needs to read and write across business units, you might get worn-out writing IAM and resource policies enabling cross-account. This is a particular risk for people adopting an ‘Account per Service and Delivery Phase’ patterns.

Cost Accounting

Tracking and managing AWS operational costs at the business unit level will be very easy in both AWS and third-party Cloud cost management tooling.

Now let’s take a look at partitioning by phase of application delivery.

Partition by Delivery Phase

Most organizations have multiple phases of application delivery and a corresponding deployment environment with names like dev, stage, and prod.

It is very helpful to deploy each environment into a separate account because each environment serves a different purpose. The primary use case of a dev environment is testing changes rapidly. The primary use of a stage environment might be testing changes promoted from dev against a large and (possibly) sensitive data set. The production environment is for customers to use.

Partitioning by phase has a number of effects on autonomy, safety, and cost management:

Autonomy

Application development teams can deploy changes and get feedback rapidly without fear of breaking downstream environments, particularly production.

Security and Safety

Varying the policies that define what permissions people have in a given environment is straightforward because IAM entities are scoped to an account. For example, the appeng role can be given permissions in the dev environment to create virtual machines or queues so they can experiment with new approaches or debug infrastructure automation code. Since the IAM role and policy defining those permissions is local to the dev account, they don’t get permissions to do the same in stage or prod. This is a great way to limit the blast radius of accidental resource deletion in the AWS console or misuse of a lost API access key by a malicious actor.

The IAM policies for each phase can also restrict access to sensitive data easily. When accounts are partitioned by phase, it’s easy to prevent people from having read access to sensitive data in production (and stage) environments by omitting that access.

Partitioning accounts by phase also demarcates audit boundaries. By default, only your production accounts can have sensitive data in them. You may choose to sanitize some of that data and make it available in another account, but that is an explicit choice that will be reflected in IAM and resource policies.

Cost Management

Partitioning by phase is also going to provide good resolution to decision makers on how much they’re spending on dev vs prod.

You can also set resource usage limits for that are appropriate for each phase. This will enable production to scale up to 200 m5.12xlarge EC2 instances should customers demand it, but limit the deployment to 50 instances in dev.

Summary

Partitioning accounts by business unit and/or phase in combination with sane IAM entity management gives many organizations controls they always wished they had in their non-Cloud datacenters. Use AWS accounts to establish safe boundaries for activities and data that enable your organization to move quickly and safely.

I hope this exploration of AWS Account organization practices has helped you understand when and why to partition activities and data between AWS accounts. This account architecture and the ‘Accounts by Delivery Phase and Business Unit’ pattern is good starting point for a lot of organizations, but it isn’t right for everyone.

I’d love to hear your thoughts and questions on these practices; hit reply!

If you’d like assistance architecting and implementing your own AWS account structure, QualiMente has a Secure AWS Account Foundation service to guide and accelerate you.

#NoDrama