PageSourceSearch

https://www.infracost.io/docs/assets/js/43c0edbf.e72aba69.js

js infracost.io collected 2026-09-24 19:35:48 UTC 31,785 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkinfracost_docs=self.webpackChunkinfracost_docs||[]).push([[126],{63885(e,n,t){t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"integrations/aws_integration_terraform","title":"Terraform","description":"Set up the Infracost AWS integration using the terraform-aws-integration Terraform module.","source":"@site/docs/integrations/aws_integration_terraform.md","sourceDirName":"integrations","slug":"/integrations/aws_integration_terraform","permalink":"/docs/integrations/aws_integration_terraform","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"slug":"aws_integration_terraform","title":"Terraform","description":"Set up the Infracost AWS integration using the terraform-aws-integration Terraform module."},"sidebar":"someSidebar","previous":{"title":"AWS Integration","permalink":"/docs/integrations/aws_integration"},"next":{"title":"CloudFormation","permalink":"/docs/integrations/aws_integration_cloudformation"}}');var r=t(74848),s=t(28453);const a={slug:"aws_integration_terraform",title:"Terraform",description:"Set up the Infracost AWS integration using the terraform-aws-integration Terraform module."},i=void 0,c={},l=[{value:"Initial Configuration",id:"initial-configuration",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Step 1: Deploy Infracost cross-account link",id:"step-1-deploy-infracost-cross-account-link",level:3},{value:"Step 2: Enable cost and usage data exports to Infracost",id:"step-2-enable-cost-and-usage-data-exports-to-infracost",level:3},{value:"Enrollment prerequisites",id:"enrollment-prerequisites",level:4},{value:"Enable Cost Optimization Hub and Compute Optimizer",id:"enable-cost-optimization-hub-and-compute-optimizer",level:5},{value:"Enable trusted access for S3 Storage Lens",id:"enable-trusted-access-for-s3-storage-lens",level:5},{value:"Ensure the BCM Data Exports service-linked role exists",id:"ensure-the-bcm-data-exports-service-linked-role-exists",level:5},{value:"Configuration",id:"configuration",level:4},{value:"Optional: Encrypt export buckets with a KMS key",id:"optional-encrypt-export-buckets-with-a-kms-key",level:4},{value:"Optional: Provide custom data exports instead",id:"optional-provide-custom-data-exports-instead",level:4},{value:"Data ownership and lifecycle",id:"data-ownership-and-lifecycle",level:4},{value:"Step 3: Enable AWS Cost Anomaly Detection monitor",id:"step-3-enable-aws-cost-anomaly-detection-monitor",level:3},{value:"Configuration",id:"configuration-1",level:4},{value:"Optional: Manually configure the anomaly monitor instead",id:"optional-manually-configure-the-anomaly-monitor-instead",level:4},{value:"Step 4: Add the integration in the Infracost Cloud",id:"step-4-add-the-integration-in-the-infracost-cloud",level:3},{value:"(Optional) Improve console links for SSO users",id:"optional-improve-console-links-for-sso-users",level:3},{value:"Upgrading",id:"upgrading",level:2},{value:"Step 1: Update version references",id:"step-1-update-version-references",level:3},{value:"Step 2: Download updated module version",id:"step-2-download-updated-module-version",level:3},{value:"Step 3: Plan and Apply",id:"step-3-plan-and-apply",level:3},{value:"Removing",id:"removing",level:2},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:"Error: creating AWS BCM Data Exports Export: operation error BCM Data Exports: CreateExport, https response error StatusCode: 400, RequestID: 00000000-0000-0000-0000-000000000000, ValidationException: This account is unable to create an export against this Table.",id:"error-creating-aws-bcm-data-exports-export-operation-error-bcm-data-exports-createexport-https-response-error-statuscode-400-requestid-00000000-0000-0000-0000-000000000000-validationexception-this-account-is-unable-to-create-an-export-against-this-table",level:3}];function d(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components},{Details:t}=n;return t||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(n.p,{children:["Deploy the Infracost AWS integration using the ",(0,r.jsx)(n.a,{href:"https://github.com/infracost/terraform-aws-integration",children:"terraform-aws-integration"})," Terraform module. Prefer CloudFormation? See the ",(0,r.jsx)(n.a,{href:"/docs/integrations/aws_integration_cloudformation/",children:"CloudFormation guide"})," instead."]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["This integration requires access to your AW
1S organization's management account. Reach out to ",(0,r.jsx)(n.a,{href:"mailto:[email protected]",children:"[email protected]"})," before getting started if you have questions."]})}),"\n",(0,r.jsx)(n.h2,{id:"initial-configuration",children:"Initial Configuration"}),"\n",(0,r.jsx)(n.h3,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Access to the AWS console on your AWS organization's ",(0,r.jsx)(n.strong,{children:"management account"})]}),"\n",(0,r.jsx)(n.li,{children:"Permission to create IAM roles and policies in that account"}),"\n",(0,r.jsxs)(n.li,{children:["Your ",(0,r.jsx)(n.strong,{children:"Infracost External ID"})," \u2014 in ",(0,r.jsx)(n.a,{href:"https://dashboard.infracost.io",children:"Infracost Cloud"}),", go to ",(0,r.jsx)(n.strong,{children:"Org Settings"})," > ",(0,r.jsx)(n.strong,{children:"General"})," and copy the ",(0,r.jsx)(n.strong,{children:"External ID"}),". It is also shown on the AWS integration page. Used as the external ID for the cross-account role."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"step-1-deploy-infracost-cross-account-link",children:"Step 1: Deploy Infracost cross-account link"}),"\n",(0,r.jsxs)(n.p,{children:["The Infracost AWS Integration uses a ",(0,r.jsx)(n.a,{href:"https://registry.terraform.io/modules/infracost/integration/aws/latest",children:"Terraform module"})," (",(0,r.jsx)(n.a,{href:"https://search.opentofu.org/module/infracost/integration/aws/latest",children:"also available via OpenTofu"}),") to provision a read-only IAM role in your accounts. Infracost uses this role to access the data needed to power cost visibility features."]}),"\n",(0,r.jsxs)(n.p,{children:["Add the following to your Terraform configuration for your ",(0,r.jsx)(n.strong,{children:"management account"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'module "infracost_management_account" {\n  source  = "infracost/integration/aws"\n  version = "0.3.2"\n\n  infracost_external_id  = "YOUR_EXTERNAL_ID"\n  is_management_account  = true\n\n  providers = {\n    aws = aws.management_account\n  }\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Replace ",(0,r.jsx)(n.code,{children:"YOUR_EXTERNAL_ID"})," with the value from the prerequisites."]}),"\n",(0,r.jsxs)(n.p,{children:["Repeat this for each ",(0,r.jsx)(n.strong,{children:"member account"})," in your AWS organization, using ",(0,r.jsx)(n.code,{children:"is_management_account = false"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'module "infracost_member_account_1" {\n  source  = "infracost/integration/aws"\n  version = "0.3.2"\n\n  infracost_external_id  = "YOUR_EXTERNAL_ID"\n  is_management_account  = false\n\n  providers = {\n    aws = aws.member_account_1\n  }\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Include an ",(0,r.jsx)(n.code,{children:"outputs.tf"})," for each account so you can easily reference the ARNs needed in a later step. Replace ",(0,r.jsx)(n.code,{children:"MODULE_NAME"})," with the name you used above:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'output "account_id" {\n  description = "The AWS account ID where the module was provisioned."\n  value       = module.MODULE_NAME.account_id\n}\n\noutput "role_arn" {\n  description = "The ARN value of the Cross-Account Role with IAM read-only permissions. Provide this to Infracost."\n  value       = module.MODULE_NAME.role_arn\n}\n\noutput "billing_and_cost_management_export_arn" {\n  description = "The ARN of the BCM Data Exports export."\n  value       = module.MODULE_NAME.billing_and_cost_management_export_arn\n}\n\noutput "billing_and_cost_management_bucket_arn" {\n  description = "The ARN of the S3 bucket used for BCM Data Exports."\n  value       = module.MODULE_NAME.billing_and_cost_management_bucket_arn\n}\n\noutput "s3_storage_lens_configuration_arn" {\n  description = "The ARN of the S3 Storage Lens configuration."\n  value       = module.MODULE_NAME.s3_storage_lens_configuration_arn\n}\n\noutput "s3_storage_lens_bucket_arn" {\n  description = "The ARN of the S3 bucket used for S3 Storage Lens exports."\n  value       = module.MODULE_NAME.s3_storage_lens_bucket_arn\n}\n\noutput "cost_anomaly_detection_services_monitor_arn" {\n  description = "The ARN of the Cost Anomaly Detection SERVICES monitor."\n  value       = module.MODULE_NAME.cost_anomaly_detection_services_monitor_arn\n}\n'})}
1),"\n",(0,r.jsx)(n.p,{children:"Then run:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"terraform init\nterraform apply\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Once applied, Terraform will output a ",(0,r.jsx)(n.strong,{children:"Cross-Account Link role ARN"})," for the management account \u2014 you'll need it in Step 4."]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsx)(n.p,{children:"When new features are added, this module may need to be updated to include new permissions. Infracost will notify you when an update is required."})}),"\n",(0,r.jsx)(n.h3,{id:"step-2-enable-cost-and-usage-data-exports-to-infracost",children:"Step 2: Enable cost and usage data exports to Infracost"}),"\n",(0,r.jsxs)(n.p,{children:["Cost and usage data exports are ",(0,r.jsx)(n.strong,{children:"required"})," for Infracost to see individual billing line items and S3 usage metrics. This module can create the data exports for you, or you can ",(0,r.jsx)(n.a,{href:"#optional-provide-custom-data-exports-instead",children:"bring your own existing export"})," instead."]}),"\n",(0,r.jsx)(n.h4,{id:"enrollment-prerequisites",children:"Enrollment prerequisites"}),"\n",(0,r.jsx)(n.h5,{id:"enable-cost-optimization-hub-and-compute-optimizer",children:"Enable Cost Optimization Hub and Compute Optimizer"}),"\n",(0,r.jsxs)(n.p,{children:["The Cost Optimization Hub recommendations export requires your AWS Organization's management account to be opted in to both ",(0,r.jsx)(n.strong,{children:"AWS Compute Optimizer"})," and ",(0,r.jsx)(n.strong,{children:"AWS Cost Optimization Hub"}),", org-wide."]}),"\n",(0,r.jsx)(n.p,{children:"These enrollments are not managed by the Terraform module \u2014 they are global, account-level toggles that must be performed manually, one-time, against the management account before applying:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"aws compute-optimizer update-enrollment-status \\\n  --status Active \\\n  --include-member-accounts \\\n  --region us-east-1\n\naws cost-optimization-hub update-enrollment-status \\\n  --status Active \\\n  --include-member-accounts \\\n  --region us-east-1\n"})}),"\n",(0,r.jsx)(n.p,{children:"AWS documents that enrollment can take up to 24 hours to take effect, though it is often faster."}),"\n",(0,r.jsx)(n.h5,{id:"enable-trusted-access-for-s3-storage-lens",children:"Enable trusted access for S3 Storage Lens"}),"\n",(0,r.jsxs)(n.p,{children:["S3 Storage Lens must have ",(0,r.jsx)(n.a,{href:"https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage_lens_with_organizations_enabling_trusted_access.html",children:"trusted access"})," configured for cross-account visibility."]}),"\n",(0,r.jsx)(n.p,{children:"This configuration is not managed by the Terraform module \u2014 it is a global, account-level toggle that must be performed manually, one-time, against the management account before applying:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"aws organizations enable-aws-service-access --service-principal storage-lens.s3.amazonaws.com\n"})}),"\n",(0,r.jsx)(n.h5,{id:"ensure-the-bcm-data-exports-service-linked-role-exists",children:"Ensure the BCM Data Exports service-linked role exists"}),"\n",(0,r.jsxs)(n.p,{children:["Creating the cost and usage data exports requires the ",(0,r.jsx)(n.code,{children:"AWSServiceRoleForBCMDataExports"})," ",(0,r.jsx)(n.a,{href:"https://docs.aws.amazon.com/cur/latest/userguide/data-exports-slr.html",children:"service-linked role"})," in the management account. AWS usually creates it automatically the first time a data export is created, but if it does not yet exist ",(0,r.jsx)(n.code,{children:"terraform apply"})," will fail to create the exports."]}),"\n",(0,r.jsx)(n.p,{children:"If the role is missing, create it once, manually, before applying:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"aws iam create-service-linked-role --aws-service-name bcm-data-exports.amazonaws.com\n"})}),"\n",(0,r.jsxs)(n.p,{children:["This is a no-op if the role already exists (it returns an ",(0,r.jsx)(n.code,{children:"InvalidInput"})," error stating the role has already been created, which is safe to ignore)."]}),"\n",(0,r.jsx)(n.h4,{id:"configuration",children:"Configuration"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'module "infracost_management_account" {\n  source  = "infracost/integration/aws"\n  version = "0.3.2"\n\n  infracost_external_id = "YOUR_EXTERNAL_ID"\n  is_management_account = true\n  enable_data_exports   = true # <-- Set this variable to true\n\n  providers = {\n    aws = aws.management_account\n  }\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:"This provisions the configuration and storage for the following exports:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://docs.aws.amazon.com/cur/latest/userguide/table-dictionary-focus-1-2-aws.html",children:"FOCUS 1.2 billing data"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://docs.aws.amazon.com/cur/latest/userguide/table-dictionary-cor.html",children:"Cost Optimization Hub recommendations"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage_lens_view_metrics_export.html",children:"S3 StorageLens data"}),"."]}),"\n"]}),"\n",(0,r.jsxs)(n.admonition,{type:"note",children:[(0,r.jsx)(n.p,{children:"The data exports are read periodically by Infracost, which may incur minor AWS query costs (~$0.0004 per 1,000 S3 requests). S3 storage costs also apply."}),(0,r.jsxs)(n.p,{children:["After completing the export configuration, AWS can take upwards of ",(0,r.jsx)(n.strong,{children:"24 hours"})," to populate the buckets with the first data exports."]})]}),"\n",(0,r.jsx)(n.h4,{id:"optional-encrypt-export-buckets-with-a-kms-key",children:"Optional: Encrypt export buckets with a KMS key"}),"\n",(0,r.jsxs)(n.p,{children:["By default, export buckets use SSE-S3 (AES-256) encryption. To use a customer-managed KMS key instead, pass its ARN via ",(0,r.jsx)(n.code,{children:"kms_key_arn"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'module "infracost_management_account" {\n  source  = "infracost/integration/aws"\n  version = "0.3.2"\n\n  infracost_external_id = "YOUR_ORG_ID"\n  is_management_account = true\n  enable_data_exports   = true\n  kms_key_arn           = "arn:aws:kms:us-east-1:111111111111:key/mrk-abc123"\n\n  providers = {\n    aws = aws.management_account\n  }\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["When ",(0,r.jsx)(n.code,{children:"kms_key_arn"})," is set, the module automatically grants the Infracost cross-account role ",(0,r.jsx)(n.code,{children:"kms:Decrypt"})," and ",(0,r.jsx)(n.code,{children:"kms:DescribeKey"})," on that key. You must also ensure the KMS key policy itself grants permissions to two sets of principals:"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"AWS service principals"})," \u2014 need ",(0,r.jsx)(n.code,{children:"kms:GenerateDataKey"})," and ",(0,r.jsx)(n.code,{children:"kms:Decrypt"})," to write and read back the encrypted export objects."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Infracost cross-account role"})," \u2014 needs ",(0,r.jsx)(n.code,{children:"kms:Decrypt"})," and ",(0,r.jsx)(n.code,{children:"kms:DescribeKey"})," to read the encrypted objects."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"The following key policy statements cover both:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n  "Statement": [\n    {\n      "Sid": "AllowExportServicePrincipals",\n      "Effect": "Allow",\n      "Principal": {\n        "Service": [\n          "bcm-data-exports.amazonaws.com",\n          "billingreports.amazonaws.com",\n          "storage-lens.s3.amazonaws.com"\n        ]\n      },\n      "Action": [\n        "kms:GenerateDataKey",\n        "kms:Decrypt"\n      ],\n      "Resource": "*",\n      "Condition": {\n        "StringEquals": {\n          "aws:SourceAccount": "111111111111"\n        }\n      }\n    },\n    {\n      "Sid": "AllowInfracostRoleDecrypt",\n      "Effect": "Allow",\n      "Principal": {\n        "AWS": "arn:aws:iam::111111111111:role/infracost-readonly"\n      },\n      "Action": [\n        "kms:Decrypt",\n        "kms:DescribeKey"\n      ],\n      "Resource": "*"\n    }\n  ]\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Replace ",(0,r.jsx)(n.code,{children:"111111111111"})," with your management account ID. The ",(0,r.jsx)(n.code,{children:"infracost-readonly"})," role ARN is available as a Terraform output from the module (",(0,r.jsx)(n.code,{children:"role_arn"}),")."]}
1),"\n",(0,r.jsx)(n.h4,{id:"optional-provide-custom-data-exports-instead",children:"Optional: Provide custom data exports instead"}),"\n",(0,r.jsxs)(n.p,{children:["Use this option if you prefer to manage your own data exports or want to provide additional custom data to Infracost. You can enable Infracost access for specific S3 bucket ARNs. When doing so, please contact ",(0,r.jsx)(n.a,{href:"mailto:[email protected]",children:"[email protected]"})," to ensure your use case and configuration are supported."]}),"\n",(0,r.jsxs)(n.p,{children:["If you are creating the FOCUS billing data export manually (for example, via the AWS Billing and Cost Management console under ",(0,r.jsx)(n.strong,{children:"Data Exports"}),"), configure it with the following settings so Infracost can ingest it:"]}),"\n",(0,r.jsxs)(t,{children:[(0,r.jsx)("summary",{children:"Manual FOCUS settings"}),(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Setting"}),(0,r.jsx)(n.th,{children:"Value"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Export type"}),(0,r.jsx)(n.td,{children:"FOCUS 1.2"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Columns"}),(0,r.jsx)(n.td,{children:"Include all columns"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Compression type and file format"}),(0,r.jsx)(n.td,{children:"Parquet - Parquet"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Time granularity"}),(0,r.jsx)(n.td,{children:"Daily"})]})]})]})]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'module "infracost_management_account" {\n  source  = "infracost/integration/aws"\n  version = "0.3.2"\n\n  infracost_external_id      = "YOUR_EXTERNAL_ID"\n  is_management_account      = true\n\n  providers = {\n    aws = aws.management_account\n  }\n\n  s3_bucket_arns = [\n    "arn:aws:s3:::my-custom-export" # <-- Add any custom S3 ARNs\n  ]\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:"If using this option, please provide the following details to Infracost:"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Field"}),(0,r.jsx)(n.th,{children:"Example"})]})}),(0,r.jsx)(n.tbody,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"AWS S3 bucket ARN"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"arn:aws:s3:::my-custom-export"})})]})})]}),"\n",(0,r.jsx)(n.h4,{id:"data-ownership-and-lifecycle",children:"Data ownership and lifecycle"}),"\n",(0,r.jsx)(n.p,{children:"Your AWS account retains ownership of the data. Infracost is granted solely read-only access to the export buckets."}),"\n",(0,r.jsx)(n.p,{children:"Each data exports bucket is configured with a 365-day object lifecycle policy. Intelligent tiering is applied to reduce storage costs."}),"\n",(0,r.jsx)(n.h3,{id:"step-3-enable-aws-cost-anomaly-detection-monitor",children:"Step 3: Enable AWS Cost Anomaly Detection monitor"}),"\n",(0,r.jsxs)(n.p,{children:["To surface AWS-detected cost anomalies alongside your cost data, the module can provision an AWS-managed ",(0,r.jsx)(n.a,{href:"https://docs.aws.amazon.com/cost-management/latest/userguide/getting-started-ad.html",children:"Cost Anomaly Detection"})," monitor. Set ",(0,r.jsx)(n.code,{children:"enable_anomaly_monitors = true"})," on the management account."]}),"\n",(0,r.jsx)(n.h4,{id:"configuration-1",children:"Configuration"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'module "infracost_management_account" {\n  source  = "infracost/integration/aws"\n  version = "0.3.2"\n\n  infracost_external_id   = "YOUR_EXTERNAL_ID"\n  is_management_account   = true\n  enable_anomaly_monitors = true # <-- Set this variable to true\n\n  providers = {\n    aws = aws.management_account\n  }\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["This provisions a single AWS-managed monitor named ",(0,r.jsx)(n.code,{children:"InfracostServicesMonitor"})," that evaluates every AWS service for anomalous spend. No alert subscription is created; Infracost reads the detected anomalies via the cross-account role."]}),"\n",(0,r.jsx)(n.h4,{id:"optional-manually-configure-the-anomaly-monitor-instead",children:"Optional: Manually configure the anomaly monitor instead"}),"\n",(0,r.jsxs)(n.p,{children:["Use this option if you prefer to manage your own cost anomaly monitors instead of relying on the Infracost provisioned one. Refer to AWS's ",(0,r.jsx)(n.a,{href:"https://docs.aws.amazon.com/cost-management/latest/userguide/getting-started-ad.html",children:"Getting Started guide"})," for the full procedure:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Navigate to ",(0,r.jsx)(n.code,{children:"Billing and Cost Management > Cost Anomaly Detection"})]}),"\n",(0,r.jsxs)(n.li,{children:["Select ",(0,r.jsx)(n.code,{children:"Cost monitors > Create monitor"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["Name your monitor and select ",(0,r.jsx)(n.code,{children:"Managed by AWS"})," with the ",(0,r.jsx)(n.code,{children:"AWS Services"})," monitor dimension."]}),"\n",(0,r.jsx)(n.li,{children:"Set or create a new alert subscription for the monitor (this is unused by Infracost, yet required for the creation process in the AWS console)."}),"\n"]}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsxs)(n.p,{children:["Note: If you are managing a custom cross-account role, ensure it has the ",(0,r.jsx)(n.code,{children:"ce:GetAnomalyM
1onitors"})," and ",(0,r.jsx)(n.code,{children:"ce:GetAnomalies"})," permissions set in its IAM policy."]}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"caution",children:(0,r.jsxs)(n.p,{children:["AWS allows only ",(0,r.jsx)(n.strong,{children:"one"})," managed ",(0,r.jsx)(n.code,{children:"SERVICES"})," (",(0,r.jsx)(n.code,{children:"DIMENSIONAL"})," / ",(0,r.jsx)(n.code,{children:"SERVICE"}),") anomaly monitor per payer account. If your management account already has one \u2014 created manually in the AWS console, by another tool, or in a previous setup \u2014 ",(0,r.jsx)(n.code,{children:"terraform apply"})," will fail when the module attempts to create a duplicate, returning a ",(0,r.jsx)(n.code,{children:"ValidationException"})," from the Cost Explorer API."]})}),"\n",(0,r.jsx)(n.h3,{id:"step-4-add-the-integration-in-the-infracost-cloud",children:"Step 4: Add the integration in the Infracost Cloud"}),"\n",(0,r.jsx)(n.p,{children:"After deploying the module, add the integration to Infracost from the dashboard:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Go to ",(0,r.jsx)(n.strong,{children:"Org Settings > Integrations > Add integrations"}),", then click ",(0,r.jsx)(n.strong,{children:"Add integration"})," for ",(0,r.jsx)(n.strong,{children:"Amazon Web Services"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["Enter an ",(0,r.jsx)(n.strong,{children:"Alias"})," to identify the integration, and the ",(0,r.jsx)(n.strong,{children:"Role ARN"})," of the management account's cross-account-link role output by the module (for example, ",(0,r.jsx)(n.code,{children:"arn:aws:iam::111111111111:role/infracost-readonly"}),")."]}),"\n",(0,r.jsxs)(n.li,{children:["Click ",(0,r.jsx)(n.strong,{children:"Test connection"})," to verify Infracost can assume the role."]}),"\n",(0,r.jsx)(n.li,{children:"Once the test passes, save the integration."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"optional-improve-console-links-for-sso-users",children:"(Optional) Improve console links for SSO users"}),"\n",(0,r.jsxs)(n.p,{children:["If your team signs in through ",(0,r.jsx)(n.strong,{children:"IAM Identity Center"})," (AWS SSO), set your access portal URL so console links to resources on findings route through the portal and open in the correct account \u2014 without it, the links can fail for federated users who aren't already signed in."]}),"\n",(0,r.jsxs)(n.p,{children:["In the dashboard, go to ",(0,r.jsx)(n.strong,{children:"Org Settings > Agent settings"})," and set ",(0,r.jsx)(n.strong,{children:"AWS access portal"})," to your portal URL, for example ",(0,r.jsx)(n.code,{children:"https://your-subdomain.awsapps.com/start"}),". You can find this in the AWS console under ",(0,r.jsx)(n.strong,{children:"IAM Identity Center > Settings > AWS access portal URL"}),". Leave it blank to keep using direct console links."]}),"\n",(0,r.jsx)(n.h2,{id:"upgrading",children:"Upgrading"}),"\n",(0,r.jsx)(n.p,{children:"As Infracost adds support for additional capabilities there may be a need to upgrade the Terraform module."}),"\n",(0,r.jsx)(n.h3,{id:"step-1-update-version-references",children:"Step 1: Update version references"}),"\n",(0,r.jsxs)(n.p,{children:["To upgrade, change the ",(0,r.jsx)(n.code,{children:"version"})," of the module to the version you'd like to use and make any additional changes needed."]}),"\n",(0,r.jsx)(n.admonition,{type:"tip",children:(0,r.jsxs)(n.p,{children:["Don't forget to review the ",(0,r.jsx)(n.a,{href:"https://github.com/infracost/terraform-aws-integration/releases",children:"release notes"})," for updates and breaking changes."]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-diff",children:'module "infracost_management_account" {\n   source  = "infracost/integration/aws"\n-  version = "0.3.0"\n+  version = "0.4.0"\n\n+  super_cool_new_feature = true\n\n   ...\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"step-2-download-updated-module-version",children:"Step 2: Download updated module version"}),"\n",(0,r.jsxs)(n.p,{children:["Once you've updated the version, rerun ",(0,r.jsx)(n.code,{children:"terraform init"})," but add the ",(0,r.jsx)(n.code,{children:"-upgrade"})," flag to force it to check for and download the correct version of the module:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"terraform init -upgrade\n"})}),"\n",(0,r.jsx)(n.h3,{id:"step-3-plan-and-apply",children:"Step 3: Plan and Apply"}),"\n",(0,r.jsxs)(n.p,{children:["Now that you've updated the module version, and made any additional modifications, you can run a ",(0,r.jsx)(n.code,{children:"plan"})," to verify your work, and ",(0,r.jsx)(n.code,{children:"apply"})," the changes."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"terraform plan\nterraform apply\n"})}),"\n",(0,r.jsx)(n.h2,{id:"removing",children:"Removing"}),"\n",(0,r.jsxs)(n.p,{children:["To remove the Infracost cross-account link components simply run ",(0,r.jsx)(n.code,{children:"terraform destroy"})," against your project."]}),"\n",(0,r.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,r.jsx)(n.h3,{id:"error-creating-aws-bcm-data-exports-export-operation-error-bcm-data-exports-createexport-https-response-error-statuscode-400-requestid-00000000-0000-0000-0000-000000000000-validationexception-this-account-is-unable-to-create-an-export-against-this-table",children:"Error: creating AWS BCM Data Exports Export: operation error BCM Data Exports: CreateExport, https response error StatusCode: 400, RequestID: 00000000-0000-0000-0000-000000000000, ValidationException: This account is unable to create an export against this Table."}),"\n",(0,r.jsx)(n.p,{children:"This error typically happens for one of the following reasons:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Management account is not yet opted in to Compute Optimizer and Cost Optimization Hub.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Run the commands in ",(0,r.jsx)(n.a,{href:"#enrollment-prerequisites",children:"Enrollment prerequisites"})," above, then re-run ",(0,r.jsx)(n.code,{children:"terraform apply"}),"."]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["Target is not the management account.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Make sure you are targetting the management/payer account."}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["IAM billing access is not enabled. If this setting is deactivated, IAM users and roles in the account can\u2019t access the Billing and Cost Management console pages, even if they have administrator access or the required IAM policies.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:'As the root user, head to the AWS Console and select "Account" from the drop-down in upper-right corner.'}),"\n",(0,r.jsx)(n.li,{children:'Scroll down to the "IAM user and role access to Billing information" section.'}),"\n",(0,r.jsx)(n.li,{children:'Select "Edit", and check the box in front of "Activate IAM Access".'}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["IAM user does not have the correct IAM permissions to create the resources.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Ensure the user has ",(0,r.jsx)(n.code,{children:"cur:PutReportDefinition"})," and ",(0,r.jsx)(n.code,{children:"bcm-data-exports:CreateExport"})]}),"\n"]}),"\n"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453(e,n,t){t.d(n,{R:()=>a,x:()=>i});var o=t(96540);const r={},s=o.createContext(r);function a(e){const n=o.useContext(s);return o.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.