This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Documentation

Welcome to the Org Kickstart documentation. This section covers everything you need to deploy and manage a governed AWS Organization using Terraform.

In This Section

1 - Overview

What Org Kickstart is and why you’d use it.

What is Org Kickstart?

Org Kickstart is an opinionated Terraform module for bootstrapping and managing AWS Organizations. It is PrimeHarbor’s alternative to AWS Control Tower — designed to give you the good parts of a landing zone without the cost, complexity, and lock-in that Control Tower brings.

Deployed into a brand new AWS Management (Payer) account, a single terraform apply can stand up a fully governed AWS Organization with security services enabled, organizational guardrails in place, and an account factory ready to provision new accounts.

Org Kickstart Architecture

Why not just use Control Tower?

Control Tower is a massive beast designed to support highly regulated enterprises. For most organizations, it brings significant drawbacks:

  • Expensive: Heavy reliance on AWS Config means costs scale with the number of accounts and regions.
  • Inflexible: Modifications require navigating AWS Service Catalog customizations.
  • Slow to update: Features like Organization CloudTrail and GuardDuty Delegated Admin lagged behind AWS best practices for years.
  • Complex: You effectively need a PhD in AWS Service Catalog to change anything.

Most organizations deploy Control Tower because their AWS Solutions Architect recommended it, or because they needed an account factory. Org Kickstart gives you the account factory, the security posture, and the governance — without the baggage.

What Org Kickstart does

Org Kickstart deploys and manages:

  1. Security Account — Creates a dedicated security account and delegates GuardDuty, Macie, Inspector, Security Hub, SSO, and CloudFormation StackSets to a dedicated Security Account. Configures all security services in every default region across all accounts.
  2. CloudTrail — Creates a CloudTrail bucket in the Security Account and enables an Organizations CloudTrail in the Management Account.
  3. Alternate Contacts — Sets Billing, Operations, and Security contacts for all AWS accounts.
  4. Organizational Units — Creates four default OUs (Workloads, Governance, Sandbox, Suspended) plus any custom OUs you define.
  5. AI Opt-Out Policy — Creates and applies a default AI opt-out policy at the root OU.
  6. Account Management — Manages AWS accounts and OU placement from Terraform.
  7. Audit Role — Deploys an Audit Role via CloudFormation StackSet to all accounts, trusting the Security Account.
  8. Billing Reports — Creates an S3 bucket for billing data and an Athena-compatible CUR report.
  9. Organization Services — Enables all important AWS Organization Integrated Services.
  10. Org Policies — Manages Service Control Policies, Declarative Policies, and Resource Control Policies with Terraform templating support.
  11. SSO / Identity Center — Creates an AdministratorAccess Permission Set, an admin group, and assigns both to every account.

What is required vs. optional?

Cannot be disabled:

  • Security Account
  • Four default OUs (Governance, Workloads, Sandbox, Suspended)
  • AI Opt-Out Policy
  • Core Organization Integrated Services

Can be disabled via variables:

  • CloudTrail management: cloudtrail_bucket_name = null
  • SSO management: disable_sso_management = true
  • Audit Role StackSet: deploy_audit_role = false
  • Security services: security_services object with disable_* flags
  • CUR reports: cur_report_frequency = "NONE"
  • Alternate contacts: omit contact blocks from tfvars

Where should I go next?

2 - Getting Started

Prerequisites, bootstrapping, and first deployment.

This section walks you through getting Org Kickstart deployed into a new AWS account.

Prerequisites

Before running Org Kickstart you need:

  • Terraform >= 1.0 (< 2.0)
  • AWS CLI configured with credentials for the Management (Payer) account
  • An S3 bucket for Terraform remote state
  • A few manual “artisanal” steps completed in the AWS console (see Bootstrap)

Steps

  1. Complete the Bootstrap steps in the AWS Console
  2. Copy examples/pipeline to your own private repo — it includes the Makefile, backend config, and directory layout
  3. Create your-org.tfvars and your-org.tfbackend for your organization (see the Reference for all variables; name them to match your env value)
  4. Initialize Terraform:
    make env=your-org tf-init
    
  5. Create the Security Account first (required before full apply):
    terraform apply -var-file="your-org.tfvars" -target module.security_account
    
  6. Deploy everything:
    make env=your-org tf-execute
    
    This runs tf-plan followed by tf-apply — saving the plan, applying it, and writing output-your-org.json to your state bucket.

For subsequent updates, use:

make env=your-org update

Using with an Existing Organization

If you already have an AWS Organization, see Importing an Existing Org for guidance on importing existing resources into Terraform state.

Example tfvars

See the Reference page for a full annotated example. The examples/pipeline directory in the repository contains a sample private-repo layout with a Makefile, backend config template, and scripts for CI/CD deployments.

2.1 - Bootstrap a New Account

Manual steps required in the AWS Console before running Terraform.

Before Org Kickstart can be deployed, a few steps must be completed via ClickOps in your new AWS Management (Payer) account. Terraform cannot perform these actions automatically.

Root Account Tasks

Log into the root user of your new AWS “payer” account and complete the following:

  1. Add MFA to root
  2. Enable IAM access to billing
  3. Go to Organizations and create an Organization
  4. Go to AWS IAM Identity Center (SSO) and enable it
  5. Add yourself as a user in Identity Center
  6. Create a Permission Set named TempAdministratorAccess (4-hour session recommended)
  7. Assign the Permission Set to the Payer/Management Account for your user
  8. Activate trusted access for CloudFormation StackSets — click “Activate trusted access with AWS Organizations to use service-managed permissions” (must be done via console)

Log out of root and never use it again.

Note: As of January 2026, Terraform does not support the aws login capability. An IAM Identity Center or IAM User must be created to run Terraform.

On Your Machine

  1. Check email and activate your IAM Identity Center account
  2. Add MFA to your Identity Center account
  3. Configure AWS credentials in your environment:
    aws configure sso
    # or
    export AWS_PROFILE=your-sso-profile
    

You are now ready to deploy Org Kickstart.

Next Steps

  • Create your tfvars file — see the Reference for all variables and a full example
  • Run terraform init and your first apply — see Getting Started

2.2 - Importing an Existing Organization

How to adopt Org Kickstart into an existing AWS Organization.

Org Kickstart can manage an existing AWS Organization. Several resources must be imported into Terraform state before running terraform apply.

The minimum required imports are the organization, the management account, and the Security Account (if it already exists). You may also want to import existing accounts, CloudTrail buckets, billing buckets, and SSO configuration.

Automated Import

The scripts/import_org.sh script generates an import-org.tf file and a TFVars snippet for your existing accounts.

# From the org-kickstart directory
./scripts/import_org.sh

Review the generated import-org.tf carefully before running Terraform.

Steps

  1. Run import_org.sh and review import-org.tf
  2. Add your CloudTrail or billing bucket to the import file if applicable
  3. Review SCPs you want to import:
    aws organizations list-policies --filter SERVICE_CONTROL_POLICY \
      --query 'Policies[].[Id,Name]' --output text
    
  4. Iterate with tf-plan until no unwanted changes appear:
    make env=your-org tf-plan
    make env=your-org tf-show    # review the plan output
    
  5. Once satisfied, apply:
    make env=your-org tf-apply
    
  6. Incrementally enable additional features

Manual Import Examples

Organizational Units

ROOT_OU=$(aws organizations list-roots --query Roots[0].Id --output text)
aws organizations list-organizational-units-for-parent \
  --parent-id $ROOT_OU \
  --query 'OrganizationalUnits[].[Id,Name]' --output text
import {
  to = module.organization.aws_organizations_organizational_unit.TF_VARS_KEY
  id = "ou-xxxx-xxxxxxxx"
}

IAM Identity Center (SSO)

To opt out of managing an existing Identity Center, set disable_sso_management = true in your tfvars. This is recommended for existing orgs with complex SSO configurations.

IDENTITY_STORE_ID=$(aws sso-admin list-instances \
  --query Instances[0].IdentityStoreId --output text)
SSO_INSTANCE_ARN=$(aws sso-admin list-instances \
  --query Instances[0].InstanceArn --output text)
import {
  to = module.organization.aws_identitystore_group.admin_group
  id = "$IDENTITY_STORE_ID/$GROUP_ID"
}
import {
  to = module.organization.aws_ssoadmin_permission_set.admin_permission_set
  id = "$PERMISSION_SET_ARN,$SSO_INSTANCE_ARN"
}
import {
  to = module.organization.aws_ssoadmin_managed_policy_attachment.admin_policy_attachments
  id = "arn:aws:iam::aws:policy/AdministratorAccess,$PERMISSION_SET_ARN,$SSO_INSTANCE_ARN"
}

CloudTrail

aws cloudtrail list-trails --query Trails[].TrailARN --output text
import {
  to = module.organization.aws_s3_bucket.cloudtrail_bucket[0]
  id = "YOUR_EXISTING_BUCKET_NAME"
}
import {
  to = module.organization.aws_cloudtrail.org_cloudtrail[0]
  id = "TRAIL_ARN"
}

Service Control Policies

aws organizations list-policies --filter SERVICE_CONTROL_POLICY \
  --query 'Policies[].[Id,Name]' --output text

# Get OUs targeted by a policy
aws organizations list-targets-for-policy --policy-id p-xxxxxx
import {
  to = module.organization.module.scp["POLICY_BLOCK_IDENTIFIER_FROM_TFVARS"].aws_organizations_policy.org_policy
  id = "p-xxxxxx"
}

Disabling Features for Initial Import

When importing an existing org, you may want to temporarily disable features to prevent unintended changes on the first apply:

  • CloudTrail: cloudtrail_bucket_name = null
  • SSO: disable_sso_management = true
  • Audit Role StackSet: deploy_audit_role = false
  • Security Services: use the security_services block with disable_* flags

2.3 - Example tfvars

A complete annotated example tfvars file.

The following is a complete example tfvars file showing all major configuration options. Copy this as a starting point and customize for your organization.

organization = {
  organization_name                 = "my-org"
  payer_name                        = "My Org Management Account"
  payer_email                       = "aws+payer@example.com"
  security_account_name             = "my-org-security"
  security_account_root_email       = "aws+security@example.com"
  cloudtrail_bucket_name            = "my-org-cloudtrail"
  cloudtrail_loggroup_name          = "CloudTrail/DefaultLogGroup"
  billing_data_bucket_name          = "my-org-cur"
  cur_report_frequency              = "DAILY"   # DAILY, HOURLY, or MONTHLY
  session_duration                  = "PT8H"
  admin_permission_set_name         = "AdministratorAccess"
  admin_group_name                  = "AllAdmins"
  disable_sso_management            = false
  deploy_audit_role                 = true
  audit_role_name                   = "security-audit"
  audit_role_stack_set_template_url = "https://s3.amazonaws.com/pht-cloudformation/aws-account-automation/AuditRole-Template.yaml"
  declarative_policy_bucket_name    = "my-org-account-status"
  vpc_flowlogs_bucket_name          = "my-org-flowlogs"
  macie_bucket_name                 = "my-org-macie-findings"

  # Custom OUs (in addition to the four required OUs)
  organization_units = {
    "Platform" = {
      name             = "Platform"
      is_child_of_root = true
    }
  }

  # AWS Accounts
  accounts = {
    dev = {
      account_name          = "my-org-dev"
      account_email         = "aws+dev@example.com"
      monthly_budget_amount = 500
    }

    prod = {
      account_name   = "my-org-prod"
      account_email  = "aws+prod@example.com"
      parent_ou_name = "Workloads"
    }

    sandbox = {
      account_name   = "my-org-sandbox"
      account_email  = "aws+sandbox@example.com"
      parent_ou_name = "Sandbox"
    }

    sso = {
      account_name    = "my-org-sso"
      account_email   = "aws+sso@example.com"
      parent_ou_name  = "Governance"
      delegated_admin = ["sso.amazonaws.com"]
    }
  }

  # Alternate contacts applied to all accounts (can be overridden per account)
  global_billing_contact = {
    name          = "Finance Team"
    title         = "CFO"
    email_address = "billing@example.com"
    phone_number  = "+14041234567"
  }

  global_security_contact = {
    name          = "Security Team"
    title         = "CISO"
    email_address = "security@example.com"
    phone_number  = "+14041234567"
  }

  global_primary_contact = {
    full_name       = "IT Operations"
    company_name    = "My Org, Inc."
    address_line_1  = "123 Main Street"
    city            = "Atlanta"
    state_or_region = "GA"
    postal_code     = "30332"
    country_code    = "US"
    email_address   = "aws@example.com"
    phone_number    = "+14041234567"
  }

  # Service Control Policies
  service_control_policies = {
    deny_root = {
      policy_name        = "DenyRoot"
      policy_description = "Denies use of root user"
      policy_json_file   = "policies/DenyRootSCP.json"
    }

    security_controls = {
      policy_name        = "DefaultSecurityControls"
      policy_description = "Base security controls for all accounts"
      policy_json_file   = "policies/SecurityControlsSCP.json.tftpl"
      policy_vars = {
        audit_role_name = "security-audit"
      }
    }
  }

  # Resource Control Policies
  resource_control_policies = {
    s3_data_perimeter = {
      policy_name        = "S3DataPerimeter"
      policy_description = "Restricts S3 to principals inside the org"
      policy_json_file   = "policies/RCP_S3DataPerimeter.json.tftpl"
      policy_vars = {
        org_id = "o-xxxxxxxxxxxx"
      }
    }
  }

  # Declarative Policies
  declarative_policies = {
    deny_public_ami = {
      policy_name        = "Block_Public_AMIs"
      policy_description = "Deny public sharing of all AMIs"
      policy_type        = "DECLARATIVE_POLICY_EC2"
      policy_json_file   = "policies/EC2ImageBPA_DCP.json"
      policy_targets     = ["Workloads", "Governance", "Sandbox"]
    }
  }

  # Security Services
  security_services = {
    disable_guardduty   = false
    disable_securityhub = false
    disable_macie       = false
  }

  # Billing Alerts
  billing_alerts = {
    levels = {
      level1  = 100
      level2  = 500
      oh_shit = 1000
    }
    subscriptions = ["billing-alerts@example.com"]
  }

  budget_defaults = {
    alert_recipients      = ["finance@example.com"]
    currency              = "USD"
    warning_percentage    = 80
    organizational_budget = 1000
  }
}

backend_bucket = "my-org-terraform-state-123456789012"

Backend Config File

Create a my-org.tfbackend file alongside your tfvars:

bucket = "my-org-terraform-state-123456789012"
key    = "org-kickstart.tfstate"
region = "us-east-1"

Then initialize with:

terraform init -backend-config="my-org.tfbackend"

3 - Examples

Example configurations and pipeline setups.

Pipeline Example

The examples/pipeline directory in the repository contains a sample layout for a private CI/CD deployment repo. This shows how to structure your organization-specific configuration files alongside the module.

Sample tfvars

See the Example tfvars page for a full annotated example configuration file covering all major options.

Policy Library

Ready-to-use policy files are available in the policies/ directory:

  • DenyRootSCP.json — Deny root user access
  • SecurityControlsSCP.json.tftpl — Base security guardrails
  • DisableRegionsPolicy.json.tftpl — Region restrictions
  • RCP_S3DataPerimeter.json.tftpl — S3 data perimeter
  • EC2IMDSv2Enforce_DCP.json — IMDSv2 enforcement
  • And more…

Importing an Existing Organization

See Importing an Existing Organization for a step-by-step guide on adopting Org Kickstart in an existing AWS Organization.

4 - Concepts

Key concepts and architecture behind Org Kickstart.

AWS Organizations Structure

Org Kickstart manages resources in two AWS accounts simultaneously using Terraform’s multi-provider pattern:

  • Management (Payer) Account — Where Terraform runs. Contains the Organization, OUs, SCPs, RCPs, Declarative Policies, CloudTrail, and SSO/Identity Center.
  • Security Account — A dedicated account that is Delegated Administrator for GuardDuty, Macie, Inspector, Security Hub, CloudFormation StackSets, and optionally SSO.

Required Organizational Units

Four OUs are always created and cannot be disabled:

OU Purpose
Governance Security and payer accounts
Workloads Production workload accounts
Sandbox Development accounts with more freedom
Suspended Accounts pending closure

Policy Types

AWS Organizations supports three types of preventive controls, all managed by Org Kickstart:

Type Abbreviation Scope
Service Control Policies SCP What IAM principals can do
Resource Control Policies RCP What can be done to resources
Declarative Policies DP Baseline configuration of AWS services (EC2 only)

All three are defined using the same Terraform structure and support .tftpl templating.

Security Services

Org Kickstart enables and configures the following security services across all default AWS regions and all accounts in the organization:

  • GuardDuty — Threat detection. Payer and Security account both run detectors.
  • Security Hub — Aggregated security findings. Security Account is delegated admin.
  • Inspector — Vulnerability management. Security Account is delegated admin.
  • Macie — S3 data security. Security Account is delegated admin.

Audit Role

A cross-account audit role is deployed to every account via CloudFormation StackSets. The role trusts the Security Account, allowing centralized read access for security tools and audits without needing IAM users in every account.

Account Factory Pattern

New AWS accounts are defined in the accounts map in tfvars. The account module handles everything automatically:

  1. Creates the AWS Organizations account
  2. Places it in the correct OU
  3. Assigns SSO access (via Identity Center group and Permission Set)
  4. Sets billing, operations, and security alternate contacts
  5. Creates a budget with alert thresholds
  6. Applies SCPs/RCPs/Declarative Policies inherited from the parent OU

5 - Tasks

How-to guides for common Org Kickstart operations.

This section contains task-oriented guides for common Org Kickstart operations.

Common Tasks

5.1 - Adding a New Account

How to add a new AWS account to your organization.

Adding a new AWS account is the most common operation in Org Kickstart. All account configuration lives in the accounts map in your tfvars file.

Steps

  1. Add an entry to the accounts map in your tfvars file:

    accounts = {
      # ... existing accounts ...
    
      my_new_account = {
        account_name  = "my-org-new-account"
        account_email = "aws+new-account@example.com"
        parent_ou_name = "Workloads"
        monthly_budget_amount = 500
      }
    }
    
  2. Plan and apply:

    make env=your-org tf-execute
    

    Or step-by-step to review the plan before applying:

    make env=your-org tf-plan
    make env=your-org tf-show
    make env=your-org tf-apply
    

Org Kickstart will create the AWS account, place it in the correct OU, assign SSO access, set alternate contacts, and apply any policies that target the parent OU.

Account Options

Option Description
account_name Display name for the AWS account
account_email Root email address (must be globally unique)
parent_ou_name Place the account in this OU (by name)
parent_ou_id Place the account in this OU (by ID)
monthly_budget_amount Budget alert threshold in USD
delegated_admin List of AWS services to delegate admin for
close_on_deletion Whether to close the account when removed from Terraform
primary_contact Override the global primary contact for this account

Notes

  • The account_email must be unique across all AWS accounts globally
  • New accounts are created by AWS Organizations and may take a few minutes to become available
  • The Security Account is managed separately via the security_account block

5.2 - Creating Policies

How to create and attach SCPs, RCPs, and Declarative Policies.

Org Kickstart manages three types of AWS Organizations policies via the same Terraform pattern: Service Control Policies (SCPs), Resource Control Policies (RCPs), and Declarative Policies.

Steps

  1. Create a policy JSON file in the policies/ directory of your deployment repo. For dynamic values, use a .tftpl extension and Terraform template syntax.

    // policies/MyPolicy.json
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Deny",
          "Action": "s3:DeleteBucket",
          "Resource": "*"
        }
      ]
    }
    
  2. Add the policy definition to the appropriate block in your tfvars file:

    service_control_policies = {
      deny_s3_delete = {
        policy_name        = "DenyS3BucketDeletion"
        policy_description = "Prevent deletion of S3 buckets"
        policy_json_file   = "policies/MyPolicy.json"
        policy_targets     = ["Workloads", "Sandbox"]
      }
    }
    
  3. Plan and apply:

    make env=your-org tf-execute
    

    SCPs and RCPs are high-impact changes. Always review the plan before applying:

    make env=your-org tf-plan
    make env=your-org tf-show
    make env=your-org tf-apply
    

    You can also run a security scan of the plan with Checkov before applying:

    make env=your-org checkov
    

Policy Types

Block AWS Type
service_control_policies Service Control Policy (SCP)
resource_control_policies Resource Control Policy (RCP)
declarative_policies Declarative Policy (EC2)

Declarative Policies also require policy_type = "DECLARATIVE_POLICY_EC2".

Targeting OUs

policy_targets accepts a list of OU names or OU IDs. Use "Root" to target the organization root:

policy_targets = ["Root"]                          # all accounts
policy_targets = ["Workloads", "Sandbox"]          # by name
policy_targets = ["ou-xxxx-xxxxxxxx"]             # by ID

Templated Policies

For policies that need org-specific values, use a .tftpl file:

// policies/AuditRoleProtection.json.tftpl
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Deny",
    "Action": ["iam:Delete*"],
    "Resource": "arn:aws:iam::*:role/${audit_role_name}"
  }]
}
service_control_policies = {
  protect_audit_role = {
    policy_name      = "ProtectAuditRole"
    policy_json_file = "policies/AuditRoleProtection.json.tftpl"
    policy_vars = {
      audit_role_name = "security-audit"
    }
  }
}

Sample Policies

See the policies/ directory in the repository for a library of ready-to-use policies. Or check out PrimeHarbor’s respository of Organizational Policies.

6 - Tutorials

End-to-end walkthroughs for common Org Kickstart scenarios.

Step-by-step tutorials for common deployment scenarios.

7 - Reference

Variable reference, policy library, and module documentation.

This section contains low-level reference documentation for Org Kickstart.

In This Section

Source

The complete module documentation is generated from the Terraform source and available in the ModuleDocs.md file in the repository.

Policy Library

Sample policies are included in the policies/ directory of the repository:

File Type Description
DenyRootSCP.json SCP Deny use of root user in all accounts
SecurityControlsSCP.json.tftpl SCP Base security controls (requires audit_role_name)
DisableRegionsPolicy.json.tftpl SCP Restrict to approved AWS regions
DenyUnapprovedInstanceTypes.json SCP Deny non-approved EC2 instance types
DenyUnapprovedServices.json SCP Deny unapproved AWS services
SuspendedAccountsPolicy.json.tftpl SCP Deny all activity in suspended accounts
RCP_S3DataPerimeter.json.tftpl RCP Restrict S3 access to org principals
EC2ImageBPA_DCP.json Declarative Block public sharing of AMIs
EC2SnapshotBPA_DCP.json Declarative Block public sharing of EBS snapshots
EC2IMDSv2Enforce_DCP.json Declarative Enforce IMDSv2 with hop limit of 2

Policies with the .tftpl extension support Terraform template variables via policy_vars.

7.1 - Module Documentation

Auto-generated Terraform module reference — inputs, outputs, resources, and sub-modules.

Requirements

Name Version
aws >= 5.80.0

Providers

Name Version
aws >= 5.80.0
aws.security-account >= 5.80.0
external n/a

Modules

Name Source Version
accounts ./modules/account n/a
billing_alerts ./modules/billing_alerts n/a
declarative_policies ./modules/declarative_policies n/a
rcp ./modules/rcp n/a
scp ./modules/scp n/a
security_account ./modules/account n/a

Resources

Name Type
aws_account_alternate_contact.billing resource
aws_account_alternate_contact.operations resource
aws_account_alternate_contact.security resource
aws_account_primary_contact.primary resource
aws_cloudformation_stack.account_factory resource
aws_cloudformation_stack.audit_role_payer resource
aws_cloudformation_stack_set.audit_role resource
aws_cloudformation_stack_set_instance.audit_role resource
aws_cloudtrail.org_cloudtrail resource
aws_cloudwatch_log_group.cloudtrail resource
aws_cur_report_definition.cur_report_definition resource
aws_iam_organizations_features.org resource
aws_iam_role.cloudtrail_to_cloudwatch resource
aws_iam_role_policy.cloudtrail_to_cloudwatch resource
aws_identitystore_group.admin_group resource
aws_kms_alias.macie_key resource
aws_kms_key.macie_key resource
aws_kms_key_policy.macie_key resource
aws_organizations_account.payer resource
aws_organizations_delegated_administrator.cloudformation resource
aws_organizations_delegated_administrator.securityhub resource
aws_organizations_delegated_administrator.sso resource
aws_organizations_organization.org resource
aws_organizations_organizational_unit.custom_ous resource
aws_organizations_organizational_unit.governance_ou resource
aws_organizations_organizational_unit.sandbox_ou resource
aws_organizations_organizational_unit.suspended_ou resource
aws_organizations_organizational_unit.workloads_ou resource
aws_organizations_policy.ai_policy resource
aws_organizations_policy_attachment.ai_policy_root resource
aws_s3_bucket.billing_logs resource
aws_s3_bucket.cloudtrail_bucket resource
aws_s3_bucket.declarative_policy_bucket resource
aws_s3_bucket.macie_bucket resource
aws_s3_bucket.vpc_flowlogs_bucket resource
aws_s3_bucket_notification.bucket_notification resource
aws_s3_bucket_ownership_controls.cloudtrail_bucket resource
aws_s3_bucket_ownership_controls.declarative_policy_bucket resource
aws_s3_bucket_ownership_controls.macie_bucket resource
aws_s3_bucket_ownership_controls.vpc_flowlogs_bucket resource
aws_s3_bucket_policy.allow_billing_logging resource
aws_s3_bucket_policy.cloudtrail_bucket_policy resource
aws_s3_bucket_policy.declarative_policy_bucket_policy resource
aws_s3_bucket_policy.macie_bucket_policy resource
aws_s3_bucket_policy.vpc_flowlogs_bucket_policy resource
aws_s3_bucket_public_access_block.cloudtrail_bucket_bpa resource
aws_s3_bucket_public_access_block.declarative_policy_bucket_bpa resource
aws_s3_bucket_public_access_block.macie_bucket_bpa resource
aws_s3_bucket_public_access_block.vpc_flowlogs_bucket_bpa resource
aws_s3_bucket_server_side_encryption_configuration.macie_bucket resource
aws_s3_bucket_versioning.cloudtrail_bucket resource
aws_s3_bucket_versioning.declarative_policy_bucket resource
aws_s3_bucket_versioning.macie_bucket resource
aws_s3_bucket_versioning.vpc_flowlogs_bucket resource
aws_s3_object.account_factory_config resource
aws_securityhub_account.payer_account resource
aws_securityhub_account.security_account resource
aws_securityhub_configuration_policy.no_enabled_standards resource
aws_securityhub_configuration_policy_association.root_ou resource
aws_securityhub_finding_aggregator.regional_aggregator resource
aws_securityhub_organization_admin_account.delegated_admin resource
aws_securityhub_organization_configuration.security_account resource
aws_sns_topic.cloudtrail_s3_notification_topic resource
aws_ssoadmin_account_assignment.payer_account_group_assignment resource
aws_ssoadmin_managed_policy_attachment.admin_policy_attachments resource
aws_ssoadmin_permission_set.admin_permission_set resource
aws_billing_service_account.main data source
aws_iam_policy_document.allow_billing_logging data source
aws_iam_policy_document.cloudtrail_bucket_policy data source
aws_iam_policy_document.cloudtrail_s3_notification_topic data source
aws_iam_policy_document.declarative_policy_bucket_policy data source
aws_iam_policy_document.macie_bucket_policy data source
aws_iam_policy_document.vpc_flowlogs_bucket_policy data source
aws_organizations_organization.org data source
aws_organizations_organizational_units.all_ous data source
aws_regions.current data source
aws_ssoadmin_instances.identity_store data source
external_external.get_caller_identity data source

Inputs

Name Description Type Default Required
account_configurator n/a any null no
accounts Account Index any n/a yes
admin_group_name Name of the Identity Store Group with all the admin users string "AllAdmins" no
admin_permission_set_name Name of the Permission Set to Create string "AdministratorAccess" no
audit_role_name Name of the AuditRole to deploy string "security-audit" no
audit_role_stack_set_template_url URL that points to the Audit Role Policy Template string null no
backend_bucket n/a any n/a yes
billing_alerts n/a any null no
billing_data_bucket_name Name of the S3 Bucket for CUR reports. Set to null to disable string null no
cloudtrail_bucket_name Name of the S3 Bucket to create to store CloudTrail events. Set to null to disable cloudtrail management string null no
cloudtrail_loggroup_name Name of the CloudWatch Log Group in the payer account where CloudTrail will send its events string null no
cur_report_frequency Frequency CUR reports should be delivered (DAILY, HOURLY, MONTHLY). Set to NONE to disable string "NONE" no
declarative_policies Map of Declarative Policies to deploy map {} no
declarative_policy_bucket_name Name of S3 Bucket for Declarative Policy Reports any null no
deploy_audit_role Boolean to determine if org-kickstart should manage Audit Role bool true no
disable_sso_management Set to true to manage AWS Identity Center outside of org-kickstart bool false no
global_billing_contact Map for the central billing alternate contact to be applied to all accounts any null no
global_operations_contact Map for the central operations alternate contact to be applied to all accounts any null no
global_primary_contact Map for the primary account owner to be applied to all accounts any null no
global_security_contact Map for the central security alternate contact to be applied to all accounts any null no
macie_bucket_name Name of the S3 Bucket to create to store Macie Findings. Set to null to skip creation string null no
organization_name Name of the Organization. This is used for resource prefixes and general reference string n/a yes
organization_units Map of OUs to deploy map {} no
payer_email Root Email address for the Organization Management account string null no
payer_name Name of the Organization Management account string "AWS Payer" no
resource_control_policies Map of RCPs to deploy map {} no
security_account_name Name of the Security Account string "Security Account" no
security_account_root_email Root Email address for the security account string null no
security_services explictly disable or not manage a security service map
{
“disable_guardduty”: “false”,
“disable_inspector”: “false”,
“disable_macie”: “false”,
“disable_securityhub”: “false”
}
no
service_control_policies Map of SCPs to deploy map {} no
session_duration Default Session Duration string "PT8H" no
tag_set Default map of tags to be applied to all resources via all providers map(any) {} no
vpc_flowlogs_bucket_name Name of the S3 Bucket to create to store VPC Flow Logs. Set to null to skip creation string null no

Outputs

Name Description
cloudtrail_cloudwatch_log_group n/a
cloudtrail_s3_notification_topic n/a
declarative_policy_bucket n/a
macie_key_arn Things to pass to the Security Services Regional Modules
org_id n/a
org_name n/a
security_account_id n/a
sso_instance_arn AWS Identity Center Instance ARN managed by org-kickstart

7.2 - Parameter Reference

All Terraform variables for the Org Kickstart module.

All configuration is passed via the organization variable (an object type) and a few top-level variables. Below are the key configuration parameters.

Top-Level Variables

Variable Type Required Description
organization object Yes Main configuration object (see below)
backend_bucket string Yes S3 bucket name for Terraform state

Organization Object

Core Identity

Parameter Type Required Description
organization_name string Yes Short name for the organization
payer_name string Yes Display name for the management account
payer_email string Yes Root email of the management account
security_account_name string Yes Display name for the security account
security_account_root_email string Yes Root email for the new security account

CloudTrail

Parameter Type Default Description
cloudtrail_bucket_name string required S3 bucket for CloudTrail logs. Set null to disable
cloudtrail_loggroup_name string "CloudTrail/DefaultLogGroup" CloudWatch Log Group name

SSO / Identity Center

Parameter Type Default Description
session_duration string "PT8H" ISO 8601 duration for SSO sessions
admin_permission_set_name string "AdministratorAccess" Name of the admin Permission Set
admin_group_name string "AllAdmins" Name of the admin Identity Center group
disable_sso_management bool false Set true to stop Terraform from managing SSO

Audit Role

Parameter Type Default Description
deploy_audit_role bool true Deploy the cross-account audit role StackSet
audit_role_name string "security-audit" Name of the audit role in each account
audit_role_stack_set_template_url string required if deploy S3 URL to the CloudFormation template

Billing

Parameter Type Required Description
billing_data_bucket_name string Yes S3 bucket for CUR reports
cur_report_frequency string "DAILY" DAILY, HOURLY, MONTHLY, or "NONE" to disable
declarative_policy_bucket_name string Yes S3 bucket for declarative policy documents

Security Services

Configure which security services to enable/disable:

security_services = {
  disable_guardduty   = false
  disable_securityhub = false
  disable_macie       = false
}

Organizational Units

Four OUs are always created: Governance, Workloads, Sandbox, Suspended. Additional OUs can be defined:

organization_units = {
  "MyOU" = {
    name             = "MyOU"
    is_child_of_root = true
  }
  "NestedOU" = {
    name         = "NestedOU"
    parent_id    = "MyOU"   # use parent OU name for direct children of custom OUs
  }
}

Accounts

Each account in the accounts map:

accounts = {
  my_account = {
    account_name          = "my-org-prod"        # AWS account display name
    account_email         = "aws+prod@example.com" # root email (must be unique)
    parent_ou_name        = "Workloads"           # OU name (or use parent_ou_id)
    monthly_budget_amount = 1000                  # optional, in USD
    delegated_admin       = ["service.amazonaws.com"]  # optional
    close_on_deletion     = false                 # optional

    # Optional: override primary contact for this account
    primary_contact = {
      full_name       = "Account Owner"
      company_name    = "My Org"
      address_line_1  = "123 Main St"
      city            = "Atlanta"
      state_or_region = "GA"
      postal_code     = "30332"
      country_code    = "US"
      email_address   = "owner@example.com"
      phone_number    = "+14041234567"
    }
  }
}

Alternate Contacts

Applied org-wide (overridable per account):

global_billing_contact = {
  name          = "Name"
  title         = "CFO"
  email_address = "billing@example.com"
  phone_number  = "+1xxxxxxxxxx"
}

global_security_contact = {
  name          = "Name"
  title         = "CISO"
  email_address = "security@example.com"
  phone_number  = "+1xxxxxxxxxx"
}

global_operations_contact = {
  name          = "Name"
  title         = "VP Engineering"
  email_address = "ops@example.com"
  phone_number  = "+1xxxxxxxxxx"
}

global_primary_contact = {
  full_name       = "Name"
  company_name    = "My Org"
  address_line_1  = "123 Main St"
  city            = "Atlanta"
  state_or_region = "GA"
  postal_code     = "30332"
  country_code    = "US"
  email_address   = "aws@example.com"
  phone_number    = "+1xxxxxxxxxx"
}

Policies

All three policy types follow the same structure:

service_control_policies = {
  my_policy = {
    policy_name        = "MyPolicy"
    policy_description = "Description"
    policy_json_file   = "policies/MyPolicy.json"
    policy_targets     = ["Workloads", "ou-xxxx-xxxxxxxx"]  # OU names or IDs
    policy_vars = {                                         # for .tftpl files
      variable_name = "value"
    }
  }
}

The same structure applies to resource_control_policies and declarative_policies (which also require policy_type = "DECLARATIVE_POLICY_EC2").

Billing Alerts

billing_alerts = {
  levels = {
    level1  = 100   # USD threshold
    level2  = 500
    oh_shit = 1000
  }
  subscriptions = ["email@example.com"]
}

budget_defaults = {
  alert_recipients      = ["email@example.com"]
  currency              = "USD"
  warning_percentage    = 80
  organizational_budget = 1000
}

8 - Contribution Guidelines

How to contribute to Org Kickstart

We welcome contributions to both the Terraform module and this documentation site. All submissions require review via GitHub pull request.

Contributing to the Module

  1. Fork the org-kickstart repo on GitHub
  2. Create a feature branch
  3. Make your changes and test them against a real AWS Organization (see the CLAUDE.md for testing guidance)
  4. Send a pull request with a clear description of the change and why it’s needed

Testing

When modifying the module:

  • Use make env=your-org tf-plan extensively before applying
  • Test in a non-production organization first
  • Use targeted applies for risky changes: terraform apply -var-file="your-org.tfvars" -target <resource>
  • Verify SCPs don’t lock out root or prevent remediation

Contributing to the Docs

The documentation source lives in the org-kickstart-site/ directory alongside the module.

Running the Site Locally

Requirements:

  • Hugo extended >= 0.155.0
  • Node.js (for PostCSS/SCSS processing)
cd org-kickstart-site
make npm        # install Node dependencies (first time only)
make test       # starts dev server at http://localhost:1319/

Use make test-drafts to also render draft and future-dated content.

Editing Pages

  1. Fork the org-kickstart-site repo
  2. Edit files under org-kickstart-site/content/en/
  3. Preview locally with make test
  4. Submit a pull request

You can also click Edit this page in the top right of any documentation page to jump directly to the source file on GitHub.

Creating an Issue

Found a bug or want to request a feature? Open an issue on GitHub.

Useful Resources