AWS onboarding with Terraform
9 minute read
Terraform onboarding is off by default. CloudBolt recommends the CloudFormation StackSet deployment described in Configure AWS accounts, because it also covers member accounts. To use Terraform, contact CloudBolt Support to enable it for your organization; the Connect Terraform Deployment option then appears on the AWS connection form.
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.
The module doesn’t deploy to member accounts. Cost data for every account in the organization still flows through the FOCUS exports of the management account, but CloudBolt doesn’t collect resource inventory, Security Hub findings, or reserved-instance and savings-plan details for member accounts via this path, and member accounts appear as not configured. To cover member accounts, use the StackSet deployment types of the CloudFormation template, described in Advanced AWS account configuration.
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-accountsCloudBolt 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
AWSServiceRoleForBCMDataExportsservice-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
- Log in to the CloudBolt Platform.
- Go to Settings > Connections.
- In the AWS section, select Add Connection, review the ACTION REQUIRED dialog, then select Got it.
- Select Connect Terraform Deployment, then select Download Terraform module. Your browser saves
cloudbolt-aws-terraform.zip. - 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 underpolicies/.
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.
Option A: apply the example root (recommended)
-
Change to
cloudbolt-aws-terraform/examples/management-only/. -
Copy
terraform.tfvars.exampletoterraform.tfvarsand set the following values.Variable Value focus_bucket_nameName of the S3 bucket for the cost report exports. With create_bucket = true(default) Terraform creates it; withcreate_bucket = falseit must already exist.tenant_hosted_regionUS(default) orEU, matching where your CloudBolt tenant is hosted. Selects the CloudBolt identity provider the roles trust.resource_name_prefixPrefix on the managed-policy names and on the export names CloudBolt creates. Default CloudBolt.deployment_nameSuffix on those names. Takes the place of the CloudFormation stack name. Default CloudBoltOnboarding. -
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
- Return to the AWS connection form (Settings > Connections > Add Connection) and enter a Connection Name.
- Select Connect Terraform Deployment. The CloudFormation options are hidden, and a Terraform output box appears, with the
terraform output -jsoncommand above it (select the copy icon to copy it). - Run
terraform output -jsonin 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. - 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:
- Assumes the
CloudBoltFocusCrossAccountRolethe module created. - Verifies the account prerequisites.
- 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. Withcreate_bucket = truethe 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. |
Contact CloudBolt Support if you require assistance with your deployment.
Related topics
- Configure AWS accounts: The recommended CloudFormation path.
- Connect AWS: Connecting a CloudFormation deployment.
- Advanced AWS account configuration: StackSet deployment types that cover member accounts.
- IAM roles: Details on the roles the module creates.
- CloudFormation template parameters: The CloudFormation equivalents of the module variables.
- CloudFormation template outputs: The CloudFormation equivalents of the module outputs.