AWS onboarding with Terraform

Configure an AWS management account for the CloudBolt Platform with Terraform instead of CloudFormation, and connect it

The CloudBolt Terraform module creates, in the management (payer) account, what the ManagementAccountOnly deployment of the CloudFormation template creates: an S3 bucket for the cost report exports, the CloudBolt OIDC identity provider, and the CloudBoltFocusCrossAccountRole and CloudBoltActionsCrossAccountRole IAM roles. CloudBolt then creates the FOCUS 1.0, FOCUS 1.2 Hourly, FOCUS 1.2 Daily, and Cost Optimization Recommendations data exports itself once the connection is established.

Prerequisites

Complete these in the management/payer account before applying. They match the CloudFormation path described in Configure AWS accounts.

  • Cost Explorer is enabled. Go to Billing and Cost Management > Cost Explorer and open it once to enable it.

  • AWS Compute Optimizer is opted in for the account and all member accounts. Cost Optimization Hub sources its rightsizing recommendations from Compute Optimizer, so enable it first. Go to Compute Optimizer > Get started, or run:

    aws compute-optimizer update-enrollment-status --status Active --include-member-accounts
    

    CloudBolt doesn’t verify this enrollment. A connection succeeds without it, but your rightsizing recommendations are incomplete.

  • Cost Optimization Hub is opted in for the organization, including member accounts. Go to Billing and Cost Management > Cost Optimization Hub, choose Enable Cost Optimization Hub for this account and all member accounts, then select Enable. Alternatively, run:

    aws cost-optimization-hub update-enrollment-status --status Active --include-member-accounts --region us-east-1
    
  • The AWSServiceRoleForBCMDataExports service-linked role exists. Go to Billing and Cost Management > Data Exports > Create to provision it automatically, or run:

    aws iam create-service-linked-role --aws-service-name bcm-data-exports.amazonaws.com
    
  • Terraform 1.5 or later, the AWS provider 5.81.0 or later, and credentials that can manage IAM, S3, and STS in the management account. Configure the provider for us-east-1: AWS Data Exports operate only there.

  • The account doesn’t already carry the CloudBolt CloudFormation stack. Role names are fixed, so applying the module next to the stack fails with EntityAlreadyExists.

  • A CloudBolt Platform user with the Operations or Admin role, in an organization where Terraform onboarding is enabled. Refer to Manage roles.

Get the module

  1. Log in to the CloudBolt Platform.
  2. Go to Settings > Connections.
  3. In the AWS section, select Add Connection, review the ACTION REQUIRED dialog, then select Got it.
  4. Select Connect Terraform Deployment, then select Download Terraform module. Your browser saves cloudbolt-aws-terraform.zip.
  5. Unzip it. The archive contains the module at the top level, a ready-to-apply root under examples/management-only/, a README, and the generated IAM policy documents under policies/.

Leave the CloudBolt tab open; you return to it after the apply.

Apply the module

Either apply the example root as-is, or call the module from a Terraform root you already maintain. Either way, store the Terraform state in a remote backend; later updates and terraform destroy depend on it. All variables are listed under Variables.

  1. Change to cloudbolt-aws-terraform/examples/management-only/.

  2. Copy terraform.tfvars.example to terraform.tfvars and set the following values.

    Variable Value
    focus_bucket_name Name of the S3 bucket for the cost report exports. With create_bucket = true (default) Terraform creates it; with create_bucket = false it must already exist.
    tenant_hosted_region US (default) or EU, matching where your CloudBolt tenant is hosted. Selects the CloudBolt identity provider the roles trust.
    resource_name_prefix Prefix on the managed-policy names and on the export names CloudBolt creates. Default CloudBolt.
    deployment_name Suffix on those names. Takes the place of the CloudFormation stack name. Default CloudBoltOnboarding.
  3. Run the following commands:

    terraform init
    terraform plan
    terraform apply
    terraform output -json
    

Option B: call the module from your own Terraform root

Place the unzipped module directory next to your existing configuration and add a module block. The module declares no provider, so it uses yours; keep that provider in us-east-1.

module "cloudbolt_onboarding" {
  source               = "./cloudbolt-aws-terraform"
  focus_bucket_name    = "cloudbolt-cost-reports-123456789012"
  tenant_hosted_region = "US"
}

output "cloudbolt_onboarding" {
  value = module.cloudbolt_onboarding
}

Connect in CloudBolt

  1. Return to the AWS connection form (Settings > Connections > Add Connection) and enter a Connection Name.
  2. Select Connect Terraform Deployment. The CloudFormation options are hidden, and a Terraform output box appears, with the terraform output -json command above it (select the copy icon to copy it).
  3. Run terraform output -json in the directory you applied and paste everything it prints into Terraform output. CloudBolt fills in the Account ID and shows the other values it read: FOCUS Bucket, Resource Prefix, and Deployment Name. Select Edit values to correct one, or Enter the values manually instead if you don’t have the output.
  4. Select Connect Terraform Deployment.

The Resource Prefix and Deployment Name must match the applied values exactly. CloudBolt names the cost report exports {Resource Prefix}-<export>-{Deployment Name}. To switch back to the CloudFormation options, select Use CloudFormation instead.

What happens next

As soon as the connection is created, CloudBolt finishes setup automatically:

  1. Assumes the CloudBoltFocusCrossAccountRole the module created.
  2. Verifies the account prerequisites.
  3. Creates any of the cost report exports that don’t already exist in the bucket.

The connection card shows progress, then displays Connected. If setup can’t be completed, the card displays a specific error and a Retry action. FOCUS data appears once AWS delivers the first export, which can take up to 24 hours.

Manage the connection

  • Test Connection: Runs health checks and refreshes the status.
  • Re-Sync: Re-verifies the cost report exports using the stored FOCUS Bucket, Resource Prefix, and Deployment Name, and creates any that are missing. Use after correcting a value, or if exports were deleted.
  • Manage: Edit the connection Name, FOCUS Bucket, Resource Prefix, and Deployment Name. Correct a typo, save, then select Re-Sync.

The connection card shows Configured via: Terraform. Visit Manage connections to view, test, edit, or disconnect connections.

Variables

Name Type Default Description
focus_bucket_name string required Bucket for the cost report exports. 3–63 lowercase letters, digits, or hyphens.
create_bucket bool true Create the bucket with versioning, public access block, and SSE-S3. false reuses an existing bucket named focus_bucket_name.
create_bucket_policy bool true Attach the policy that lets bcm-data-exports.amazonaws.com write the exports. Set false only if the bucket already has an equivalent policy.
tenant_hosted_region string "US" US or EU (auth.cloudbolt.io or auth.eu.cloudbolt.io).
resource_name_prefix string "CloudBolt" Prefix on managed-policy names and on the export names CloudBolt creates. 1–32 characters.
deployment_name string "CloudBoltOnboarding" Suffix on managed-policy names and export names. Stands in for the CloudFormation stack name. 1–64 characters.
manage_oidc_providers bool true Create the CloudBolt OIDC providers. false looks up existing providers by URL instead (AWS allows one provider per URL per account).
additional_trusted_account_arns list(string) [] Extra IAM root, role, or user ARNs allowed to assume both roles.
additional_oidc_trusts list(object) [] Extra OIDC providers to create (or look up) and trust: { url, client_id }. The URL must start with https:// and end with /; the built-in CloudBolt URLs are rejected.
tags map(string) {} Tags applied to every created resource.

The example root under examples/management-only/ adds one input, aws_region (default us-east-1), for its provider block.

Outputs

terraform output -json prints these; CloudBolt reads the first four from the pasted document and ignores the rest.

Name Description
account_id Management account ID. Fills Account ID.
focus_bucket_name Bucket receiving the exports. Fills FOCUS Bucket.
resource_name_prefix Prefix CloudBolt uses on export names. Fills Resource Prefix.
deployment_name Suffix CloudBolt uses on export names. Fills Deployment Name.
focus_role_arn CloudBoltFocusCrossAccountRole ARN.
actions_role_arn CloudBoltActionsCrossAccountRole ARN.
oidc_provider_arns Identity provider ARNs in use, keyed us, eu, and any extra URLs.

Created resources

Resource Purpose
S3 bucket (optional) Stores the cost report exports. Versioning, public access block, SSE-S3.
Bucket policy (optional) Lets AWS Data Exports (bcm-data-exports.amazonaws.com) write to the bucket, scoped to this account.
OIDC identity provider(s) Trust for the CloudBolt SaaS tenant (US, plus EU when selected).
CloudBoltFocusCrossAccountRole Billing data access and export management. Attaches the FOCUS policy and AWS ReadOnlyAccess.
CloudBoltActionsCrossAccountRole Inventory, Security Hub, and commitment reads in the management account. Attaches two action policies.

Managed-policy names follow {resource_name_prefix}-FocusCommonPolicy-{deployment_name}, {resource_name_prefix}-ActionCommonPolicy1-{deployment_name}, and ...ActionCommonPolicy2.... Role names are fixed. Role permissions are described in IAM roles; they are generated from the same policy documents as those in the CloudFormation template.

Update and remove

  • Update: Download the current zip from the connection form, replace the module files, and run terraform apply. Policy changes apply in place.
  • Remove: Disconnect the account in CloudBolt first so it stops creating exports, then run terraform destroy. With create_bucket = true the bucket is deleted only if it’s empty; move or delete the exports first.

Troubleshooting

Problem Solution
Connect Terraform Deployment isn’t on the AWS connection form Terraform onboarding isn’t enabled for your organization. Contact CloudBolt Support.
EntityAlreadyExists on a role or the OIDC provider during terraform apply The account already carries the CloudBolt CloudFormation stack, or the OIDC provider exists from an earlier deployment. Role names are fixed, so the stack and the module can’t coexist: delete the stack (keep the bucket and set create_bucket = false if it holds exports you want to retain) or import the existing roles into Terraform state. For the provider alone, set manage_oidc_providers = false.
No CloudBolt outputs found in the pasted text Paste the whole document that terraform output -json prints (or the plain terraform output listing). It must contain account_id, focus_bucket_name, resource_name_prefix, and deployment_name.
Setup is taking longer than expected. Check that the Terraform roles exist and trust CloudBolt, then retry Confirm terraform apply completed in the account you connected, and that tenant_hosted_region matches where your CloudBolt tenant is hosted (US or EU). Correct the value, re-apply, then select Retry on the connection card.
The AWSServiceRoleForBCMDataExports service-linked role is missing Create the service-linked role, then select Re-Sync on the connection card. See Prerequisites.
Cost Optimization Hub is not enabled for this account Opt in for the organization, including member accounts, then select Re-Sync on the connection card. See Prerequisites.
An export couldn’t be created because the table already has 2 of 2 exports AWS allows two data exports per table. The message names the exports holding the slots. Delete one you no longer need, or, if the message reports an incompatible format, update that export so that Format and Compression are both set to PARQUET. Then select Re-Sync.