ACAI PROVISIO Baselining
With the solution deployed, you can now start baselining your AWS accounts.
Create Baseline Specification
The baseline specification can be split up into three stages:
- Specification of Account Clusters
- Rendering the Terraform Code
- Specifying the Deployment Packages
Specify Account Clusters
The account clusters can be specified in a account_scopes
map.
The convention follows the ACAI Account Cache Query convention.
locals {
account_scopes = {
core = jsonencode(
{
"exclude" = "*",
"forceInclude" = {
"ouNameWithPath" : "/Platform/Core"
}
})
image_factory = jsonencode(
{
"exclude" = "*",
"forceInclude" = {
"accountId" = var.platform_settings.governance.org_mgmt.core_account_ids.image_factory
}
}
)
non_image_factory = jsonencode(
{
"exclude" = {
"accountId" = var.platform_settings.governance.org_mgmt.core_account_ids.image_factory
}
}
)
prod_accounts = jsonencode(
{
"exclude" = "*",
"forceInclude" = {
"ouNameWithPath" : [
{
"contains" = "/Prod/"
}
]
}
}
)
non_prod_accounts = jsonencode(
{
"exclude" = "*",
"forceInclude" = {
"ouNameWithPath" : [
{
"contains" = "/Non-Prod/"
}
]
}
}
)
dmz_accounts = jsonencode(
{
"exclude" = "*",
"forceInclude" = {
"ouNameWithPath" : [
{
"contains" = "/DMZ/"
}
]
}
}
)
non_dmz_accounts = jsonencode(
{
"exclude" = "*",
"forceInclude" = {
"ouNameWithPath" : [
{
"contains" = "/Non-DMZ/"
}
]
}
}
)
}
}
Render Packages
At this stage we will render the Terraform code for the packages.
Package specifications can be instantiated with different settings. As the provisio_settings.provisio_package_name
must be unique, it must be overwritten for additional versions of a package.
A sample for a rendering package can be found at the member sub-module of the ACF AWS Config Module.
module "aws_config" {
source = "git::https://github.com/acai-consulting/terraform-aws-acf-configservice.git//member/acai-provisio?ref=1.0.1"
provisio_settings = {
provisio_regions = var.platform_settings.governance.org_mgmt
}
aws_config_settings = var.platform_settings.security.aws_config
}
module "acai_semper_member" {
source = "git::https://github.com/acai-consulting/terraform-aws-acai-semper//member/acai-provisio?ref=1.18.0"
provisio_settings = {
provisio_regions = var.platform_settings.governance.org_mgmt
import_resources = true
}
member_settings = var.platform_settings.security.semper.member
resource_tags = var.resource_tags
}
module "account_hardening_without_ebs_encryption" {
source = "git::https://github.com/acai-consulting/terraform-aws-acf-account-hardening?ref=1.0.0"
provisio_settings = {
provisio_package_name = "account-hardening-without-ebs"
provisio_regions = var.platform_settings.governance.org_mgmt
}
account_hardening_settings = {
ebs_encryption = false
}
}
module "account_hardening_with_ebs_encryption" {
source = "git::https://github.com/acai-consulting/terraform-aws-acf-account-hardening?ref=1.0.0"
provisio_settings = {
provisio_package_name = "account-hardening-with-ebs"
provisio_regions = var.platform_settings.governance.org_mgmt
}
account_hardening_settings = {}
}
module "image_factory_spoke_role" {
source = "./packages/image-factory-spoke-role"
provisio_settings = {
provisio_regions = var.platform_settings.governance.org_mgmt
import_resources = true
}
image_factory_settings = var.platform_settings.security.image_factory
resource_tags = var.resource_tags
}
From the modules compose this:
locals {
package_specification = [
module.aws_config,
module.acai_semper_member,
module.account_hardening_with_ebs_encryption,
module.account_hardening_without_ebs_encryption,
module.image_factory_spoke_role,
]
}
output "package_specification" {
value = local.package_specification
}
Specify Deployment Packages
The deployment packages bring together account clusters with the packages.
In case no account_scope
is specified, the specified packages will be deployed to all AWS accounts of the AWS Organization.
locals {
package_deployment = [
{
deployment_name = "account-baselining-default"
provisio_package_names = [
module.aws_config.provisio_package_name,
module.image_factory_spoke_role.provisio_package_name
]
},
{
deployment_name = "prod-account-baselining"
provisio_package_names = [
module.acai_semper_member.provisio_package_name
]
},
{
deployment_name = "account-hardening-with-ebs-encryption"
account_scope = local.account_scopes.non_image_factory
provisio_package_names = [
module.account_hardening_with_ebs_encryption.provisio_package_name
]
},
{
deployment_name = "account-hardening-without-ebs-encryption"
account_scope = local.account_scopes.image_factory
provisio_package_names = [
module.account_hardening_without_ebs_encryption.provisio_package_name
]
}
]
}
output "package_deployment" {
value = local.package_deployment
}
Deploy Baseline Specification
module "account_baseline_specification" {
source = "git::https://github.com/acai-consulting/demo-aws-org-account-baseline?ref=1.0.0"
platform_settings = local.platform_settings
resource_tags = local.resource_tags
}
module "provisio_core_baseling" {
source = "git::https://github.com/acai-consulting/terraform-aws-acai-provisio//baseline?ref=1.0.0"
provisio_baseline_specification = module.account_baseline_specification
provisio_regions = local.platform_settings.governance.org_mgmt
provisio_bucket_id = module.provisio_core.provisio_configuration_to_write.core_provisio.provisio_bucket_id
providers = {
aws = aws.core_baselining
}
}
In case you want to trigger the StepFunction with the terraform pipeline run, add this section to your terraform code:
resource "null_resource" "trigger_step_function" {
provisioner "local-exec" {
command = <<-EOT
aws sts assume-role --role-arn "arn:aws:iam::123456789012/platform_cicd-core_baselining-baselining-role" --role-session-name TerraformSession > assumed_role.json
export AWS_ACCESS_KEY_ID=$(jq -r .Credentials.AccessKeyId assumed_role.json)
export AWS_SECRET_ACCESS_KEY=$(jq -r .Credentials.SecretAccessKey assumed_role.json)
export AWS_SESSION_TOKEN=$(jq -r .Credentials.SessionToken assumed_role.json)
aws --region eu-central-1 stepfunctions start-execution --state-machine-arn ${module.provisio_core.provisio_configuration_to_write.core_provisio.stepfunction_arn} --input '{"accounts":["123456789012", "optional - for all member accounts just use an empty JSON"]}'
rm assumed_role.json
EOT
}
# Using a trigger to ensure it runs on each apply or on specific changes
triggers = {
always_run = timestamp()
}
}