Skip to content

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

PROVISIO-BASELINING

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()
  }
}