The AWS account set up module creates the initial account configuration for your project, including IAM roles, KMS keys, S3 installs bucket, and more.
FedRAMP Compliance: High
- If applicable: AWS Organization (AWS GOV ORG) ID (https://github.com/Coalfire-CF/terraform-aws-organization)
Resources that are created as a part of this module include:
- IAM role, policies, and instance profiles for Packer to assume during AMI creation (optional: one account can build and store Packer AMIs and share them with other accounts).
- KMS keys and typically required IAM permissions for commonly used services (S3, ELB, RDS, EBS, etc.).
- S3 buckets:
- ELB Access Logs bucket is optional. With multiple accounts: you can designate one as a centralized logging account and have other accounts send ELB logs to one account's bucket, this is not possible with S3 access logs where the bucket must be in the same account & region).
- Set 'create_s3_elb_accesslogs_bucket' to 'true' if this is run in an account where you want the logs to be sent.
- Optional: Security core module resources (Terraform state resources should only exist in the AWS Management account and AWS GOV ORG Root account).
There are 3 supported deployment configurations regarding IAM cross-account permissions. Sharing principally concerns S3 Buckets (where applicable) and KMS Key permissions.
Sharing based on AWS ORG (Recommended, easier to maintain since permissions are granted via AWS Organization ID instead of individual account IDs):
### Sharing ###
is_organization = true # Should be "false" if setting "application_account_numbers"
organization_id = "your-organization-id"
Standalone account (No cross-account sharing: Set "is_organization" to "false" (default is "true"), and you can omit "application_account_numbers" and "organization_id"):
### Sharing ###
is_organization = false # Should be "false" if setting "application_account_numbers"
Sharing is based on a list of AWS Account IDs:
### Sharing ###
application_account_numbers = ["account-number1", "account-number2", "account-number3"]
is_organization = false # Should be "false" if setting "application_account_numbers"
AWS Backups are based on the presence of a tag and can be applied to S3 buckets. The configuration depends on "s3_backup_settings" and "s3_backup_policy". At a minimum, "s3_backup_policy" must be defined in order for the S3 buckets to be tagged. "s3_backup_settings" is an optional map variable that lets you enable or disable AWS Backups on individual S3 buckets that this pak creates. The default value will NOT tag the S3 Access Logs, ELB Access Logs, or Cloudtrail buckets for AWS Backup. This is an opinionated default that assumes that a SIEM solution will ingest and store these logs, so having a backup is a waste of money. But if this is not true, then you can individually override this as shown in the example above. Example:
### AWS Backup ###
s3_backup_policy = "aws-backup-${var.resource_prefix}-default-policy"
s3_backup_settings = {
accesslogs = {
enable_backup = true # Normally "false" because we're assuming that a SIEM will ingest and store these logs
}
elb-accesslogs = {
enable_backup = true # Normally "false" because we're assuming that a SIEM will ingest and store these logs
}
backups = {
enable_backup = true
}
installs = {
enable_backup = true
}
fedrampdoc = {
enable_backup = true
}
cloudtrail = {
enable_backup = true # Normally "false" because we're assuming that a SIEM will ingest and store these logs
}
config = {
enable_backup = true
}
}
"Management plane" account: Terraform state is stored here, Packer AMIs are built here. This is different from the AWS GOV ORG Root account where AWS ORG should have been deployed.
module "account-setup" {
source = "github.com/Coalfire-CF/terraform-aws-account-setup?ref=vx.x.x"
aws_region = var.aws_region
default_aws_region = var.default_aws_region
account_number = var.account_number
resource_prefix = var.resource_prefix
### Cloudtrail ###
create_cloudtrail = var.create_cloudtrail # false
cloudwatch_log_group_retention_in_days = var.cloudwatch_log_group_retention_in_days # 30
### Secrets Manager ### (EC2 Keypair)
ssh_key_name = var.ssh_key_name
ssh_key_secret_name = var.ssh_key_secret_name
### KMS ### (Optional)
additional_kms_keys = [
{
name = "elasticache"
policy = "${data.aws_iam_policy_document.elasticache_key_policy.json}"
}
]
### Packer ###
create_packer_iam = var.create_packer_iam # true (Packer AMIs will be built and kept on this account and shared with other accounts (share accounts is provided to Packer as a variable at build time)
### Terraform ###
create_security_core = var.create_security_core # true (Terraform state will be kept on this account)
### Sharing ###
is_organization = var.is_organization # true (Should be "false" if setting "application_account_numbers")
organization_id = var.organization_id
### AWS Backup ###
s3_backup_policy = "aws-backup-${var.resource_prefix}-default-policy"
}
Optional: "AWS ORG Member account". This code is not intended to be deployed in every account unless there's a clear need for supporting infrastructure. Does not need Terraform resources (S3 bucket to store state, DynamoDB table for state lock since these will be stored in MGMT account), Packer AMIs will not be built in this account, is not a Management account for AWS Organizations, does not need to share IAM permissions (s3 buckets, KMS keys) to any other account. The default configuration also creates individually owned Customer KMS Keys.
module "account-setup" {
source = "github.com/Coalfire-CF/terraform-aws-account-setup?ref=vx.x.x"
# Use the OrganizationAccountAccessRole in member account to deploy resources into it using MGMT account CLI credentials
providers = {
aws = aws.example-member-account
}
## GLOBAL ##
aws_region = var.aws_region
default_aws_region = var.default_aws_region
account_number = var.account_number
resource_prefix = var.resource_prefix
### Sharing ###
is_organization = var.is_organization
organization_id = var.organization_id
### Secrets Manager ### (EC2 Keypair)
ssh_key_name = var.ssh_key_name
ssh_key_secret_name = var.ssh_key_secret_name
### AWS Backup ###
s3_backup_policy = "aws-backup-${var.resource_prefix}-default-policy"
### Disable Resources Not Needed ###
create_nfw_kms_key = false
create_config_kms_key = false
create_s3_config_bucket = false
create_s3_fedrampdoc_bucket = false
}
The 'OrganizationAccountAccessRole' roles are automatically created in each AWS GOV ORG member account (including MGMT) when they are added to the ORG and should by default only be assumed by the ORG root account. You will need to make sure that the MGMT plane account has access to assume the 'OrganizationAccountAccessRole' in each required member account it needs to deploy resources to by reviewing the trust relationship of the roles.
It is possible to specify custom resource names for most resources deployed by this module, in order to conform to a given naming convention. The following inputs are supported:
cloudtrail_name
cloudtrail_bucket_name
cloudtrail_log_group_name
cloudtrail_iam_role_name
packer_iam_role_name
packer_iam_policy_name
packer_iam_instanceprofile_name
packer_s3_kmsgrant_name
packer_ebs_kmsgrant_name
accesslogs_bucket_name
config_bucket_name
backups_bucket_name
elb_accesslogs_bucket_name
fedrampdoc_bucket_name
installs_bucket_name
module "account-setup" {
source = "github.com/Coalfire-CF/terraform-aws-account-setup?ref=vx.x.x"
...
cloudtrail_name = "example-cloudtrail-mgmt"
cloudtrail_bucket_name = "example-s3-cloudtrail-mgmt"
cloudtrail_log_group_name = "example-loggroup-cloudtrail-mgmt"
cloudtrail_iam_role_name = "example-iamrole-cloudtrail-mgmt"
packer_iam_role_name = "example-iamrole-packer-mgmt"
packer_iam_policy_name = "example-iampolicy-packer-mgmt"
packer_iam_instanceprofile_name = "example-instanceprof-packer-mgmt"
packer_s3_kmsgrant_name = "example-kmsgrant-packer-s3-mgmt"
packer_ebs_kmsgrant_name = "example-kmsgrant-packer-ebs-mgmt"
accesslogs_bucket_name = "example-s3-accesslogs-mgmt"
config_bucket_name = "example-s3-config-mgmt"
backups_bucket_name = "example-s3-backups-mgmt"
elb_accesslogs_bucket_name = "example-s3-elb-accesslogs-mgmt"
fedrampdoc_bucket_name = "example-s3-docs-mgmt"
installs_bucket_name = "example-s3-installs-mgmt"
...
}
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 tfvars as needed. Note that many provided variables are outputs from other modules. For 'Member Account' directories make sure to use a Terraform alias use management account credentials/settings to create resources in member account. Example parent directory:
├── Example/ │ ├── example.auto.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── providers.tf │ ├── required-providers.tf │ ├── remote-data.tf │ ├── variables.tf │ ├── ...
Optional: Example AWS GOV ORG Member Account 'providers.tf'. Set your alias to the account specified name ('example-member-account'). Alias should match the provider being used in main.tf file. Example:
provider "aws" { region = var.aws_region skip_region_validation = true profile = var.profile use_fips_endpoint = true alias = "example-member-account" assume_role { role_arn = "arn:${local.partition}:iam::${local.example_member_account_account_id}:role/OrganizationAccountAccessRole" } }
-
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}-account-setup.tfstate" // encrypt = true // use_lockfile = true // } //} terraform { backend "local"{} }
Optional: AWS ORG Member Account example. In 'remote-data.tf', set the key to a directory structure in the format show in the example below:
//terraform { // backend "s3" { // bucket = "{resource_prefix}-{region}-tf-state" // region = "{region}" // key = "{account_name}/{region}/{resource_prefix}-{region}-account-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.
-
Run 'terraform init -migrate-state' and follow the prompts to migrate the local state file to the appropriate S3 bucket in the management plane.
Name | Version |
---|---|
terraform | >=1.10.0 |
aws | ~> 5.0 |
Name | Version |
---|---|
aws | ~> 5.0 |
tls | n/a |
Name | Source | Version |
---|---|---|
additional_kms_keys | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
backup_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
cloudwatch_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
config_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
default_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
ebs_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
ecr_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
lambda_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
nfw_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
rds_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
s3-accesslogs | github.com/Coalfire-CF/terraform-aws-s3 | v1.0.4 |
s3-backups | github.com/Coalfire-CF/terraform-aws-s3 | v1.0.4 |
s3-cloudtrail | github.com/Coalfire-CF/terraform-aws-s3 | v1.0.4 |
s3-config | github.com/Coalfire-CF/terraform-aws-s3 | v1.0.4 |
s3-elb-accesslogs | github.com/Coalfire-CF/terraform-aws-s3 | v1.0.4 |
s3-fedrampdoc | github.com/Coalfire-CF/terraform-aws-s3 | v1.0.4 |
s3-installs | github.com/Coalfire-CF/terraform-aws-s3 | v1.0.4 |
s3_config_conformance_pack | github.com/Coalfire-CF/terraform-aws-s3 | v1.0.4 |
s3_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
security-core | github.com/Coalfire-CF/terraform-aws-securitycore | v0.0.24 |
sm_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
sns_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
sqs_kms_key | github.com/Coalfire-CF/terraform-aws-kms | v1.0.1 |
Name | Description | Type | Default | Required |
---|---|---|---|---|
accesslogs_bucket_name | (Optional) custom name for the access logs S3 bucket; if left undefined, a default name is created | string |
null |
no |
account_number | The AWS account number resources are being deployed into | string |
n/a | yes |
additional_kms_keys | a list of maps of any additional KMS keys that need to be created | list(map(string)) |
[] |
no |
application_account_numbers | AWS account numbers for all application accounts that might need shared access to resources like KMS keys | list(string) |
[] |
no |
aws_region | The AWS region to create resources in | string |
n/a | yes |
backups_bucket_name | (Optional) custom name for the backups S3 bucket; if left undefined, a default name is created | string |
null |
no |
cloudtrail_bucket_name | (Optional) custom name for the Cloudtrail S3 Bucket; if left undefined, a default name is created | string |
null |
no |
cloudtrail_iam_role_name | (Optional) custom name for the Cloudtrail to Cloudwatch IAM role; if left undefined, a default name is created | string |
null |
no |
cloudtrail_log_group_name | (Optional) custom name for the Cloudtrail log group in Cloudwatch; if left undefined, a default name is created | string |
null |
no |
cloudtrail_name | (Optional) custom name for the Cloudtrail resource; if left undefined, a default name is created | string |
null |
no |
cloudwatch_log_group_retention_in_days | The number of days to retain Cloudwatch logs | number |
30 |
no |
config_bucket_name | (Optional) custom name for the configuration S3 bucket; if left undefined, a default name is created | string |
null |
no |
create_autoscale_role | Create AWS Autoscale IAM Role (needed for any autoscaling aws resources) | bool |
true |
no |
create_backup_kms_key | create KMS key for AWS Backups | bool |
true |
no |
create_cloudtrail | Whether or not to create cloudtrail resources | bool |
false |
no |
create_cloudwatch_kms_key | create KMS key for AWS Cloudwatch | bool |
true |
no |
create_config_kms_key | create KMS key for AWS Cloudwatch | bool |
true |
no |
create_default_kms_key | create default kms key | bool |
true |
no |
create_ebs_kms_key | create KMS key for ebs | bool |
true |
no |
create_ecr_kms_key | create KMS key for ECR | bool |
true |
no |
create_lambda_kms_key | create KMS key for lambda | bool |
true |
no |
create_nfw_kms_key | create KMS key for NFW | bool |
true |
no |
create_packer_iam | Whether or not to create Packer IAM resources | bool |
false |
no |
create_rds_kms_key | create KMS key for rds | bool |
true |
no |
create_s3_accesslogs_bucket | Create S3 Access Logs Bucket | bool |
true |
no |
create_s3_backups_bucket | Create S3 Backups Bucket | bool |
true |
no |
create_s3_config_bucket | Create S3 AWS Config Bucket for conformance pack storage | bool |
true |
no |
create_s3_elb_accesslogs_bucket | Create S3 ELB Access Logs Bucket | bool |
true |
no |
create_s3_fedrampdoc_bucket | Create S3 FedRAMP Documents Bucket | bool |
true |
no |
create_s3_installs_bucket | Create S3 Installs Bucket | bool |
true |
no |
create_s3_kms_key | create KMS key for S3 | bool |
true |
no |
create_security_core | Whether or not to create Security Core resources | bool |
false |
no |
create_sm_kms_key | create KMS key for secrets manager | bool |
true |
no |
create_sns_kms_key | create KMS key for SNS | bool |
true |
no |
create_sqs_kms_key | create KMS key for SQS | bool |
true |
no |
default_aws_region | The default AWS region to create resources in | string |
n/a | yes |
elb_accesslogs_bucket_name | (Optional) custom name for the ELB access logs S3 bucket; if left undefined, a default name is created | string |
null |
no |
fedrampdoc_bucket_name | (Optional) custom name for the FedRAMP docs S3 bucket; if left undefined, a default name is created | string |
null |
no |
installs_bucket_name | (Optional) custom name for the installs S3 bucket; if left undefined, a default name is created | string |
null |
no |
is_organization | Whether or not to enable certain settings for AWS Organization | bool |
true |
no |
kms_multi_region | Indicates whether the KMS key is a multi-Region (true) or regional (false) key. | bool |
false |
no |
organization_id | AWS Organization ID | string |
null |
no |
packer_additional_iam_principal_arns | List of IAM Principal ARNs allowed to assume the Packer IAM Role | list(string) |
[] |
no |
packer_ebs_kmsgrant_name | (Optional) custom name for the KMS grant allowing Packer to access the EBS KMS key; if left undefined, a default name is created | string |
null |
no |
packer_iam_instanceprofile_name | (Optional) custom name for the Packer IAM instance profile; if left undefined, a default name is created | string |
null |
no |
packer_iam_policy_name | (Optional) custom name for the Packer IAM policy; if left undefined, a default name is created | string |
null |
no |
packer_iam_role_name | (Optional) custom name for the Packer IAM role; if left undefined, a default name is created | string |
null |
no |
packer_s3_kmsgrant_name | (Optional) custom name for the KMS grant allowing Packer to access the S3 bucket KMS key; if left undefined, a default name is created | string |
null |
no |
resource_prefix | The prefix for resources | string |
n/a | yes |
s3_backup_policy | S3 backup policy to use for S3 buckets in conjunction with AWS Backups, should match an existing policy | string |
"" |
no |
s3_backup_settings | Map of S3 bucket types to their backup settings | map(object({ |
{ |
no |
s3_tags | Tags to be applied to S3 buckets | map(any) |
{} |
no |
ssh_key_name | The name of the SSH key pair to use for EC2 instances. | string |
"fedramp-mgmt-gov-key" |
no |
ssh_key_secret_name | The name of the secret in Secrets Manager that stores the private SSH key. | string |
"/management/fedramp-mgmt-gov/ec2-key-pair" |
no |
Name | Description |
---|---|
additional_kms_key_arns | n/a |
additional_kms_key_ids | n/a |
backup_kms_key_arn | n/a |
backup_kms_key_id | n/a |
cloudwatch_kms_key_arn | n/a |
cloudwatch_kms_key_id | n/a |
config_kms_key_arn | n/a |
config_kms_key_id | n/a |
ebs_kms_key_arn | n/a |
ebs_kms_key_id | n/a |
ecr_kms_key_arn | n/a |
ecr_kms_key_id | n/a |
lambda_kms_key_arn | n/a |
lambda_kms_key_id | n/a |
nfw_kms_key_arn | n/a |
nfw_kms_key_id | n/a |
packer_iam_role_arn | n/a |
packer_iam_role_name | n/a |
rds_kms_key_arn | n/a |
rds_kms_key_id | n/a |
s3_access_logs_arn | n/a |
s3_access_logs_id | n/a |
s3_backups_arn | n/a |
s3_backups_id | n/a |
s3_cloudtrail_arn | n/a |
s3_cloudtrail_id | n/a |
s3_config_arn | n/a |
s3_config_id | n/a |
s3_elb_access_logs_arn | n/a |
s3_elb_access_logs_id | n/a |
s3_fedrampdoc_arn | n/a |
s3_fedrampdoc_id | n/a |
s3_installs_arn | n/a |
s3_installs_id | n/a |
s3_kms_key_arn | n/a |
s3_kms_key_id | n/a |
s3_tstate_bucket_name | n/a |
sm_kms_key_arn | n/a |
sm_kms_key_id | n/a |
sns_kms_key_arn | n/a |
sns_kms_key_id | n/a |
sqs_kms_key_arn | n/a |
sqs_kms_key_id | n/a |
If you're interested in contributing to our projects, please review the Contributing Guidelines. And send an email to our team to receive a copy of our CLA and start the onboarding process.
Copyright © 2023 Coalfire Systems Inc.
.
|-- CHANGELOG.md
|-- CONTRIBUTING.md
|-- License.md
|-- README.md
|-- cloudtrail.tf
|-- coalfire_logo.png
|-- data.tf
|-- ec2-key-pair.tf
|-- iam.tf
|-- kms-iam.tf
|-- kms.tf
|-- locals.tf
|-- outputs.tf
|-- packer_iam.tf
|-- providers.tf
|-- release-please-config.json
|-- s3-accesslog.tf
|-- s3-aws-config.tf
|-- s3-backups.tf
|-- s3-cloudtrail.tf
|-- s3-elb-accesslog.tf
|-- s3-fedrampdoc.tf
|-- s3-installs.tf
|-- security-core.tf
|-- update-readme-tree.sh
|-- variables.tf