Manage Multiple AWS Accounts Like a Pro with Terraform

Manage Multiple AWS Accounts Like a Pro with Terraform

June 26, 2024
26 views
Get tips and best practices from Develeap’s experts in your inbox

Managing multiple AWS accounts offers several benefits: enhanced security through isolation, better cost tracking, and simplified compliance. This structure also improves resource organization and management.

The key challenge lies in managing these accounts from a central location, especially when connecting resources across accounts for tasks like data analysis. This article reviews how to work with multiple AWS accounts, offers strategies for tackling these challenges using Terraform, and provides a real-world example of connecting networks across accounts.

Working with Multiple AWS Accounts

In the first part, we will see how to use Terraform when working with more than one AWS account, and in the second part, we will look at an example of connecting two AWS networks located in different accounts and regions.

Setting Up More Than One Account in Terraform

We will examine two methods for doing this. The simpler method is using AWS profiles, but it also has its drawbacks. Another method involves using an assumed role.

Method 1 – AWS Profiles:

AWS profiles enable working from AWS cli (and also from Terraform) with more than one AWS account. How does it work? When you run the aws configure command, a directory named .aws is created in the home directory. Inside, two files are created: config for non-secret settings (such as region and output) and credentials for secrets (secret key and access key).

When working with AWS in Terraform, it defaults to looking for these files and using the configuration and credentials from them. If you want to work with more than one account in Terraform or in AWS cli, you can edit these files and add additional profiles. If you open the file, you’ll see the settings saved under a profile named “default.” This means, as the name suggests, it’s the default profile. To create a new profile, add the profile name in square brackets, followed by the profile settings. Do the same in the credentials file (ensuring the profile name is identical in both files).

~/.aws/credentials

[default]
aws_access_key_id = ***************
aws_secret_access_key = ***************

[second]
aws_access_key_id = ***************
aws_secret_access_key = ***************

~/.aws/config

[default]
region = us-east-1
output = yaml

[second]
region = us-east-2
output = yaml

Next, we will create two AWS providers in Terraform, and to differentiate between them, we will give each an alias. (You can also give an alias to just one of them, making the one without an alias the default provider).

provider.tf

provider "aws" {
alias = "first"
region = "us-east-1"
profile = "default"
}

provider "aws" {
alias = "second"
region = "us-east-2"
profile = "second"
}

Now, when I want to create a new resource (or consume data), I will specify the provider within the block, like this.

resource "aws_vpc" "first" {
provider = aws.first
cidr_block = "10.0.0.0/16"
}

resource "aws_vpc" "second" {
provider = aws.second
cidr_block = "11.0.0.0/16"
}

In this example, the first vpc will be created in the first account in us-east-1 region, and the second vpc will be created in the second account in us-east-2 region.

Working with profiles is very convenient and straightforward, but it is only useful when running Terraform from your local machine. We need a solution that can work in any runtime environment (such as running from a CI process), and for that, we will use another solution.

Method 2 – Assume Role:

This solution allows us to define one of the accounts as a management account and grant it permission to manage resources in the other account. This way, we can directly connect to just one account and through it, connect to the second account and create the necessary resources.

How do we do this?

Let’s assume we are working with two accounts, one named Management, with an account ID (for example) 111111111111, and the other named Second, with an account ID of 222222222222. Log in to the second account via the console and go to IAM. Click on “Create Role” and choose “Custom trust policy.” Paste the following block there:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
},
"Action": "sts:AssumeRole"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
},
"Action": "sts:AssumeRole"
}
]
}

This creates a role that allows the account 111111111111 to assume permissions to perform actions in this account. Next, attach policies with the permissions you want to grant. You can give it full access via an administrator policy, but it is recommended to limit the permissions according to actual needs. Finally, name it (for example, ManagementRole) and save.

Now the management account can manage the second account. However, to implement this capability, we need to create a policy in the management account that grants access to this role, and attach the policy to whoever we want to grant the permission (role, user or group). The policy will look like this:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole"
"Resource": "arn:aws:iam::222222222222:role/ManagementRole"
}
]
}

Now, go back to the provider.tf file, and this time instead of profiles, use assume role.

provider "aws" {
alias = "first"
region = "us-east-1"
}

provider "aws" {
alias = "second"
region = "us-east-2"
assume_role {
role_arn = "arn:aws:iam::222222222222:role/ManagementRole"
}
}

In this method, Terraform needs the credentials only for the management account, and from the management account it can access to the second account.

We presented two methods for working with more than one AWS account. In the next article, we will see how to connect two completely private networks located in different accounts and regions. Stay tuned!

We’re Hiring!
Develeap is looking for talented DevOps engineers who want to make a difference in the world.