Skip to main content

NTC Organizations Migration (v1 → v2)

This guide covers the migration of terraform-aws-ntc-organizations from v1.x to v2.x.

Overview of Changes

v2.0.0 introduces significant architectural improvements to simplify multi-region configurations:

Key Changes

Featurev1.xv2.x
Provider ArchitectureAWS Provider v5AWS Provider v6 with region attribute
Admin DelegationsSeparate module calls per regionIntegrated into root module
Service Quota TemplatesSeparate moduleIntegrated into root module
Multi-Region SupportMultiple provider aliases + module callsSingle module with regions configuration
Module Complexity3+ module calls neededSingle module call

Before & After Comparison

Previous approach required 3 separate module configurations:

# 1. Main organizations module
module "ntc_organizations" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations?ref=1.6.0"
# Configuration...
}

# 2. Admin delegations for eu-central-1
module "ntc_delegated_admins_euc1" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations//modules/regional-admin-delegations?ref=1.6.0"
delegated_administrators = [...]
providers = { aws = aws.euc1 }
}

# 3. Admin delegations for eu-central-2
module "ntc_delegated_admins_euc2" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations//modules/regional-admin-delegations?ref=1.6.0"
delegated_administrators = [...]
providers = { aws = aws.euc2 }
}

# 4. Admin delegations for us-east-1
module "ntc_delegated_admins_use1" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations//modules/regional-admin-delegations?ref=1.6.0"
delegated_administrators = [...]
providers = { aws = aws.use1 }
}

Migration Steps

Step 1: Update Provider Configuration

Update the terraform.required_providers to use AWS Provider v6:

main.tf
terraform {
required_version = ">= 1.3.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = "eu-central-1"
}

provider "aws" {
alias = "euc1"
region = "eu-central-1"
}

provider "aws" {
alias = "euc2"
region = "eu-central-2"
}

provider "aws" {
alias = "use1"
region = "us-east-1"
}

Step 2: Consolidate Module Configuration

2a. Extract Admin Delegations Configuration

If you have separate admin delegation modules, consolidate them:

# In ntc_organizations_admin_delegations.tf
locals {
global_delegated_administrators = [
{
service_principal = "config.amazonaws.com"
admin_account_id = local.security_account_id
},
{
service_principal = "access-analyzer.amazonaws.com"
admin_account_id = local.security_account_id
},
{
service_principal = "backup.amazonaws.com"
admin_account_id = local.backup_account_id
},
]

regional_delegated_administrators = [
{
service_principal = "securityhub.amazonaws.com"
admin_account_id = local.security_account_id
},
{
service_principal = "guardduty.amazonaws.com"
admin_account_id = local.security_account_id
},
{
service_principal = "inspector2.amazonaws.com"
admin_account_id = local.security_account_id
}
]
}

module "ntc_delegated_admins_euc1" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations//modules/regional-admin-delegations?ref=1.5.0"
delegated_administrators = concat(local.global_delegated_administrators, local.regional_delegated_administrators)
providers = { aws = aws.euc1 }
}

module "ntc_delegated_admins_euc2" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations//modules/regional-admin-delegations?ref=1.5.0"
delegated_administrators = local.regional_delegated_administrators
providers = { aws = aws.euc2 }
}

module "ntc_delegated_admins_use1" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations//modules/regional-admin-delegations?ref=1.5.0"
delegated_administrators = local.regional_delegated_administrators
providers = { aws = aws.use1 }
}

2b. Update Service Quota Templates (if used)

If you were using service quota templates, they're now part of the main module:

module "ntc_organizations" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations?ref=2.0.0"

region = "eu-central-1"

# ... other configuration ...

# Service quota templates integrated into main module
service_quota_templates = [
{
regions = ["us-east-1"]
quota_name = "Managed policies per role"
service_code = "iam"
new_value = 20 # Default: 10, Increased for complex permission models
}
]
}

Step 3: Add State Migration Blocks

Create a state_migrations.tf file to migrate resources without recreating them:

state_migrations.tf
# ---------------------------------------------------------------------------------------------------------------------
# ¦ STATE MIGRATIONS - v1.x to v2.x
# ---------------------------------------------------------------------------------------------------------------------
# These moved blocks ensure Terraform state is updated without recreating resources
# Run: terraform plan - should show only "moved" operations (no creates/destroys)
# After successful migration, this file can be deleted

# -------------------------------------------------------------------------------------------------------------------
# Global Admin Delegations
# -------------------------------------------------------------------------------------------------------------------
moved {
from = module.ntc_delegated_admins_euc1.aws_organizations_delegated_administrator.ntc_delegated_admin["access-analyzer.amazonaws.com"]
to = module.ntc_organizations.module.admin_delegations.aws_organizations_delegated_administrator.ntc_delegated_admin["access-analyzer.amazonaws.com"]
}

moved {
from = module.ntc_delegated_admins_euc1.aws_organizations_delegated_administrator.ntc_delegated_admin["backup.amazonaws.com"]
to = module.ntc_organizations.module.admin_delegations.aws_organizations_delegated_administrator.ntc_delegated_admin["backup.amazonaws.com"]
}

moved {
from = module.ntc_delegated_admins_euc1.aws_organizations_delegated_administrator.ntc_delegated_admin["config.amazonaws.com"]
to = module.ntc_organizations.module.admin_delegations.aws_organizations_delegated_administrator.ntc_delegated_admin["config.amazonaws.com"]
}

# -------------------------------------------------------------------------------------------------------------------
# Regional Admin Delegations - eu-central-1
# -------------------------------------------------------------------------------------------------------------------
moved {
from = module.ntc_delegated_admins_euc1.aws_guardduty_detector.ntc_guardduty[0]
to = module.ntc_organizations.module.admin_delegations.aws_guardduty_detector.ntc_guardduty["eu-central-1"]
}

moved {
from = module.ntc_delegated_admins_euc1.aws_guardduty_organization_admin_account.ntc_guardduty[0]
to = module.ntc_organizations.module.admin_delegations.aws_guardduty_organization_admin_account.ntc_guardduty["eu-central-1"]
}

moved {
from = module.ntc_delegated_admins_euc1.aws_inspector2_delegated_admin_account.ntc_inspector[0]
to = module.ntc_organizations.module.admin_delegations.aws_inspector2_delegated_admin_account.ntc_inspector["eu-central-1"]
}

moved {
from = module.ntc_delegated_admins_euc1.aws_securityhub_account.ntc_security_hub[0]
to = module.ntc_organizations.module.admin_delegations.aws_securityhub_account.ntc_security_hub["eu-central-1"]
}

moved {
from = module.ntc_delegated_admins_euc1.aws_securityhub_organization_admin_account.ntc_security_hub[0]
to = module.ntc_organizations.module.admin_delegations.aws_securityhub_organization_admin_account.ntc_security_hub["eu-central-1"]
}

# -------------------------------------------------------------------------------------------------------------------
# Regional Admin Delegations - eu-central-2
# -------------------------------------------------------------------------------------------------------------------
moved {
from = module.ntc_delegated_admins_euc2.aws_guardduty_detector.ntc_guardduty[0]
to = module.ntc_organizations.module.admin_delegations.aws_guardduty_detector.ntc_guardduty["eu-central-2"]
}

moved {
from = module.ntc_delegated_admins_euc2.aws_guardduty_organization_admin_account.ntc_guardduty[0]
to = module.ntc_organizations.module.admin_delegations.aws_guardduty_organization_admin_account.ntc_guardduty["eu-central-2"]
}

moved {
from = module.ntc_delegated_admins_euc2.aws_inspector2_delegated_admin_account.ntc_inspector[0]
to = module.ntc_organizations.module.admin_delegations.aws_inspector2_delegated_admin_account.ntc_inspector["eu-central-2"]
}

moved {
from = module.ntc_delegated_admins_euc2.aws_securityhub_account.ntc_security_hub[0]
to = module.ntc_organizations.module.admin_delegations.aws_securityhub_account.ntc_security_hub["eu-central-2"]
}

moved {
from = module.ntc_delegated_admins_euc2.aws_securityhub_organization_admin_account.ntc_security_hub[0]
to = module.ntc_organizations.module.admin_delegations.aws_securityhub_organization_admin_account.ntc_security_hub["eu-central-2"]
}

# -------------------------------------------------------------------------------------------------------------------
# Regional Admin Delegations - us-east-1
# -------------------------------------------------------------------------------------------------------------------
moved {
from = module.ntc_delegated_admins_use1.aws_guardduty_detector.ntc_guardduty[0]
to = module.ntc_organizations.module.admin_delegations.aws_guardduty_detector.ntc_guardduty["us-east-1"]
}

moved {
from = module.ntc_delegated_admins_use1.aws_guardduty_organization_admin_account.ntc_guardduty[0]
to = module.ntc_organizations.module.admin_delegations.aws_guardduty_organization_admin_account.ntc_guardduty["us-east-1"]
}

moved {
from = module.ntc_delegated_admins_use1.aws_inspector2_delegated_admin_account.ntc_inspector[0]
to = module.ntc_organizations.module.admin_delegations.aws_inspector2_delegated_admin_account.ntc_inspector["us-east-1"]
}

moved {
from = module.ntc_delegated_admins_use1.aws_securityhub_account.ntc_security_hub[0]
to = module.ntc_organizations.module.admin_delegations.aws_securityhub_account.ntc_security_hub["us-east-1"]
}

moved {
from = module.ntc_delegated_admins_use1.aws_securityhub_organization_admin_account.ntc_security_hub[0]
to = module.ntc_organizations.module.admin_delegations.aws_securityhub_organization_admin_account.ntc_security_hub["us-east-1"]
}
State Migration Notes
  • These moved blocks tell Terraform to update its state without recreating resources
  • After successful migration (successful apply), you can delete state_migrations.tf
  • If you have different regions, adjust the region names accordingly

Step 4: Remove Old Definitions

After consolidating the configuration, remove the Admin Delegation and Service Quota Template module calls.

Step 5: Initialize and Plan

# Upgrade to AWS Provider v6
terraform init -upgrade

# Review the plan
terraform plan

Expected plan output:

  • ✅ Many moved operations (state migrations)
  • ✅ Some in-place updates (configuration changes)
  • NO resource deletions or recreations

If you see deletions or recreations, do NOT apply! Review your configuration and state migration blocks carefully.

Step 6: Apply Migration

terraform apply

Monitor the output. The migration should complete without errors.

Step 7: Clean Up

After successful migration:

# Remove the state migration file (optional, but recommended)
rm state_migrations.tf

# Commit your changes
git add .
git commit -m "Migrate ntc-organizations from v1.x to v2.x"

Complete Example

See a complete before/after example in the GitHub repository:

Troubleshooting

Issue: Resources Being Recreated

Symptom: terraform plan shows deletions and recreations

Solution:

  1. Check your moved blocks match your existing state exactly
  2. Verify resource names haven't changed
  3. Use terraform state list to see current resource addresses

Issue: Provider Configuration Errors

Symptom: "provider configuration not present" errors

Solution:

  1. Ensure AWS Provider v6 is installed (terraform init -upgrade)
  2. Verify your required_providers block has version = "~> 6.0"

Issue: Region Not Supported

Symptom: "region not available" errors in ESC

Solution:

  1. For ESC, ensure you're using supported regions
  2. Check region codes match your partition (e.g., eu-central-1 vs eusc-de-east-1)

Need Help?