Creating Accounts in AWS Orgs

In the common course of AWS usage, you'll often find yourself spinning up a new account for each workload you do - per AWS Best Practices Documentation you'll find yourself needing new accounts often.

One good thing is that this is relatively easy to do! Although there are multiple ways to do it in IaC, we're going to use Terraform.

Skip to the Repo, Marty!

Okay, here you go. This repo is what we'll use to create a brand new, ephemeral account.

GitHub - martyjhenderson/new-aws-account-org
Contribute to martyjhenderson/new-aws-account-org development by creating an account on GitHub.

Okay, so, if you pull that down, let's talk about what the pieces do, shall we?

New Account

In new_account.tf you'll find the main engine behind this.

resource "aws_organizations_account" "account" {
  name              = var.new_account_name
  email             = var.account_email
  close_on_deletion = var.delete_account
  parent_id         = var.parent_ou
}

This references four variables - new_account_name , account_email , delete_account , and parent_id and uses them to create the new account.

You also will note that close_on_deleteion can set to true here (through a variable). There's many warnings in the Registry about what this does, but for my example, I am building ephemeral accounts. These accounts are great for things such as Sandboxes or testing things. What happens is when the terraform destroy function is ran against this code, it'll destroy the account. (If you leave it to true or don't assign anything, it'll orphan the account from your organization, if it can)

Name and email are pretty straight forward - this is the email assigned to the root of the account and the name of the account in the list. These are important things to note for setting up root credentials on an account!

However, the odd one out here is parent_id. This is the ID of an OU in your account that you are assigning the account to. This means that it'll immediately have SCPs applied and you won't have to worry about manually linking your rules and policies to it. You can find the OU ID, manually, in your AWS Organization account.

ou-2ftl-1jd3v49d is the OU ID in this screenshot

Setting your variables

Because the variables are defined as variables in the other Terraform files, you will need to defined a tfvars type file - of which there is an example in prod.tfvars in the repository. Here you simply apply what you want you want the variables to be. We'll come back to this file when we deploy. You can also name the file whatever you want - call it peanutbutter.tfvars if you really want. Just remember what you named it!

The Backend

Every time Terraform is ran, it stores it's state somewhere. If you don't define it, it will store it on the local machine from which it is ran. In this one, we're defining an S3 bucket location and the dynamo table to store the key in (Pro Tip: make sure your DynamoDB table uses LockID as the index for it to work with Terraform).

More than likely, if you're running this at an organization, they have a backend policy defined somewhere and you will need to, instead, use that. In that case, you can delete or replace backend.tf with whatever is appropriate. If you don't have a backend setup, I encourage you to setup a bucket and a dynamodb table and update that backend.tf appropriately.

A side note: Credentials

For this example, you would need to have your Organization Root Account's credentials. I highly, highly encourage you don't just grab a user/keys and assign policies to do this. The most common way to do is safely is through OIDC, which you can do with things like GitHub Actions, Bitbucket Pipelines, and GitLab. Please, please don't throw around your root credentials randomly. Be sure to rotate them regularly, use SSO if you have to have them locally, and leverage secure methods.

Fire it off!

You'll need to do your standard things - terraform init and make sure your backend validates (note, you'll need AWS creds that can see that backend. If you're running local, be sure to set AWS_PROFILE appropriately.)

Then run your terraform plan except be sure to reference your variables file! The full command should look like terraform plan -var-file=prod.tfvars (or whatever you named your tfvars file). If you get a prompt asking for the variable definitions, you either forgot to define a variable or you didn't reference the file.

Your plan should look something like this

This 1 to add shows you're going to add your account to your root organization. Woo!

Time to fire it off - run terraform apply -var-file=prod.tfvars

(If you don't want to type yes you can set -auto-approve=true but be careful with that flag!)

And tada! You have a new account in the OU you picked

If you want to get rid of it, just be sure to run terraform plan -destroy -var-file=prod.tfvars and terraform apply -destroy -var-file=prod.tfvars. There you go, ephemeral account gone!

Conclusion

Leveraging a new account for POCs and new workloads is common practice, but there's not reason to not automate it! You can even use this to leverage automating VPCs and other connections into your account with other pieces referencing your account number (and a healthy use of depends_on).

Go forth! Create all the accounts you need to minimize blast radius and maximize building!