avatarTeri Radichel

Summary

The website content provides a detailed guide on automating AWS account creation using AWS Control Tower and Account Factory, with a focus on secure baseline provisioning and governance enforcement, later transitioning to AWS CloudFormation for account creation.

Abstract

The content is part of a series on automating cybersecurity metrics, with a particular emphasis on AWS security. It introduces the concept of using AWS Control Tower and Account Factory for automated account provisioning with a secure baseline, which is crucial for maintaining governance and compliance. The author, Teri Radichel, shares sample code for an AWS Lambda function that triggers account creation, discusses the importance of zero trust permissions, and acknowledges the challenges faced due to unclear documentation and error messages. The series later shifts towards using AWS CloudFormation for account creation, highlighting an alternate approach to governance and the creation of an AWS account with improved governance.

Opinions

  • The author believes that AWS Control Tower, while conceptually helpful, presents implementation challenges due to unclear documentation and misleading error messages.
  • Teri Radichel advocates for a zero trust approach when defining permissions for automating AWS account creation, although the complete definition of these permissions is left as an exercise for the reader.
  • The author expresses a preference for AWS CloudFormation over AWS Control Tower for account creation, suggesting it as a better approach for achieving governance within AWS environments.
  • The author values simplicity and criticizes the overcomplication of certain processes, aiming to provide clear examples and guidance to help others navigate similar challenges.
  • Radichel encourages thorough testing before moving any automation solutions to production and has shared related content, including code and discussions on encountered bugs, to assist others in the field.

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.

Airbus A380 approaching the tower — 4 August 2009 — Mike Miley — Creative Commons License

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
Governance
Control Tower
AWS
Account Factory
Lambda
Recommended from ReadMedium