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
| Feature | v1.x | v2.x |
|---|---|---|
| Provider Architecture | AWS Provider v5 | AWS Provider v6 with region attribute |
| Admin Delegations | Separate module calls per region | Integrated into root module |
| Service Quota Templates | Separate module | Integrated into root module |
| Multi-Region Support | Multiple provider aliases + module calls | Single module with regions configuration |
| Module Complexity | 3+ module calls needed | Single module call |
Before & After Comparison
- v1.x Structure
- v2.x Structure
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 }
}
New consolidated approach with a single module:
module "ntc_organizations" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations?ref=2.0.0"
region = "eu-central-1" # Primary region (optional)
# All delegations configured in one place
delegated_administrators = [
{
service_principal = "securityhub.amazonaws.com"
admin_account_id = "123456789012"
regions = ["eu-central-1", "eu-central-2", "us-east-1"]
},
{
service_principal = "guardduty.amazonaws.com"
admin_account_id = "123456789012"
regions = ["eu-central-1", "eu-central-2", "us-east-1"]
},
{
service_principal = "inspector2.amazonaws.com"
admin_account_id = "123456789012"
regions = ["eu-central-1", "eu-central-2", "us-east-1"]
},
{
service_principal = "config.amazonaws.com"
admin_account_id = "123456789012"
regions = ["eu-central-1"] # Global service - delegate in primary region only
},
{
service_principal = "backup.amazonaws.com"
admin_account_id = "234567890123"
regions = ["eu-central-1"] # Global service - delegate in primary region only
},
]
# Service quotas also integrated
service_quota_templates = [...]
}
Migration Steps
Step 1: Update Provider Configuration
Update the terraform.required_providers to use AWS Provider v6:
- Before (v1.x)
- After (v2.x)
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"
}
terraform {
required_version = ">= 1.5.7"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0" # ← Updated
}
}
}
provider "aws" {
region = "eu-central-1"
}
# Regional providers still needed for some exceptions (where region attribute isn't supported)
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:
- Old Configuration
- New Configuration
# 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 }
}
# In ntc_organizations.tf - add to main module block
module "ntc_organizations" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-organizations?ref=2.0.0"
region = "eu-central-1" # Optional: falls back to provider default
# ... existing configuration ...
# NEW: Consolidated delegated administrators
delegated_administrators = [
{
service_principal = "securityhub.amazonaws.com"
admin_account_id = local.security_account_id
regions = [
"eu-central-1",
"eu-central-2",
"us-east-1",
]
},
{
service_principal = "guardduty.amazonaws.com"
admin_account_id = local.security_account_id
regions = [
"eu-central-1",
"eu-central-2",
"us-east-1",
]
},
{
service_principal = "inspector2.amazonaws.com"
admin_account_id = local.security_account_id
regions = [
"eu-central-1",
"eu-central-2",
"us-east-1",
]
},
{
service_principal = "config.amazonaws.com"
admin_account_id = local.security_account_id
regions = [
"eu-central-1", # Global service - delegate in primary region only
]
},
{
service_principal = "access-analyzer.amazonaws.com"
admin_account_id = local.security_account_id
regions = [
"eu-central-1", # Global service - delegate in primary region only
]
},
{
service_principal = "backup.amazonaws.com"
admin_account_id = local.backup_account_id
regions = [
"eu-central-1", # Global service - delegate in primary region only
]
},
]
}
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 - 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"]
}
- These
movedblocks 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
movedoperations (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:
- Check your
movedblocks match your existing state exactly - Verify resource names haven't changed
- Use
terraform state listto see current resource addresses
Issue: Provider Configuration Errors
Symptom: "provider configuration not present" errors
Solution:
- Ensure AWS Provider v6 is installed (
terraform init -upgrade) - Verify your
required_providersblock hasversion = "~> 6.0"
Issue: Region Not Supported
Symptom: "region not available" errors in ESC
Solution:
- For ESC, ensure you're using supported regions
- Check region codes match your partition (e.g.,
eu-central-1vseusc-de-east-1)
Need Help?
- 📚 Review the main migration guide
- 🐛 Check common issues
- 💬 Contact NTC Support