Resourcely Documentation
LoginSign Up
  • Get Started
    • 🎱What is Resourcely?
    • 👋Why Resourcely
    • 🏃Quickstart
      • Terraform policies integrated into CI
      • Remediate policy violations in existing infrastructure
      • Templates for generating Terraform
      • Glossary
  • Concepts
    • Foundry
      • Create Blueprints with Foundry
      • Creating Guardrails with Foundry
      • lmport Terraform Modules
    • Guardrails
      • Writing your own Guardrails
      • Editing Guardrails
      • Releasing Guardrails
      • Enabling Inactive Guardrails
      • Guardrails in Action
        • 🐱GitHub Actions
        • 🦊GitLab Pipelines
    • Campaigns
      • Get started with Campaigns
      • Creating Campaigns
      • Remediate Resources
      • Campaign Agent
        • State File Support
          • Amazon Simple Storage Service (S3)
          • Google Cloud Storage (GCS)
          • HCP Terraform
          • Spacelift
        • Running Campaigns with GitHub Actions and a Repo-Hosted State File
        • Running Campaigns Locally
    • Blueprints
      • Authoring Your Own Blueprints
      • Using Built-in Resourcely Blueprints
      • Configuring Global Contexts
      • Deep Linking
    • Resources
      • Provisioning Infrastructure
      • Editing Infrastructure
      • Shopping Cart
      • Config Roots and Environments
    • Other Features and Settings
      • Global Values
      • Global Context
      • Metrics
      • Resourcely-cli
      • Resourcely.yaml
      • VCS Proxy
      • Settings
        • User management
        • Company Information
        • Notification Settings
        • Change Management
          • 🐱Connect to GitHub
          • 🦊Connect to Gitlab
        • Generate API Token
    • ✨Production Setup
      • Single Sign-On (SSO)
        • Auth0
        • AWS Single Sign-On
        • Azure AD
        • Google Workspace
        • JumpCloud
        • Okta
        • Omnissa Workspace ONE (formerly VMware)
        • OneLogin
        • Ping Identity
        • Other SAML / OIDC Providers
      • Source Code Management
        • Page
        • 🐱GitHub
        • 🦊GitLab
        • Atlassian Bitbucket
        • Azure Repos
  • Tutorials and guides
    • Remediation Use Cases
      • Apply tags to resources for automating backups
      • Implement centralized logging
    • Blueprints Use Cases
      • Automate Data Pipeline Creation
      • Encryption for GCP
      • AWS Account Factory
      • Streamline and govern AI
      • IAM Factory
      • Cost optimization for FinOps
      • Guardrails for Terraform Modules
    • Using the Resourcely Terraform Provider
      • Setup Resourcely Provider
      • Blueprints
      • Guardrails
      • Global Context
  • Integrate
    • CI/CD & Terraform Runners
      • Atlantis
      • 🐟AWS CodeBuild
      • Azure Pipelines
      • Buildkite
      • CircleCI
      • CloudBees CI
      • Codefresh
      • Digger
      • Env0
      • 🎏GitHub Actions
        • 🐱Local Plan
          • 🐹AWS with OpenID Connect
        • 🐶Terraform Cloud Integration
      • 🦊GitLab Pipelines
      • Harness
      • 🗻HashiCorp Cloud Platform (formerly Terraform Cloud)
      • Jenkins
      • Octopus Deploy
      • Scalr
      • 🌌Spacelift
      • Terramate
      • 🌎Terrateam
    • Cloud Providers
      • 🌨️Amazon Web Services (AWS)
      • 🤓Google Cloud Platform (GCP)
        • Guardrail Gaunlet at Google Cloud Next 2025
      • 💾Microsoft Azure
      • Alibaba Cloud
      • Huawei Cloud
      • IBM Cloud
      • Oracle Cloud Infrastructure (OCI)
      • Tencent Cloud
      • VMware vSphere
    • Developer Portals
      • Atlassian Compass
      • Backstage
      • Cortex
      • Harness IDP
      • Home grown internal developer portals
      • OpsLevel
      • Port
      • Roadie
    • ITSM
      • Atlassian Jira
      • FreshWorks
      • ServiceNow ITSM
      • ZenDesk
    • CSPM
      • Wiz
    • More Terraform Provider Integrations
      • 🚂ConductorOne Provider
      • Databricks Provider
      • Kubernetes Provider
      • 🐕Datadog Provider
      • ❄️Snowflake Provider
Powered by GitBook
On this page
  • Setting up an AWS Control Tower Account Factory for Terraform (AFT)
  • Module
  • Creating a Blueprint from the module
  • Publishing and deploying AFT
  • Provisioning accounts using AFT
  • Module
  • Creating a Blueprint from the module
  • Guardrails
  • Publishing and provisioning new accounts
  • Get started today
  1. Tutorials and guides
  2. Blueprints Use Cases

AWS Account Factory

Make AWS account creation easy and frictionless

PreviousEncryption for GCPNextStreamline and govern AI

Last updated 5 months ago

AWS accounts are a critical object for structuring, securing, and managing your AWS cloud resources. While they are foundational for best practices cloud usage, they can be annoying and tedious to set up appropriately and in a streamlined way.

In this tutorial, we'll cover how you can set up an AWS ControlTower Account Factory, and give developers an easy method to create new accounts - using Terraform (and all the benefits of infrastructure as code) under the hood!

We'll accomplish this by converting some Terraform modules into Resourcely Blueprints, generating a smart UI that developers can interact with instead of needing to work with Terraform modules directly.

Setting up an AWS Control Tower Account Factory for Terraform (AFT)

Control Tower Account Factory exists to streamline the creation, orchestration, and management of AWS accounts.

Module

There is a Terraform version of Account Factory, that lets Account Factory users enjoy the benefits of infrastructure as code: versioning, review, code as documentation, and more.

The top-level module in this repository sets up Account Factory inside of a landing zone.

Creating a Blueprint from the module

We'll turn this top-level module into a Blueprint and customize it. This will automatically create a UI that developers can use to generate Terraform code for making accounts, streamlining the process for spinning up Account Factory landing zones and new AWS accounts. To do so, we only need to import the module and make some adjustments.

Resourcely automatically detects the variables from the AFT module and assigns types, defaults, descriptions, and more.

Once you have chosen which fields to include and exclude, hit Continue and move to the Groups screen. This allows you to choose how the UI will be organized.

The following Blueprint is generated, based on our AFT module. The Blueprint automatically creates variables for each input, which will be exposed as inputs in our form (see the Developer Experience tab).

AFT Module Blueprint
---
variables:
  account_customizations_repo_branch:
    default: main
    desc: Branch to source account customizations repo from
    required: false
    type: resource.aws_ssm_parameter.value
  account_customizations_repo_name:
    default: aft-account-customizations
    desc: Repository name for the account customizations files. For non-CodeCommit
      repos, name should be in the format of Org/Repo
    required: false
    type: resource.aws_ssm_parameter.value
  account_provisioning_customizations_repo_branch:
    default: main
    desc: Branch to source account provisioning customization files
    required: false
    type: resource.aws_ssm_parameter.value
  account_provisioning_customizations_repo_name:
    default: aft-account-provisioning-customizations
    desc: Repository name for the account provisioning customizations files. For
      non-CodeCommit repos, name should be in the format of Org/Repo
    required: false
    type: resource.aws_ssm_parameter.value
  account_request_repo_branch:
    default: main
    desc: Branch to source account request repo from
    group: Repos
    order: 0
    required: false
    type: resource.aws_ssm_parameter.value
  account_request_repo_name:
    default: aft-account-request
    desc: Repository name for the account request files. For non-CodeCommit repos,
      name should be in the format of Org/Repo
    group: Repos
    order: 1
    required: false
    type: resource.aws_ssm_parameter.value
  aft_backend_bucket_access_logs_object_expiration_days:
    default: 365
    desc: Amount of days to keep the objects stored in the access logs bucket for
      AFT backend buckets
    required: false
    type: resource.aws_s3_bucket_lifecycle_configuration.rule.noncurrent_version_expiration.noncurrent_days
  aft_enable_vpc:
    default: true
    desc: Flag turning use of VPC on/off for AFT
    group: VPCs
    order: 0
    required: false
    type: bool
  aft_feature_cloudtrail_data_events:
    default: "false"
    desc: Feature flag toggling CloudTrail data events on/off
    required: false
    type: resource.aws_ssm_parameter.value
  aft_feature_delete_default_vpcs_enabled:
    default: "false"
    desc: Feature flag toggling deletion of default VPCs on/off
    group: VPCs
    order: 1
    required: false
    type: resource.aws_ssm_parameter.value
  aft_feature_enterprise_support:
    default: "false"
    desc: Feature flag toggling Enterprise Support enrollment on/off
    required: false
    type: resource.aws_ssm_parameter.value
  aft_framework_repo_git_ref:
    desc: Git branch from which the AFT framework should be sourced from
    group: Repos
    order: 2
    required: false
    type: resource.aws_ssm_parameter.value
  aft_framework_repo_url:
    default: https://github.com/aws-ia/terraform-aws-control_tower_account_factory.git
    desc: Git repo URL where the AFT framework should be sourced from
    required: false
    type: resource.aws_ssm_parameter.value
  aft_management_account_id:
    desc: AFT Management Account ID
    type: resource.aws_ssm_parameter.value
  aft_metrics_reporting:
    default: "true"
    desc: Flag toggling reporting of operational metrics
    required: false
    type: resource.aws_ssm_parameter.value
  aft_vpc_cidr:
    default: 192.168.0.0/22
    desc: CIDR Block to allocate to the AFT VPC
    required: false
    type: resource.aws_vpc.cidr_block
  aft_vpc_endpoints:
    default: true
    desc: Flag turning VPC endpoints on/off for AFT VPC
    required: false
    type: bool
  aft_vpc_private_subnet_01_cidr:
    default: 192.168.0.0/24
    desc: CIDR Block to allocate to the Private Subnet 01
    required: false
    type: resource.aws_subnet.cidr_block
  aft_vpc_private_subnet_02_cidr:
    default: 192.168.1.0/24
    desc: CIDR Block to allocate to the Private Subnet 02
    required: false
    type: resource.aws_subnet.cidr_block
  aft_vpc_public_subnet_01_cidr:
    default: 192.168.2.0/25
    desc: CIDR Block to allocate to the Public Subnet 01
    required: false
    type: resource.aws_subnet.cidr_block
  aft_vpc_public_subnet_02_cidr:
    default: 192.168.2.128/25
    desc: CIDR Block to allocate to the Public Subnet 02
    required: false
    type: resource.aws_subnet.cidr_block
  audit_account_id:
    desc: Audit Account Id
    type: resource.aws_ssm_parameter.value
  backup_recovery_point_retention:
    desc: Number of days to keep backup recovery points in AFT DynamoDB tables.
      Default = Never Expire
    required: false
    type: resource.aws_backup_plan.rule.lifecycle.delete_after
  cloudwatch_log_group_retention:
    default: 0
    desc: Amount of days to keep CloudWatch Log Groups for Lambda functions. 0 =
      Never Expire
    required: false
    type: resource.aws_cloudwatch_log_group.retention_in_days
  concurrent_account_factory_actions:
    default: 5
    desc: Maximum number of accounts that can be provisioned in parallel.
    required: false
    type: number
  ct_home_region:
    desc: The region from which this module will be executed. This MUST be the same
      region as Control Tower is deployed.
    type: resource.aws_ssm_parameter.value
  ct_management_account_id:
    desc: Control Tower Management Account Id
    type: resource.aws_ssm_parameter.value
  github_enterprise_url:
    default: "null"
    desc: GitHub enterprise URL, if GitHub Enterprise is being used
    required: false
    type: resource.aws_ssm_parameter.value
  gitlab_selfmanaged_url:
    default: "null"
    desc: GitLab SelfManaged URL, if GitLab SelfManaged is being used
    required: false
    type: resource.aws_ssm_parameter.value
  global_codebuild_timeout:
    default: 60
    desc: Codebuild build timeout
    required: false
    type: number
  global_customizations_repo_branch:
    default: main
    desc: Branch to source global customizations repo from
    required: false
    type: resource.aws_ssm_parameter.value
  global_customizations_repo_name:
    default: aft-global-customizations
    desc: Repository name for the global customization files. For non-CodeCommit
      repos, name should be in the format of Org/Repo
    required: false
    type: resource.aws_ssm_parameter.value
  log_archive_account_id:
    desc: Log Archive Account Id
    type: resource.aws_ssm_parameter.value
  log_archive_bucket_object_expiration_days:
    default: 365
    desc: Amount of days to keep the objects stored in the AFT logging bucket
    required: false
    type: resource.aws_s3_bucket_lifecycle_configuration.rule.noncurrent_version_expiration.noncurrent_days
  maximum_concurrent_customizations:
    default: "5"
    desc: Maximum number of customizations/pipelines to run at once
    required: false
    type: resource.aws_ssm_parameter.value
  terraform_api_endpoint:
    default: https://app.terraform.io/api/v2/
    desc: API Endpoint for Terraform. Must be in the format of https://xxx.xxx.
    required: false
    type: resource.aws_ssm_parameter.value
  terraform_distribution:
    default: oss
    desc: Terraform distribution being used for AFT - valid values are oss, tfc, or
      tfe
    required: false
    type: resource.aws_ssm_parameter.value
  terraform_org_name:
    default: "null"
    desc: Organization name for Terraform Cloud or Enterprise
    required: false
    type: resource.aws_ssm_parameter.value
  terraform_token:
    default: "null"
    desc: Terraform token for Cloud or Enterprise
    required: false
    type: resource.aws_ssm_parameter.value
  terraform_version:
    default: 1.6.0
    desc: Terraform version being used for AFT
    required: false
    type: resource.aws_ssm_parameter.value
  tf_backend_secondary_region:
    default: ""
    desc: AFT creates a backend for state tracking for its own state as well as OSS
      cases. The backend's primary region is the same as the AFT region, but
      this defines the secondary region to replicate to.
    required: false
    type: resource.aws_ssm_parameter.value
  vcs_provider:
    default: codecommit
    desc: Customer VCS Provider - valid inputs are codecommit, bitbucket, github,
      githubenterprise, gitlab, or gitLab self-managed
    required: false
    type: resource.aws_ssm_parameter.value
groups:
  Repos:
    order: 0
  VPCs:
    order: 1
---

module "{{ module_name }}_{{ __guid }}" {
  source = "git::https://github.com/aws-ia/terraform-aws-control_tower_account_factory"

  account_customizations_repo_branch = {{ account_customizations_repo_branch }}

  account_customizations_repo_name = {{ account_customizations_repo_name }}

  account_provisioning_customizations_repo_branch = {{ account_provisioning_customizations_repo_branch }}

  account_provisioning_customizations_repo_name = {{ account_provisioning_customizations_repo_name }}

  account_request_repo_branch = {{ account_request_repo_branch }}

  account_request_repo_name = {{ account_request_repo_name }}

  aft_backend_bucket_access_logs_object_expiration_days = {{ aft_backend_bucket_access_logs_object_expiration_days }}

  aft_enable_vpc = {{ aft_enable_vpc }}

  aft_feature_cloudtrail_data_events = {{ aft_feature_cloudtrail_data_events }}

  aft_feature_delete_default_vpcs_enabled = {{ aft_feature_delete_default_vpcs_enabled }}

  aft_feature_enterprise_support = {{ aft_feature_enterprise_support }}

  aft_framework_repo_git_ref = {{ aft_framework_repo_git_ref }}

  aft_framework_repo_url = {{ aft_framework_repo_url }}

  aft_management_account_id = {{ aft_management_account_id }}

  aft_metrics_reporting = {{ aft_metrics_reporting }}

  aft_vpc_cidr = {{ aft_vpc_cidr }}

  aft_vpc_endpoints = {{ aft_vpc_endpoints }}

  aft_vpc_private_subnet_01_cidr = {{ aft_vpc_private_subnet_01_cidr }}

  aft_vpc_private_subnet_02_cidr = {{ aft_vpc_private_subnet_02_cidr }}

  aft_vpc_public_subnet_01_cidr = {{ aft_vpc_public_subnet_01_cidr }}

  aft_vpc_public_subnet_02_cidr = {{ aft_vpc_public_subnet_02_cidr }}

  audit_account_id = {{ audit_account_id }}

  backup_recovery_point_retention = {{ backup_recovery_point_retention }}

  cloudwatch_log_group_retention = {{ cloudwatch_log_group_retention }}

  concurrent_account_factory_actions = {{ concurrent_account_factory_actions }}

  ct_home_region = {{ ct_home_region }}

  ct_management_account_id = {{ ct_management_account_id }}

  github_enterprise_url = {{ github_enterprise_url }}

  gitlab_selfmanaged_url = {{ gitlab_selfmanaged_url }}

  global_codebuild_timeout = {{ global_codebuild_timeout }}

  global_customizations_repo_branch = {{ global_customizations_repo_branch }}

  global_customizations_repo_name = {{ global_customizations_repo_name }}

  log_archive_account_id = {{ log_archive_account_id }}

  log_archive_bucket_object_expiration_days = {{ log_archive_bucket_object_expiration_days }}

  maximum_concurrent_customizations = {{ maximum_concurrent_customizations }}

  terraform_api_endpoint = {{ terraform_api_endpoint }}

  terraform_distribution = {{ terraform_distribution }}

  terraform_org_name = {{ terraform_org_name }}

  terraform_token = {{ terraform_token }}

  terraform_version = {{ terraform_version }}

  tf_backend_secondary_region = {{ tf_backend_secondary_region }}

  vcs_provider = {{ vcs_provider }}
}

We'll customize this procedurally generated Blueprint to improve our description names and suggestions, giving anyone who is setting up AFT via our form more guidance.

Adding suggestions and grouping
---
variables:
  aft_vpc_cidr:
    default: 192.168.0.0/22
    desc: CIDR Block to allocate to the AFT VPC
    required: false
    type: resource.aws_vpc.cidr_block
    group: Network
  vcs_provider:
    suggest: "github"
    desc: Customer VCS Provider - valid inputs are codecommit, bitbucket, github, or
      githubenterprise
    required: false
    type: resource.aws_ssm_parameter.value
    group: Repository
  aft_enable_vpc:
    default: true
    desc: Flag turning use of VPC on/off for AFT
    required: false
    type: bool
    group: Network
  ct_home_region:
    desc: The region from which this module will be executed. This MUST be the same
      region as Control Tower is deployed.
    type: resource.aws_ssm_parameter.value
    suggest: "us-east-1"
    group: Location
  audit_account_id:
    desc: Audit Account Id
    type: resource.aws_ssm_parameter.value
    suggest: "123456789012"
    group: Accounts
  aft_vpc_endpoints:
    default: true
    desc: Flag turning VPC endpoints on/off for AFT VPC
    required: false
    type: bool
    group: Network
  ct_management_account_id:
    desc: Control Tower Management Account Id
    type: resource.aws_ssm_parameter.value
    suggest: "111122223333"
    group: Accounts
  aft_management_account_id:
    desc: AFT Management Account ID
    suggest: "777788889999"
    type: resource.aws_ssm_parameter.value
    group: Accounts
  account_request_repo_branch:
    default: main
    desc: Branch to source account request repo from
    required: false
    type: resource.aws_ssm_parameter.value
    group: Repository
  tf_backend_secondary_region:
    suggest: "us-west-2"
    desc: AFT creates a backend for state tracking for its own state as well as OSS
      cases. The backend's primary region is the same as the AFT region, but
      this defines the secondary region to replicate to.
    required: false
    type: resource.aws_ssm_parameter.value
    group: Location
  aft_vpc_public_subnet_01_cidr:
    default: 192.168.2.0/25
    desc: CIDR Block to allocate to the Public Subnet 01
    required: false
    type: resource.aws_subnet.cidr_block
    group: Network
  aft_vpc_public_subnet_02_cidr:
    default: 192.168.2.128/25
    desc: CIDR Block to allocate to the Public Subnet 02
    required: false
    type: resource.aws_subnet.cidr_block
    group: Network
  aft_vpc_private_subnet_01_cidr:
    default: 192.168.0.0/24
    desc: CIDR Block to allocate to the Private Subnet 01
    required: false
    type: resource.aws_subnet.cidr_block
    group: Network
  aft_vpc_private_subnet_02_cidr:
    default: 192.168.1.0/24
    desc: CIDR Block to allocate to the Private Subnet 02
    required: false
    type: resource.aws_subnet.cidr_block
    group: Network
  cloudwatch_log_group_retention:
    default: 0
    desc: Amount of days to keep CloudWatch Log Groups for Lambda functions. 0 =
      Never Expire
    required: false
    type: resource.aws_cloudwatch_log_group.retention_in_days
    group: General
  log_archive_account_id:
    desc: Log Archive Account Id
    suggest: "444455556666"
    type: resource.aws_ssm_parameter.value
    group: Accounts
  backup_recovery_point_retention:
    default: 365
    desc: Number of days to keep backup recovery points in AFT DynamoDB tables.
      Default = Never Expire
    required: false
    type: resource.aws_backup_plan.rule.lifecycle.delete_after
    group: General
  global_customizations_repo_name:
    suggest: "myorg/aft-global-customizations"
    desc: Repository name for the global customization files. For non-CodeCommit
      repos, name should be in the format of Org/Repo
    required: false
    type: resource.aws_ssm_parameter.value
    group: Repository
  account_customizations_repo_name:
    suggest: "myorg/aft-account-customizations"
    desc: Repository name for the account customizations files. For non-CodeCommit
      repos, name should be in the format of Org/Repo
    required: false
    type: resource.aws_ssm_parameter.value
    group: Repository
  log_archive_bucket_object_expiration_days:
    default: 365
    desc: Amount of days to keep the objects stored in the AFT logging bucket
    required: false
    type: resource.aws_s3_bucket_lifecycle_configuration.rule.noncurrent_version_expiration.noncurrent_days
    group: General
  account_provisioning_customizations_repo_name:
    suggest: "myorg/aft-account-provisioning-customizations"
    desc: Repository name for the account provisioning customizations files. For
      non-CodeCommit repos, name should be in the format of Org/Repo
    required: false
    type: resource.aws_ssm_parameter.value
    group: Repository
  aft_backend_bucket_access_logs_object_expiration_days:
    default: 365
    desc: Amount of days to keep the objects stored in the access logs bucket for
      AFT backend buckets
    required: false
    type: resource.aws_s3_bucket_lifecycle_configuration.rule.noncurrent_version_expiration.noncurrent_days
    group: General

groups:
  Accounts:
    order: 1
  General:
    order: 2
  Repository:
    order: 3
  Network:
    order: 4
  Location:
    order: 5
---

module "{{ module_name }}_{{ __guid }}" {
  source = "git::https://github.com/aws-ia/terraform-aws-control_tower_account_factory"

  aft_vpc_cidr = {{ aft_vpc_cidr }}

  vcs_provider = {{ vcs_provider }}

  aft_enable_vpc = {{ aft_enable_vpc }}

  ct_home_region = {{ ct_home_region }}

  audit_account_id = {{ audit_account_id }}

  aft_vpc_endpoints = {{ aft_vpc_endpoints }}

  ct_management_account_id = {{ ct_management_account_id }}

  aft_management_account_id = {{ aft_management_account_id }}

  tf_backend_secondary_region = {{ tf_backend_secondary_region }}

  aft_vpc_public_subnet_01_cidr = {{ aft_vpc_public_subnet_01_cidr }}

  aft_vpc_public_subnet_02_cidr = {{ aft_vpc_public_subnet_02_cidr }}

  aft_vpc_private_subnet_01_cidr = {{ aft_vpc_private_subnet_01_cidr }}

  aft_vpc_private_subnet_02_cidr = {{ aft_vpc_private_subnet_02_cidr }}

  cloudwatch_log_group_retention = {{ cloudwatch_log_group_retention }}

  backup_recovery_point_retention = {{ backup_recovery_point_retention }}

  global_customizations_repo_name = {{ global_customizations_repo_name }}

  account_customizations_repo_name = {{ account_customizations_repo_name }}

  log_archive_account_id = {{ log_archive_account_id }}

  log_archive_bucket_object_expiration_days = {{ log_archive_bucket_object_expiration_days }}

  account_provisioning_customizations_repo_name = {{ account_provisioning_customizations_repo_name }}

  aft_backend_bucket_access_logs_object_expiration_days = {{ aft_backend_bucket_access_logs_object_expiration_days }}
}

Publishing and deploying AFT

Once you have customized your AFT module Blueprint to your liking, add metadata and publish the Blueprint. This will make it available for anyone to deploy.

Once you have published the Blueprint, deploy your AFT with it. Go to Resources, create a Pull Request, find your AFT Blueprint, fill it out to your liking, and then submit and deploy it.

Provisioning accounts using AFT

Now that we have AFT setup, we have all of the necessary IAM roles, VPCs, lambda functions, and other resources needed to set up an account.

Module

Within our AFT module, there is a submodule called aft-account-provisioning-framework. We'll create a Blueprint from this module, and use that as our primary vehicle for creating accounts using the AFT we just deployed.

Creating a Blueprint from the module

Similar to previous steps, Resourcely will automatically infer variable tags such as description. Finish importing this module, add Groups, and then inspect your Blueprint code. It should look something like this:

Resulting Blueprint
---
variables:
  account_metadata_ssm_lambda_function_name:
    type: resource.aws_lambda_function.function_name
  aft_account_provisioning_customizations_sfn_name:
    type: string
  aft_account_provisioning_framework_sfn_name:
    type: resource.aws_sfn_state_machine.name
  aft_common_layer_arn:
    type: string
  aft_enable_vpc:
    type: bool
  aft_failure_sns_topic_arn:
    type: string
  aft_features_sfn_name:
    type: string
  aft_kms_key_arn:
    type: string
  aft_sns_topic_arn:
    type: string
  aft_vpc_default_sg:
    required: false
    type: resource.aws_lambda_function.vpc_config.security_group_ids
  aft_vpc_private_subnets:
    required: false
    type: resource.aws_lambda_function.vpc_config.subnet_ids
  cloudwatch_log_group_retention:
    type: resource.aws_cloudwatch_log_group.retention_in_days
  create_role_lambda_function_name:
    type: resource.aws_lambda_function.function_name
  delete_default_vpc_lambda_function_name:
    type: string
  enable_cloudtrail_lambda_function_name:
    type: string
  enroll_support_lambda_function_name:
    type: string
  lambda_runtime_python_version:
    type: resource.aws_lambda_function.runtime
  persist_metadata_lambda_function_name:
    type: resource.aws_lambda_function.function_name
  provisioning_framework_archive_hash:
    type: resource.aws_lambda_function.source_code_hash
  provisioning_framework_archive_path:
    type: resource.aws_lambda_function.filename
  tag_account_lambda_function_name:
    type: resource.aws_lambda_function.function_name
  trigger_customizations_sfn_name:
    type: string
---

module "{{ module_name }}_{{ __guid }}" {
  source = "git::https://github.com/aws-ia/terraform-aws-control_tower_account_factory//modules/aft-account-provisioning-framework"

  account_metadata_ssm_lambda_function_name = {{ account_metadata_ssm_lambda_function_name }}

  aft_account_provisioning_customizations_sfn_name = {{ aft_account_provisioning_customizations_sfn_name }}

  aft_account_provisioning_framework_sfn_name = {{ aft_account_provisioning_framework_sfn_name }}

  aft_common_layer_arn = {{ aft_common_layer_arn }}

  aft_enable_vpc = {{ aft_enable_vpc }}

  aft_failure_sns_topic_arn = {{ aft_failure_sns_topic_arn }}

  aft_features_sfn_name = {{ aft_features_sfn_name }}

  aft_kms_key_arn = {{ aft_kms_key_arn }}

  aft_sns_topic_arn = {{ aft_sns_topic_arn }}

  aft_vpc_default_sg = {{ aft_vpc_default_sg }}

  aft_vpc_private_subnets = {{ aft_vpc_private_subnets }}

  cloudwatch_log_group_retention = {{ cloudwatch_log_group_retention }}

  create_role_lambda_function_name = {{ create_role_lambda_function_name }}

  delete_default_vpc_lambda_function_name = {{ delete_default_vpc_lambda_function_name }}

  enable_cloudtrail_lambda_function_name = {{ enable_cloudtrail_lambda_function_name }}

  enroll_support_lambda_function_name = {{ enroll_support_lambda_function_name }}

  lambda_runtime_python_version = {{ lambda_runtime_python_version }}

  persist_metadata_lambda_function_name = {{ persist_metadata_lambda_function_name }}

  provisioning_framework_archive_hash = {{ provisioning_framework_archive_hash }}

  provisioning_framework_archive_path = {{ provisioning_framework_archive_path }}

  tag_account_lambda_function_name = {{ tag_account_lambda_function_name }}

  trigger_customizations_sfn_name = {{ trigger_customizations_sfn_name }}
}

Make sure to check out the Developer Experience tab in Foundry after you have generated your Blueprint. This is the form that your developers will see when deploying new accounts.

You can now add your own guidance by amending the variable descriptions, suggestions, and defaults. Note that Resourcely automatically creates variables that are inputs in the Blueprint form. If you don't want to give developers the ability to add their own custom references, and instead want to lock them in to the AFT resources, you can simply hardcode them in the Blueprint code.

For example, let's say that we don't want to expose an input for tag_account_lambda_function_name. This would make sure that consistent tags are always applied to your accounts, and developers won't be able to deviate. All you would need to do is replace the inline {{ tag_account_lambda_function_name }} variable reference with a hardcoded reference in Terraform.

Guardrails

Guardrailsare a great way to add rules to your input form that keep developers on track. One easy example would be adding a rule for the cloudwatch_log_group_retention variable. To do so, and create the following Guardrail:

GUARDRAIL "Retention in days > 364"
  WHEN aws_cloudwatch_log_group
    REQUIRE retention_in_days > 364
  OVERRIDE WITH APPROVAL @default

After savings and navigating back to your Blueprint, this would appear as a Guardrail lock on your form:

Publishing and provisioning new accounts

Once you have finished customizing your Blueprint, add metadata and publish it to make it discoverable. Now, developers have an easy way to create a new AWS account: meeting the expectations that you set when creating the AFT, and utilizing isolation-related best practices.

Get started today

Log in to Resourcely and navigate to the (Blueprints -> Create a Blueprint -> Import a Module).

Paste in the GitHub URL () and click Continue

You can choose which fields to omit, and which fields to include. Our version of the AFT landing zone Blueprint is available .

Navigate back to the , and make sure the same url () is still entered.

These Blueprints are available in Resourcely for you! If you want to streamline AWS account creation, making it easy for developers to follow best practices, all you need to do is sign up for your .

We love feedback! if you had any trouble with this.

Import screen
https://github.com/aws-ia/terraform-aws-control_tower_account_factory
here
Import screen
https://github.com/aws-ia/terraform-aws-control_tower_account_factory
free account
Let us know
LogoGitHub - aws-ia/terraform-aws-control_tower_account_factory: AWS Control Tower Account FactoryGitHub
Importing a GitHub repo into a Blueprint
Choosing which fields to include in the Blueprint
Assigning variables to Groups
Importing our provisioning module
Guardrail embedded into a Blueprint