Skip to main content

Account Baseline

The Account Baseline feature in NTC Account Factory allows you to establish and maintain consistent configurations, guardrails, and security controls across multiple AWS accounts through comprehensive infrastructure as code.

Overview

Account Baselines ensure that all AWS accounts in your organization follow a consistent set of standards and configurations. Unlike the event-driven Account Lifecycle Management, baselines provide ongoing governance through CI/CD pipelines that apply Terraform code to maintain the desired state of your accounts.

How It Works

  1. Terraform code defines the desired configuration for accounts
  2. S3 buckets store the Terraform code and state files
  3. CodePipeline orchestrates the deployment process
  4. CodeBuild executes Terraform to apply the configuration
  5. DynamoDB tables protect against accidental deletion

NTC Account Factory Account Baseline

Key Features

FeatureDescriptionBenefits
Scoped DeploymentApply different baselines to specific accounts based on OU paths, names, or tagsTarget configurations to the right environments
Multi-Region SupportDeploy resources across multiple AWS regionsMaintain consistency across global infrastructure
Modular DesignBuild baselines from reusable templates or custom codeReduce duplication and maintenance overhead
Cross-Account OrchestrationConfigure resources that require access to multiple accountsSimplify complex cross-account dependencies
Scheduled UpdatesAutomatically reapply baselines at scheduled intervalsEnforce compliance and correct drift
State ManagementMaintain Terraform state to detect and correct configuration driftEnsure resources stay properly configured

NTC Account Baseline Templates

The NTC Account Baseline Templates module provides a set of pre-built, reusable templates for common account configurations. These templates can be easily integrated into your Account Factory configuration to standardize governance across accounts.

Available Templates

The following templates are available in the NTC Account Baseline Templates module:

TemplateDescriptionWhen to Use
iam_roleCreates a standardized IAM role with configurable trust policy, principal access, and permission settingsWhen you need consistent IAM roles across accounts for cross-account access, service roles, or EC2 instance profiles
aws_configSets up AWS Config recorders and rulesFor continuous compliance monitoring
openid_connectConfigures OIDC integrationFor setting up an OpenID Connect (OIDC) identity provider in IAM with assumable role and permissions

Implementation

The NTC Account Baseline Templates can be implemented in your NTC Account Factory configuration through a few simple steps:

  1. Include the Templates Module

First, include the NTC Account Baseline Templates module in your Terraform configuration:

module "account_baseline_templates" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-account-baseline-templates?ref=X.X.X"

account_baseline_templates = [
{
file_name = "iam_monitoring_reader"
template_name = "iam_role"
iam_role_inputs = {
role_name = "CloudWatch-CrossAccountSharingRole"
# policy can be submitted directly as JSON or via data source aws_iam_policy_document
policy_json = data.aws_iam_policy_document.monitoring_reader.json
role_principal_type = "AWS"
# grant account (org management) permission to assume role in member account
role_principal_identifiers = [123456789102] # monitoring account id
}
},
{
file_name = "iam_instance_profile"
template_name = "iam_role"
iam_role_inputs = {
role_name = "ntc-ssm-instance-profile"
# use 'policy_arn' to reference an aws managed policy
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
role_principal_type = "Service"
# grant account (org management) permission to assume role in member account
role_principal_identifiers = ["ec2.amazonaws.com"]
# (optional) set to true to create an instance profile
role_is_instance_profile = true
}
},
{
file_name = "aws_config"
template_name = "aws_config"
aws_config_inputs = {
config_log_archive_bucket_arn = "CONFIG_LOG_ARCHIVE_BUCKET_ARN"
config_log_archive_kms_key_arn = "CONFIG_LOG_ARCHIVE_KMS_KEY_ARN"
# optional inputs
config_recorder_name = "ntc-config-recorder"
config_delivery_channel_name = "ntc-config-delivery"
config_iam_role_name = "ntc-config-role"
config_iam_path = "/"
config_delivery_frequency = "One_Hour"
# (optional) override account baseline main region with main region of security tooling
# this is necessary when security tooling uses a different main region
# omit to use the main region of the account baseline
config_security_main_region = ""
}
},
{
file_name = "oidc_spacelift"
template_name = "openid_connect"
openid_connect_inputs = {
provider = "example.app.spacelift.io"
audience = "example.app.spacelift.io"
role_name = "ntc-oidc-spacelift-role"
role_path = "/"
role_max_session_in_hours = 1
permission_boundary_arn = ""
permission_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
subject_list_encoded = <<EOT
flatten([
[
"space:REPLACE_ME_WITH_SPACELIFT_SPACE_ID:stack:$${var.current_account_name}:*"
],
[
for subject in try(var.current_account_customer_values.additional_oidc_subjects, []) : "space:REPLACE_ME_WITH_SPACELIFT_SPACE_ID:stack:$${subject}:*"
]
])
EOT
}
}
]
}
  1. Reference Templates in Account Factory Configuration

After defining the templates, reference them in your NTC Account Factory configuration:

module "ntc_account_factory" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-account-factory?ref=X.X.X"

account_factory_baseline_bucket_name = "ntc-account-factory-baseline"

# Other account factory configuration...

account_baseline_scopes = [
{
scope_name = "workloads"
terraform_binary = "opentofu"
terraform_version = "1.8.5"
aws_provider_version = "5.76.0"

provider_default_tags = {
ManagedBy = "ntc-account-factory",
BaselineScope = "workloads",
BaselineVersion = "1.3"
}

baseline_execution_role_name = "OrganizationAccountAccessRole"

# Reference pre-defined templates
baseline_terraform_files = [
module.account_baseline_templates.account_baseline_terraform_files["iam_monitoring_reader"],
module.account_baseline_templates.account_baseline_terraform_files["iam_instance_profile"],
module.account_baseline_templates.account_baseline_terraform_files["aws_config"],
]

baseline_regions = ["us-east-1", "eu-central-1"]
baseline_main_region = "eu-central-1"

# Target specific accounts
include_accounts_all = false
include_accounts_by_ou_paths = [
"/root/workloads/prod",
"/root/workloads/dev"
]
}
]
}
  1. Testing and Monitoring

Once your baseline configuration is deployed, you can monitor its status through:

  • AWS CodePipeline console to track deployment
  • CodeBuild logs for detailed execution information
  • Account-level resources to verify proper configuration

Custom Baseline Templates

Injected Variables

The NTC Account Factory automatically injects several predefined variables into your baseline Terraform templates, providing essential account and deployment context information. These variables are automatically injected by the NTC Account Factory CodePipeline and are available in all baseline templates without any additional configuration.

VariableTypeDescription
var.current_regionstringThe AWS region where the baseline is currently being deployed
var.main_regionstringThe primary region designated for the account baseline
var.is_current_region_main_regionboolBoolean flag indicating whether the current deployment region is the main region
var.current_account_idstringThe AWS account ID where the baseline is being applied
var.current_account_namestringThe name of the AWS account
var.current_account_emailstringThe email address associated with the AWS account
var.current_account_ou_pathstringThe organizational unit path where the account is located
var.current_account_tagsmapKey-value pairs of tags assigned to the account
var.current_account_alternate_contactslistList of alternate contact information for the account
var.current_account_customer_valuesanyCustom values provided during account creation or configuration
var.baseline_parametersanyConfiguration parameters specific to the baseline scope

While the pre-built templates cover many common scenarios, you may need to create custom baseline templates for unique requirements. The injected variables provide powerful capabilities for creating dynamic, account-aware configurations that adapt based on the deployment context.

Leveraging Injected Variables in Custom Templates

The injected variables enable you to create sophisticated baseline templates that automatically adapt to different accounts, regions, and organizational contexts:

# Example: Account-aware resource naming
resource "aws_s3_bucket" "logs" {
bucket = "${var.current_account_id}-${var.current_region}-audit-logs"

tags = merge(var.current_account_tags, {
Purpose = "Audit Logging"
Region = var.current_region
})
}

# Example: Region-specific deployments
resource "aws_iam_role" "cross_account_role" {
# Only create in main region since IAM is global
count = var.is_current_region_main_region ? 1 : 0

name = "${var.current_account_name}-CrossAccountRole"
# ... role configuration
}

# Example: Environment-based configurations
locals {
environment = can(regex("/prod", var.current_account_ou_path)) ? "production" : "non-production"

# Different settings based on environment
backup_retention_days = local.environment == "production" ? 30 : 7
monitoring_enabled = local.environment == "production" ? true : false

# Use customer values for additional customization
custom_budget_limit = try(var.current_account_customer_values.budget_limit, "100")
}

Simple Account Budget Template

For straightforward budget management, here's a simple template that uses injected variables for basic account-aware budgeting:

# files/simple_account_budget.tf

resource "aws_budgets_budget" "account_budget" {
# Only create in main region to avoid duplicates
count = var.is_current_region_main_region ? 1 : 0

name = "${var.current_account_name}-monthly-budget"
budget_type = "COST"
limit_amount = var.baseline_parameters["budget_limit"]
limit_unit = "USD"
time_unit = "MONTHLY"
time_period_start = "2024-01-01_00:00"

# 80% threshold notification
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = [var.current_account_email]
}

# 100% threshold notification
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = [var.current_account_email]
}

tags = merge(var.current_account_tags, {
ManagedBy = "ntc-account-factory"
Purpose = "cost-monitoring"
})
}

This simple template:

  • Uses var.current_account_name for unique budget naming
  • Gets budget limit from var.baseline_parameters["budget_limit"]
  • Sends notifications to var.current_account_email
  • Only deploys in the main region using var.is_current_region_main_region
  • Merges account tags using var.current_account_tags

You can configure different budget limits per scope in your Account Factory configuration:

account_baseline_scopes = [
{
scope_name = "production_accounts"

baseline_parameters = {
budget_limit = "1000"
}

baseline_terraform_files = [
{
file_name = "simple_account_budget.tf"
content = file("${path.module}/files/simple_account_budget.tf")
}
]

include_accounts_by_ou_paths = ["/root/workloads/prod"]
},
{
scope_name = "development_accounts"

baseline_parameters = {
budget_limit = "200"
}

baseline_terraform_files = [
{
file_name = "simple_account_budget.tf"
content = file("${path.module}/files/simple_account_budget.tf")
}
]

include_accounts_by_ou_paths = ["/root/workloads/dev"]
}
]

Account Budget Template with Dynamic Configuration

Here's an enhanced budget template that leverages injected variables for dynamic configuration based on account context:

  1. Create the Enhanced Terraform File

    # files/account_budget_dynamic.tf

    locals {
    # Determine environment from OU path
    environment = can(regex("/prod", var.current_account_ou_path)) ? "production" : (
    can(regex("/dev", var.current_account_ou_path)) ? "development" : "sandbox"
    )

    # Set budget limits based on environment and custom values
    default_budget_limits = {
    production = "1000"
    development = "200"
    sandbox = "50"
    }

    # Allow override via customer values, fallback to environment defaults
    budget_limit = try(
    var.current_account_customer_values.budget_limit,
    local.default_budget_limits[local.environment],
    "100"
    )

    # Environment-specific notification settings
    notification_emails = {
    production = ["finance-prod@company.com", "team-lead@company.com"]
    development = ["finance-dev@company.com"]
    sandbox = ["admin@company.com"]
    }

    # Use account email as fallback if environment-specific emails not defined
    budget_emails = try(
    var.current_account_customer_values.budget_notification_emails,
    local.notification_emails[local.environment],
    [var.current_account_email]
    )
    }

    resource "aws_budgets_budget" "account_budget" {
    # Only create in main region to avoid duplicates
    count = var.is_current_region_main_region ? 1 : 0

    name = "${var.current_account_name}-monthly-budget"
    budget_type = "COST"
    limit_amount = local.budget_limit
    limit_unit = "USD"
    time_unit = "MONTHLY"
    time_period_start = "2024-01-01_00:00"

    # 80% threshold notification
    notification {
    comparison_operator = "GREATER_THAN"
    threshold = 80
    threshold_type = "PERCENTAGE"
    notification_type = "ACTUAL"
    subscriber_email_addresses = local.budget_emails
    }

    # 100% threshold notification
    notification {
    comparison_operator = "GREATER_THAN"
    threshold = 100
    threshold_type = "PERCENTAGE"
    notification_type = "ACTUAL"
    subscriber_email_addresses = local.budget_emails
    }

    # Forecasted 100% threshold
    notification {
    comparison_operator = "GREATER_THAN"
    threshold = 100
    threshold_type = "PERCENTAGE"
    notification_type = "FORECASTED"
    subscriber_email_addresses = local.budget_emails
    }

    tags = merge(var.current_account_tags, {
    ManagedBy = "ntc-account-factory"
    Environment = local.environment
    BudgetLimit = local.budget_limit
    })
    }

    # Optional: Create CloudWatch alarm for budget exceeded
    resource "aws_cloudwatch_metric_alarm" "budget_alarm" {
    count = var.is_current_region_main_region ? 1 : 0

    alarm_name = "${var.current_account_name}-budget-exceeded"
    comparison_operator = "GreaterThanThreshold"
    evaluation_periods = "1"
    metric_name = "ActualSpend"
    namespace = "AWS/Billing"
    period = "86400"
    statistic = "Maximum"
    threshold = local.budget_limit
    alarm_description = "Budget exceeded for account ${var.current_account_name}"

    dimensions = {
    Currency = "USD"
    }

    tags = var.current_account_tags
    }
  2. Use in Account Factory Configuration

    account_baseline_scopes = [
    {
    scope_name = "all_workloads"

    baseline_terraform_files = [
    {
    file_name = "account_budget_dynamic.tf"
    content = file("${path.module}/files/account_budget_dynamic.tf")
    }
    ]

    # Apply to all workload accounts
    include_accounts_by_ou_paths = [
    "/root/workloads/prod",
    "/root/workloads/dev",
    "/root/workloads/sandbox"
    ]

    baseline_regions = ["us-east-1", "eu-central-1"]
    baseline_main_region = "us-east-1"
    }
    ]

Multi-Region Resource Template

This template demonstrates how to use injected variables for region-aware deployments:

# files/multi_region_resources.tf

# Global resources (created only in main region)
resource "aws_iam_role" "application_role" {
count = var.is_current_region_main_region ? 1 : 0

name = "${var.current_account_name}-ApplicationRole"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}
]
})

tags = merge(var.current_account_tags, {
CreatedIn = var.main_region
})
}

# Regional resources (created in each region)
resource "aws_s3_bucket" "regional_bucket" {
bucket = "${var.current_account_id}-${var.current_region}-regional-data"

tags = merge(var.current_account_tags, {
Region = var.current_region
IsMainRegion = var.is_current_region_main_region
})
}

# Cross-region reference (data source in non-main regions)
data "aws_iam_role" "application_role" {
count = var.is_current_region_main_region ? 0 : 1
name = "${var.current_account_name}-ApplicationRole"
}

locals {
# Get role ARN whether created locally or referenced from main region
application_role_arn = var.is_current_region_main_region ?
aws_iam_role.application_role[0].arn :
data.aws_iam_role.application_role[0].arn
}

# Use the role ARN in regional resources
resource "aws_instance_profile" "application_profile" {
name = "${var.current_account_name}-${var.current_region}-profile"
role = local.application_role_arn

tags = var.current_account_tags
}

These enhanced examples demonstrate how the injected variables enable you to create dynamic, intelligent baseline templates that automatically adapt to different deployment contexts while maintaining consistency across your AWS organization.

Cross-Account Orchestration

Account Baseline supports configuring resources that require access to multiple accounts. This is particularly useful when your baseline needs to manage networking resources (like Transit Gateway attachments) or DNS delegations that are centrally managed in dedicated accounts.

baseline_assume_role_providers = [
{
configuration_alias = "connectivity"
role_arn = "REPLACE_WITH_THE_ROLE_ARN_THAT_ALLOWS_BASELINE_TO_MANAGE_NETWORKING_RESOURCES" # local.ntc_parameters["connectivity"]["baseline_assume_role_arn"]
session_name = "ntc-account-factory"
}
]

This configuration creates additional AWS provider aliases that can be used in your baseline Terraform code. For example, you might use the connectivity provider to:

  • Attach VPCs to Transit Gateways: Automatically connect new account VPCs to your central networking infrastructure
  • Create DNS subdomain delegations: Set up Route53 hosted zones and delegate subdomains from a central DNS account
  • Configure cross-account security group rules: Allow traffic between accounts through centrally managed security groups

Setting Up Cross-Account Access

To use cross-account orchestration, you need to create a role in the target account (e.g., connectivity account) that can be assumed by the baseline pipeline:

  1. Create the cross-account role in the target account:
# In your connectivity account
resource "aws_iam_role" "ntc_baseline" {
name = "ntc-baseline-role"
assume_role_policy = data.aws_iam_policy_document.ntc_baseline_trust.json
}

data "aws_iam_policy_document" "ntc_baseline_trust" {
statement {
effect = "Allow"
principals {
type = "AWS"
identifiers = ["ACCOUNT_FACTORY_BASELINE_ROLE_ARN"] # local.ntc_parameters["mgmt-account-factory"]["baseline_role_arns"]
}
actions = ["sts:AssumeRole"]
}
}

# Grant specific permissions needed for baseline operations
resource "aws_iam_role_policy" "ntc_baseline" {
name = "ntc-baseline-permissions"
role = aws_iam_role.ntc_baseline.id
policy = data.aws_iam_policy_document.ntc_baseline_permissions.json
}

data "aws_iam_policy_document" "ntc_baseline_permissions" {
# permission required to manage transit gateway attachments
statement {
sid = "ManageTransitGatewayAttachments"
effect = "Allow"
actions = [
"ec2:CreateTags",
"ec2:DescribeTransitGatewayAttachments",
"ec2:AssociateTransitGatewayRouteTable",
"ec2:EnableTransitGatewayRouteTablePropagation",
"ec2:GetTransitGatewayAttachmentPropagations",
]
resources = [
module.ntc_core_network_frankfurt.transit_gateway_arn,
module.ntc_core_network_zurich.transit_gateway_arn
]
}
# permissions required to manage subdomain delegations
statement {
sid = "ManageRoute53SubdomainDelegations"
effect = "Allow"
actions = [
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets",
"route53:ListTagsForResource",
"route53:GetHostedZone",
]
resources = ["*"] # Use "*" to allow access to all Route53 hosted zones, or specify specific ARNs if needed like module.ntc_route53_dev.zone_arn
}
statement {
effect = "Allow"
actions = [
"route53:ListHostedZones",
"route53:GetChange",
]
resources = ["*"]
}

# add additional permissions as needed
}

  1. Use the provider in your baseline templates:
# Example: Attach new account VPC to Transit Gateway
resource "aws_ec2_transit_gateway_vpc_attachment" "workload_attachment" {
provider = aws.connectivity
subnet_ids = [aws_subnet.workload_subnet.id]
transit_gateway_id = var.transit_gateway_id
vpc_id = aws_vpc.workload_vpc.id

tags = {
Name = "${var.current_account_name}-attachment"
}
}

# Example: Create subdomain delegation
resource "aws_route53_record" "subdomain_delegation" {
provider = aws.connectivity
zone_id = var.parent_zone_id
name = "${var.current_account_name}.example.com"
type = "NS"
ttl = 300
records = aws_route53_zone.account_zone.name_servers
}

Account Scoping

You can precisely target which accounts receive specific baselines using several scoping mechanisms:

  1. Include by OU Path

    include_accounts_by_ou_paths = [
    "/root/workloads/prod",
    "/root/workloads/dev"
    ]
  2. Include by Account Name

    include_accounts_by_names = ["exclusive-account"]
  3. Include by Tags

    include_accounts_by_tags = [
    {
    key = "AccountType"
    value = "workload"
    }
    ]
  4. Exclusion Options

    exclude_accounts_by_ou_paths = ["/root/workloads/sandbox"]
    exclude_accounts_by_names = ["test-account"]
    exclude_accounts_by_tags = [
    {
    key = "ExcludeFromBaseline"
    value = "true"
    }
    ]

Scheduled Updates

To ensure your baselines remain consistently applied, you can schedule automatic reapplication:

schedule_rerun_every_x_hours = 24  # Rerun daily

This feature is particularly useful for:

  • Correcting manual changes that cause drift
  • Ensuring new resources meet compliance requirements
  • Applying updates to resources that might be modified by other processes

Decommissioning

When you need to remove resources created by a baseline:

decommission_accounts_all = false
decommission_accounts_by_tags = [
{
key = "AccountDecommission"
value = true
}
]

Pipeline Delay Options

To handle dependencies and ensure resources are available before applying the baseline:

pipeline_delay_options = {
wait_for_seconds = 120 # Sets a fixed delay before starting baseline deployment, useful for allowing AWS operations to propagate
wait_retry_count = 5 # Number of times to retry dependency checks before failing, combined with wait_for_seconds can wait up to 10 minutes
wait_for_execution_role = true # Ensures the IAM execution role exists and is accessible in target accounts before proceeding
wait_for_regions = false # If true, checks that all AWS regions specified in baseline_regions are enabled in the account
wait_for_securityhub = false # If true, verifies AWS Security Hub is properly configured before proceeding with the baseline
wait_for_guardduty = false # If true, checks if AWS GuardDuty is properly configured before applying the baseline
}

Differences from Account Lifecycle Management

While Account Lifecycle Management provides event-driven, reactive automation for specific moments, Account Baseline is focused on:

Account BaselineAccount Lifecycle Management
Deployment MethodCI/CD pipeline-based execution
Operational ModeComprehensive, ongoing governance
State ManagementState-based approach that maintains and reconciles desired state
Execution TimingScheduled or on-demand execution
Account TargetingPrecision targeting based on OU paths, tags, or account names
Typical Use CasesStandardized security controls, compliance requirements, organizational policies

Best Practices

  1. Start Simple: Begin with a few essential resources and gradually expand
  2. Test Thoroughly: Test baseline changes in a development environment first
  3. Version Control: Store baseline templates in version control
  4. Modular Design: Break down complex baselines into modular components
  5. Documentation: Document the purpose and requirements of each baseline component
  6. Tagging Strategy: Develop a consistent tagging strategy for resources
  7. Error Handling: Include proper error handling in your baseline code
  8. Idempotency: Ensure your Terraform code is idempotent to avoid issues with repeated applications
  9. Scoping: Use precise account targeting to avoid applying baselines to the wrong accounts
  10. Dependency Management: Consider dependencies between resources and baseline components

FAQ

How do Account Baselines differ from traditional Terraform deployments?

Account Baselines provide several advantages over traditional Terraform deployments:

  • Centralized management through a single point of configuration
  • Multiple account targeting without managing separate state files for each account
  • Automated deployment pipelines that eliminate manual terraform apply steps
  • Consistent provider configuration across all targeted accounts
  • Scheduled reapplication to maintain compliance and prevent drift
  • Coordinated multi-region deployments from a single baseline definition

Can I use both pre-defined and custom templates together?

Yes, you can combine pre-defined templates from the NTC Account Baseline Templates module with your custom templates in the same baseline. This allows you to leverage existing solutions for common tasks while still implementing custom logic for your specific requirements.

How do I handle secrets in my baseline templates?

For handling secrets in your baseline templates, you have several options:

  1. AWS Secrets Manager: Store secrets in Secrets Manager and retrieve them at runtime
  2. AWS Parameter Store: Use Parameter Store for configuration values, especially with SecureString parameters
  3. IAM Role Assumption: Use IAM roles with specific permissions rather than hardcoded credentials
  4. Environment Variables: Pass sensitive values as environment variables to CodeBuild jobs

Never hardcode secrets in your Terraform files. Instead, use:

data "aws_secretsmanager_secret_version" "example" {
secret_id = "arn:aws:secretsmanager:region:account:secret:name"
}

locals {
secret_value = jsondecode(data.aws_secretsmanager_secret_version.example.secret_string)
}

How do I debug issues with my baseline deployment?

When troubleshooting baseline deployment issues:

  1. Check the CodeBuild logs for detailed error messages
  2. Verify that the execution role has the necessary permissions
  3. Inspect the Terraform plan output for expected changes
  4. Check for timeouts or connectivity issues in cross-account operations
  5. Verify that the resources defined in your baseline are valid for all targeted regions
  6. Test your Terraform templates locally before adding them to your baseline

Can I use OpenTofu instead of Terraform for my baselines?

Yes, NTC Account Factory supports both Terraform and OpenTofu. To use OpenTofu:

account_baseline_scopes = [
{
scope_name = "workloads"
terraform_binary = "opentofu" # Specify OpenTofu instead of Terraform
terraform_version = "1.8.5" # Specify OpenTofu version
# ...other configuration...
}
]