Automate AWS Account Creation
ACM.12 Better governance through a secure baseline and automated account provisioning with Control Tower and Account Factory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
⚙️ Check out my series on Automating Cybersecurity Metrics. The Code.
🔒 Related Stories: AWS Security | S3 Buckets | Lambda Security | Cloud Governance
💻 Free Content on Jobs in Cybersecurity | ✉️ Sign up for the Email List
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note: I switched to using AWS CloudFormation later in the series which I think is a better approach. You can still trigger the account creation by calling a command to deploy your AWS CloudForamtion template if you want.
We’ve been progressing through this series to try to automate security metrics we started with the batch jobs and containers but then we needed KMS keys to protect the data, but to create a KMS key policy we needed users and identity. That led to a post on considering what type of MFA we would use for our batch job automation and an explanation of some potential risks when usign the Yubikey CLI with the AWS CLI for MFA. I personally don’t use it, though I love Yubikeys for logging into the AWS console, email, and other browser-UI based authentication processed.
Before we can use any of that — we need an AWS account.
If you heard my presentation on Underrated AWS Security Controls at the AWS Atlanta Summit I spoke about how AWS Control Tower can help you automate provisioning of accounts with a secure baseline and enforce governance.
Without going into too much more detail on that here, I’m providing sample code to create an account using an AWS Lambda function using AWS Control Tower Account Factory. By using AWS Account Factory, this account will be provisioned with the log, security, and policy settings you’ve defined for your organization in AWS Control Tower.
You’ll want to test this thoroughly before using it in production, of course, but I did not find a simple example of this elsewhere. Sometimes I think people make things way too complicated.
There are are two values you’ll need here which are the product ID and product provisioning artifact ID, the latter of which is an overly-complicated way of saying “version.”
import json
import boto3
def get_parameter(event, parameter_name):
parameter_value=str(event[parameter_name])
if parameter_value is None or parameter_value == "":
raise Exception("Must pass in " + parameter_name)
return parameter_value
def get_json_parameter(name, value):
return '{"Key": "' + name + '", "Value": "' + value + '"}'
def lambda_handler(event, context):
account_name=get_parameter(event, "account_name")
account_email_domain=get_parameter(event, \
"account_email_domain")
account_email=account_name + "@" + account_email_domain
ou=get_parameter(event, "ou")
sso_user_email=get_parameter(event, "sso_user_email")
sso_user_first_name=get_parameter(event, "sso_user_first_name")
sso_user_last_name=get_parameter(event, "sso_user_last_name")
servicecatalog=boto3.client('servicecatalog')
#todo: these are hard-coded but should pass in or look up
product_id="xxxxxxxxxx"
prov_artifact_id='xxxxxxxxxx'
str_params= '[' \
+ get_json_parameter("SSOUserEmail", \
sso_user_email) \
+ ', ' + get_json_parameter("SSOUserFirstName", \
sso_user_first_name) \
+ ', ' + get_json_parameter("SSOUserLastName", \
sso_user_last_name) \
+ ', ' + get_json_parameter("ManagedOrganizationalUnit", \
ou) \
+ ', ' + get_json_parameter("AccountName", \
account_name) \
+ ', ' + get_json_parameter("AccountEmail", \
account_email) \
+ ']'
params=json.loads(str_params)
servicecatalog.provision_product(
ProductId=product_id,
ProvisioningArtifactId=prov_artifact_id,
ProvisionedProductName=account_name,
ProvisioningParameters=params
)
return {
'statusCode': 200
}
You can find the product ID and Product Provisioning Artifact ID by going to Service Catalog, click on Products on the left, and then click on a product. Then you’ll see the Product Provisioning Artifact IDs (the screen actually says “versions”) associated with the product. Use the active ID.
Now that looks simple enough, right? It wasn’t simple to come to that and I hit numerous error messages along the way which may be slowing teams down when trying to learn and use this pretty awesome concept. It took multiple fits and starts with limited time and a couple of days to do what should have been simple if the error messages and documentation were clearer.
I haven’t yet completely finished defining zero trust permissions for this function. My related blog posts explain why and how to go about doing that. You will need Service Catalog, Control Tower, Cloud Formation, CloudWatch Logs, and SSO.describe provisioned in regions permissions to run this code. You should not need any functions related to delete, setting permissions, and a number of other possible permissions that could be excluded.
Due to the time I had to wade through so many misleading error messages and dig for documentation to get to this point I initially left that as an excercise for the reader. You can find some of the bugs here as I write about them hopefully to help others who hit the same issues:
Since then I’ve written a blog post about how to query and create zero-trust IAM policies in a few posts starting here:
Note that I haven’t checked this into the GitHub repo associated with this series yet. That’s because I’m actually going to change my approach down the line and use CloudFormation instead along with a different governance model. I love the concept and reason for AWS Control Tower but the implementation is challenging. I propose an alternate solution down the road but perhaps AWS can fix this because it’s a super helpful service.
As noted at the top of the post, I ended up moving away from AWS Control Tower and now create accounts with AWS CloudFormation.
You can read more about how I manage an AWS Account with CloudFormation and improved governance here:
Follow for updates.
Teri Radichel | © 2nd Sight Lab 2022
About Teri Radichel:
~~~~~~~~~~~~~~~~~~~~
⭐️ Author: Cybersecurity Books
⭐️ Presentations: Presentations by Teri Radichel
⭐️ Recognition: SANS Award, AWS Security Hero, IANS Faculty
⭐️ Certifications: SANS ~ GSE 240
⭐️ Education: BA Business, Master of Software Engineering, Master of Infosec
⭐️ Company: Penetration Tests, Assessments, Phone Consulting ~ 2nd Sight Lab
Need Help With Cybersecurity, Cloud, or Application Security?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
🔒 Request a penetration test or security assessment
🔒 Schedule a consulting call
🔒 Cybersecurity Speaker for Presentation
Follow for more stories like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
❤️ Sign Up my Medium Email List
❤️ Twitter: @teriradichel
❤️ LinkedIn: https://www.linkedin.com/in/teriradichel
❤️ Mastodon: @teriradichel@infosec.exchange
❤️ Facebook: 2nd Sight Lab
❤️ YouTube: @2ndsightlab