This module sets up an AWS Organization with org-level services, including Guard Duty, Security Hub, AWS Config, and Cloudtrail.
FedRAMP Compliance: Moderate, High
A high-level list of resources created as a part of this module.
- AWS Organization with org level services
- Cloudtrail
- AWS Organization policy
- IAM role and policy
- KMS keys and typically required IAM permissions for commonly used services (S3, DynamoDB, Config).
- S3 buckets (ORG CloudTrail, Config, Backups, State)
Example for how to call the module below with generic variables:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "=4.58"
}
}
}
module "aws_org" {
source = "github.com/Coalfire-CF/terraform-aws-organization"
service_access_principals = [
"backup.amazonaws.com",
"config.amazonaws.com",
"cloudtrail.amazonaws.com",
"guardduty.amazonaws.com",
"malware-protection.guardduty.amazonaws.com",
"member.org.stacksets.cloudformation.amazonaws.com",
"ram.amazonaws.com",
"securityhub.amazonaws.com",
"servicecatalog.amazonaws.com",
"ssm.amazonaws.com",
"sso.amazonaws.com",
"tagpolicies.tag.amazonaws.com"
]
org_account_name = "${var.resource_prefix}-org-root"
enabled_policy_types = ["SERVICE_CONTROL_POLICY"]
create_org_cloudtrail = var.create_org_cloudtrail
feature_set = "ALL"
aws_region = var.aws_region
default_aws_region = var.default_aws_region
resource_prefix = var.resource_prefix
account_number = var.account_number
create_cloudtrail = var.create_cloudtrail
is_organization = var.is_organization
organization_id = var.organization_id
}For org deployments where a delegated admin is required/needed:
module "org" {
## update source once branch is merged into main
source = "git::https://github.com/Coalfire-CF/terraform-aws-organization.git?ref=fa-aws-pakpt-update"
service_access_principals = [
"backup.amazonaws.com",
"config.amazonaws.com",
"cloudtrail.amazonaws.com",
"guardduty.amazonaws.com",
"malware-protection.guardduty.amazonaws.com",
"member.org.stacksets.cloudformation.amazonaws.com",
"ram.amazonaws.com",
"securityhub.amazonaws.com",
"servicecatalog.amazonaws.com",
"ssm.amazonaws.com",
"sso.amazonaws.com",
"tagpolicies.tag.amazonaws.com"
]
org_account_name = "${var.resource_prefix}-org-root"
enabled_policy_types = ["SERVICE_CONTROL_POLICY"]
create_org_cloudtrail = var.create_org_cloudtrail
feature_set = "ALL"
aws_region = var.aws_region
default_aws_region = var.default_aws_region
resource_prefix = var.resource_prefix
account_number = var.account_number
create_cloudtrail = var.create_cloudtrail
is_organization = var.is_organization
organization_id = var.organization_id
}
## Full Delegate Admin Policy ##
resource "aws_organizations_resource_policy" "admin_delegate" {
content = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DelegatingAdmin",
"Effect": "Allow",
"Principal": {
"AWS": "arn:${local.partition}:iam::${local.mgmt_plane_account_id}:root"
},
"Action": [
"organizations:CreatePolicy",
"organizations:UpdatePolicy",
"organizations:DeletePolicy",
"organizations:AttachPolicy",
"organizations:DetachPolicy",
"organizations:EnablePolicyType",
"organizations:DisablePolicyType",
"organizations:DescribeOrganization",
"organizations:DescribeOrganizationalUnit",
"organizations:DescribeAccount",
"organizations:DescribePolicy",
"organizations:DescribeEffectivePolicy",
"organizations:ListRoots",
"organizations:ListOrganizationalUnitsForParent",
"organizations:ListParents",
"organizations:ListChildren",
"organizations:ListAccounts",
"organizations:ListAccountsForParent",
"organizations:ListPolicies",
"organizations:ListPoliciesForTarget",
"organizations:ListTargetsForPolicy",
"organizations:ListTagsForResource"
],
"Resource": "*"
}
]
}
EOF
}
NOTE: This resource must be commented out on the first run of your terraform plan/apply of aws-org since it will throw an error that an organization is required for this to be created ("Your account is not a member of an organization"). Once you run the first apply and obtain the organization_id, you can add this back in for the second round of terraform apply.
Included in the available-SCPs directory are a set of commonly used Service Control Policies, otherwise known as SCPs. These SCPs can be used to strengthen your AWS Organization's security posture
Each of them can be modified to meet your needs, such as partition changes, additional tags, or any additional roles to be permitted to perform certain actions.
This link can help visualize how to assign your SCPs, whether root, OU or account based.
Copy and save any applicable SCP terraform files in the same directory as where you called the terraform-aws-organization module
Below is some examples of how you can use and apply SCPs to your organization.
Creating a policy:
resource "aws_organizations_policy" "DenyLeavingOrg" {
name = "Prevent member accounts from leaving the organization"
content = data.aws_iam_policy_document.example.json
}Account targeted SCP
resource "aws_organizations_policy_attachment" "ProdDenyOrgLeavy" {
policy_id = aws_organizations_policy.DenyLeavingOrg.id
target_id = "123456789012"
}Org Root targeted SCP
resource "aws_organizations_policy_attachment" "RootDenyOrgLeavy" {
policy_id = aws_organizations_policy.DenyLeavingOrg.id
target_id = aws_organizations_organization.gov-org.roots[0].id
}Org Unit targeted SCP
resource "aws_organizations_policy_attachment" "ProdOUDenyOrgLeavy" {
policy_id = aws_organizations_policy.DenyLeavingOrg.id
target_id = aws_organizations_organizational_unit.prod.id
}Establish a secure connection to the Management AWS account used for the build:
IAM user authentication:
- Download and install the AWS CLI (https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
- Log into the AWS Console and create AWS CLI Credentials (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html)
- Configure the named profile used for the project, such as 'aws configure --profile example-mgmt'
SSO-based authentication (via IAM Identity Center SSO):
- Login to the AWS IAM Identity Center console, select the permission set for MGMT, and select the 'Access Keys' link.
- Choose the 'IAM Identity Center credentials' method to get the SSO Start URL and SSO Region values.
- Run the setup command 'aws configure sso --profile example-mgmt' and follow the prompts.
- Verify you can run AWS commands successfully, for example 'aws s3 ls --profile example-mgmt'.
- Run 'export AWS_PROFILE=example-mgmt' in your terminal to use the specific profile and avoid having to use '--profile' option.-
Navigate to the Terraform project and create a parent directory in the upper level code, for example:
../{CLOUD}/terraform/{REGION}/management-account/example
If multi-account management plane:
../{CLOUD}/terraform/{REGION}/{ACCOUNT_TYPE}-mgmt-account/example
-
Create a properly defined main.tf file via the template found under 'Usage' while adjusting 'auto.tfvars' as needed. Example parent directory:
├── Example/ │ ├── example.auto.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── providers.tf │ ├── required-providers.tf │ ├── remote-data.tf │ ├── variables.tf │ ├── ...
Example 'auto.tfvars':
aws_region = "us-gov-west-1" default_aws_region = "us-gov-west-1" account_number = "01010101010101" resource_prefix = "test-org" create_cloudtrail = true # This is always set to true to create the cloudtrail S3 bucket using account setup PAK # Set both to FALSE on first apply, then run again with TRUE to apply the org cloudtrail and organization ID to policies create_org_cloudtrail = false is_organization = false # Uncomment on second run with ORG ID obtained from the output of the first run #organization_id = ""
-
Configure Terraform local backend and stage remote backend. For the first run, the entire contents of the 'remote-data.tf' file must be commented out with terraform local added to facilitate local state setup, like below:
//terraform { // backend "s3" { // bucket = "{resource_prefix}-{region}-tf-state" // region = "{region}" // key = "{resource_prefix}-{region}-org-setup.tfstate" // encrypt = true // use_lockfile = true // } //} terraform { backend "local"{} }
-
Initialize the Terraform working directory:
terraform init
Create an execution plan and verify the resources being created:
terraform plan
Apply the configuration:
terraform apply
-
After the deployment has succeeded, uncomment the contents of 'remote-state.tf' and remove the terraform local code block.
-
Follow the directions on the example 'auto.tfvars' previously provided to create cloudtrail and update policies. You will need to update 'create_org_cloudtrail' and 'is_organization' to 'true' while uncommenting and adding 'organization_id' value. You can also add in the Delegate Admin Policy resource now too.
-
Create an execution plan and verify the resources being created:
terraform plan
Apply the configuration:
terraform apply
-
Run 'terraform init -migrate-state' and follow the prompts to migrate the local state file to the appropriate S3 bucket in the AWS Master Payer account.
Ensure you invite other AWS accounts to the organization, then accept the invitations in each child account.
Depending on the context of the build out of this module, the role OrganizationAccountAccessRole may need to be manually created in each child project. The trust relationship of this role must include other AWS accounts that use cross project resource provisioning. See reference https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts_create-cross-account-role.html
No requirements.
| Name | Version |
|---|---|
| aws | n/a |
| Name | Source | Version |
|---|---|---|
| account_setup | git::https://github.com/Coalfire-CF/terraform-aws-account-setup | v0.2.4 |
| Name | Type |
|---|---|
| aws_cloudtrail.org-trail | resource |
| aws_iam_role.aws_config_org_role | resource |
| aws_iam_role_policy_attachment.organization | resource |
| aws_organizations_organization.org | resource |
| aws_caller_identity.current | data source |
| aws_iam_policy_document.assume_role | data source |
| aws_iam_policy_document.controltower_kms | data source |
| aws_partition.current | data source |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| account_number | The AWS account number resources are being deployed into | string |
n/a | yes |
| aws_region | n/a | string |
n/a | yes |
| config_cross_account_ids | AWS account IDs allowed cross-account access to the Config bucket | list(string) |
[] |
no |
| create_cloudtrail | Whether or not to create cloudtrail resources | bool |
n/a | yes |
| create_org_cloudtrail | True/False statement whether to enable AWS Cloudtrail in the Organization | bool |
n/a | yes |
| default_aws_region | The default AWS region to create resources in | string |
n/a | yes |
| enabled_policy_types | List of Organizations policy types to enable in the Organization Root. Organization must have feature_set set to ALL. For additional information about valid policy types (e.g., AISERVICES_OPT_OUT_POLICY, BACKUP_POLICY, SERVICE_CONTROL_POLICY, and TAG_POLICY) | list(string) |
[ |
no |
| feature_set | Feature set to be used with Org and member accounts Specify ALL(default) or CONSOLIDATED_BILLING. | string |
"ALL" |
no |
| is_organization | Whether or not to enable certain settings for AWS Organization | bool |
n/a | yes |
| org_account_name | value to be used for the org account name | string |
n/a | yes |
| organization_id | AWS Organization ID | string |
n/a | yes |
| resource_prefix | n/a | string |
n/a | yes |
| service_access_principals | List of AWS Service Access Principals that you want to enable for organization integration | list(string) |
[ |
no |
Relative or absolute link to contributing.md
Absolute link to any relevant Coalfire Pages
Copyright © 2023 Coalfire Systems Inc.
.
|-- CHANGELOG.md
|-- CONTRIBUTING.md
|-- LICENSE
|-- README.md
|-- account-setup.tf
|-- available-SCPs
| |-- DenyLeaveOrg.tf
| |-- S3_public_access_block.tf
| |-- aws_region_lock.tf
| |-- deny-resource-creation-without-tags.tf
| |-- disable_use_of_instance_types.tf
| |-- mfa_required_changes.tf
| |-- prevent_aws_iam_changes.tf
| |-- prevent_changes_to_cloudtrail.tf
| |-- prevent_changes_to_guardduty.tf
| |-- prevent_vpcflowlog_deletion.tf
|-- cloudtrail.tf
|-- coalfire_logo.png
|-- data.tf
|-- iam.tf
|-- org.tf
|-- outputs.tf
|-- release-please-config.json
|-- variables.tf
