In one of the recent posts I mentioned how we are using AWS Organizations to manage multiple environments in multiple AWS Accounts. There is a lot of literature and discussions available online to justify this being a best practice, and it all boils down to simple things which matter the most - unified billing of resources, and separation of concerns. After all, no body wants to accidentally test a feature in a prod CIDR range.
Previous to the last week, I also explored AWS Amplify to accelerate the frontend development using React. The advantage broke quite a few beliefs about cherishing the favourite tech stack for “everything”. This resulted in viewing the architecture into 3 main parts - frontend, backend components supporting frontend, and backend.
This post takes this discussion further with respect to providing appropriate developer access in target environments. It will help teams who are struggling with this topic and act as a resource to those for whom IAM is in a state of mess.
Who is a developer?
Let us revisit this question to better understand the role. Simply put, developer is any individual who actively contributes to the code base, to build a component or an end-to-end service, that supports any business application.
In a broader sense, developers are not only those individuals who “develop” code, but also those who are responsible for testing, operationalising, and enhancing the same for automation purposes.
These individuals typically require full access to one of the environments where they can test new code without any worry. Such environments are also known as sandbox or development environment.
There are arguments about implementing the principle of least privileges in larger teams - which I do not oppose. However, for smaller teams or startups, it is a bit rich to worry about it initially. Having a separate AWS Account instead to manage development activities addresses most of the concerns, and any mishaps are easily traceable.
AWS Accounts and User Accounts
When multiple AWS accounts are created using AWS Organizations, an OrganizationAccountAccessRole is automatically created in the child accounts, which grants full admin access. It is also possible to create a custom role for the same, perhaps for higher environments which demand principle of least privilege to be followed.
AWS IAM allows users to “Assume” a specific role in a target AWS account without actually having any account created for them. Depending on the level of permissions assigned to the assumed role in target account, the user assuming the role enjoys same privilege while assuming that role. In our case, the OrganizationAccountAccessRole is allocated Administrator privileges in all the environments.
As seen in the diagram below, the root AWS account manages the Dev, QA, and Prod AWS accounts, where corresponding environments are hosted.
To keep IAM clean, we create all the user and service accounts in the root AWS account so that it would be easier to manage all of them from a single place.
Developer accounts are those which are allocated to the individuals, while service accounts are the ones used by DevOps or automation tooling. Service account typically require only programmatic access.
Every account created in AWS has a corresponding ARN (Amazon Resource Name) which is a unique identifier and is in a format that is interpreted by AWS and humans alike, to know the whereabouts of that AWS account. The ARN is also allocated to all other AWS resources as well.
Each account is also associated with Access Key and Secret Key which users and service accounts use to authenticate themselves against the root account.
Establishing trust with AssumeRole
Any developer who has successfully authenticated against the root account, needs to assume a role in target AWS account, where they are supposed to interact with the resources.
As discussed earlier, every child AWS account has Organization Access role, or a custom role which may be created, can be assumed by developers to perform their tasks. Assuming a role can take place via multiple ways - AWS CLI, 3rd party tools, SDKs, etc. Thus, this path to authenticate and authorise is universal in nature.
To enable developers to make changes in Dev account, establish a trust relationship by adding the developer account’s ARN in the OrganizationAccountAccessRole as trusted entities. This needs to be done by the Dev account’s specific admin user manually. Once this is done, every time that particular developer tries to assume the role for Dev account, they are allowed to do the changes.
Similarly, if the developer tries to assume another role (QA, or Prod), where such trust relationship is not established, then the access is denied. The same is reflected in the diagram above.
Conclusion
AWS AssumeRole function makes it easier at the same time also makes a lot of sense to manage access in such a complex environment. These are the basic rudiments which have to be in place as the complexity of the projects grow tenfolds.
This model till now has been of great help and relief as far as managing access and avoiding accidental changes to higher environments is concerned. Many organisations follow a similar access management strategy, but there are teams who do struggle with this.