I wrote this code in a quick and dirty way, just to send it to a few companies that were trying to decide between the age-old AWS Control Tower
v.s. Landing Zone
v.s. AWS Deployment Framework vs. Terraform
vs. Other
debate.
You should be able to understand this code within a day or two, and not have account creation be much more complicated than say, S3 bucket creation.
If you look at e.g. AWS Control Tower Account Factory for Terraform I am sure you will not be able to understand it all within a day or two, nor customize it easily to your heart's content.
There are more details below, but at a high-level:
- Creates an account
- Writes Terraform file under
aws-organizations/accounts/
- Outputs the
terraform import
command needed to import the generated Terraform file.
python -m create_aws_account --help
usage: create_aws_account [-h] --account_type ACCOUNT_TYPE --data_classification
DATA_CLASSIFICATION --project PROJECT --description DESCRIPTION
[--ou DESIRED_OU]
Creates an AWS account, writes Terraform and gives import command
options:
-h, --help show this help message and exit
--account_type ACCOUNT_TYPE
Specify the Account Type (Production/Development/Sandbox)
--data_classification DATA_CLASSIFICATION
Specify the Data Classification (Public/Internal/Confidential)
--project PROJECT Specify the Project
--description DESCRIPTION
Give a one-liner about the account.
--ou DESIRED_OU Give a valid OU (parent_id) for the account.
This creates 2 folders with generated Terraform in them that each call a respective module.
One is an SCP baseline, which will be applied in the context of your management account. The other is a configuration baseline, which will be applied in the context of the subaccount.
See subaccounts/smoky-production
as an example.
python -m generate_subaccount_tf --help
usage: generate_subaccount_tf [-h] [--only-scp-baseline] [--only-configuration-baseline]
--account-name ACCOUNT_NAME
Creates baseline Terraform using 2 different modules
options:
-h, --help show this help message and exit
--only-scp-baseline Only generate SCP baseline
--only-configuration-baseline
Only generate configuration baseline
--account-name ACCOUNT_NAME
Give a valid account name.
This does the following:
- Creates the AWS account with a name of
{args.project}-{args.account_type}
(will append-2
if there is already an account with that name,-5
if there are 4, etc.) The name of the - Add tags of
"account_type"
,"data_classification"
,"project"
,"description"
- In all regions enables EBS encryption by default and deletes all default VPCs
- Edits the
admin
role trust policy to include thests:SetSourceIdentity
permission - Adds the managed
IAMFullAccess
,ReadOnlyAccess
,SecurityAudit
,ViewOnlyAccess
policies, and a customEnableS3AccountPublicAccessBlock
policy, toadmin
role - Remove
AdministratorAccess
(* on *
) fromadmin
role - Moves new account to the given OU, if one was given.
- Writes Terraform / displays
import
instructions
All this code is straightforwardly read from __main__.py which is only 100 lines of code.
Note: We need to change ADMIN_NAME
in constants.py if you do not want admin
to be the name of the role made upon account creation. (This defaults to OrganizationAccountAccessRole
, a mouthful, if left unspecified.)
The scps
baseline module will turn on a bunch of account-specific SCPs by default (the variables.tf of the module are a bunch of bool values)
Any SCP inheritance can be leveraged separately, by specifying a parent_id
argument to the aws_account
module (example).
The configuration
baseline module will just setup IAM roles and turn on aws_s3_account_public_access_block
The only import
necessary, is that of the admin
IAM role. As it is automatically made upon account creation and we have to use it to get into the account in the first place.
Note: This assumes you setup GuardDuty and CloudTrail at the org-level, such that you do not need to re-do it for each individual account.
(I could have made it so you also need to import the e.g. 4 policy attachments of IAMFullAccess
/ReadOnlyAccess
/SecurityAudit
/ViewOnlyAccess
/EnableS3AccountPublicAccessBlock
mentioned above, but since it is the admin
role this felt unnecessary.)
Two reasons: first is the resources that are created automatically due to AWS. The other reason (for the case of EBS encryption region-wide) is because doing something in all regions is painful in Terraform.
Assuming you run this automation before handing an account to a customer, the SCP blocking e.g. "ec2:DisableEbsEncryptionByDefault"
will be applied prior to a customer ever getting access to the account.
The only case where I was ambivalent as to what to do is: s3:PutAccountPublicAccessBlock
.
We could
- Do it upon account creation, and never Terraform it.
- Do it upon account creation, and Terraform import it.
- Give
admin
permission to turn it on upon account creation, Terraform the setting viaaws_s3_account_public_access_block
.
I chose option 3, as it seemed the least bad.
As with EBS encryption, an SCP blocking "s3:PutAccountPublicAccessBlock"
will be applied prior to a customer getting access.
I wrote this code in a sloppy way just to demonstrate the idea, not use it in production. (Though I have written very similar code in a production setting, and this approach worked well.)
- Change the email list value to be configurable rather than hard-coded
- Add tests
- Add more SCPs to
scp_baseline
(https://github.com/ScaleSec/terraform_aws_scp/tree/main/security_controls_scp/modules can be mined for SCPs.) - Terraform a
baseline_ou
that can be used in addition to thescp_baseline
module, in the case that we run into theMaximum attached per account
(5) limit. - Add better IAM policies for
admin
andoperator
, such as service-specific IAM policies that take advantage of condition keys. - Handling the case wherein you enable a new region at the org-level that all subaccounts can use (We would want to e.g. delete the default VPC, enable EBS encryption, in newly enabled regions.)
This lays the ground work for automatically setting up:
- Networking
- AWS Config
- SSM
- Permissions for e.g. your security team, Terraform CI/CD pipeline etc.
and many other things, upon account creation.