Geopatriation — localizing data, compute, and cloud infrastructure for regulatory and resilience reasons — is a top Gartner 2026 strategic trend. Countries are increasingly requiring that certain data stays within their borders. The EU’s GDPR, China’s PIPL, India’s DPDPA, and sector-specific regulations in finance and healthcare all drive data residency requirements.
Terraform is the ideal tool for enforcing data sovereignty because infrastructure-as-code can be audited, policy-checked, and consistently deployed to specific regions.
Architecture: Region-Locked Infrastructure
┌─────────────────────────────────────┐
│ AWS Organization │
│ │
│ SCP: Deny all regions except │
│ eu-central-1, eu-west-1 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ eu-central-1 │ │ eu-west-1 │ │
│ │ (Frankfurt) │ │ (Ireland) │ │
│ │ │ │ │ │
│ │ Production │ │ DR/Backup │ │
│ │ VPC + RDS │ │ S3 Replicas │ │
│ │ + S3 │ │ │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────┘
Service Control Policy: Restrict Regions
resource "aws_organizations_policy" "eu_only" {
name = "eu-region-restriction"
type = "SERVICE_CONTROL_POLICY"
content = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "DenyNonEURegions"
Effect = "Deny"
Action = "*"
Resource = "*"
Condition = {
StringNotEquals = {
"aws:RequestedRegion" = [
"eu-central-1", # Frankfurt
"eu-west-1", # Ireland
"eu-west-2", # London
"eu-west-3", # Paris
"eu-north-1", # Stockholm
"eu-south-1", # Milan
"eu-south-2", # Spain
"eu-central-2" # Zurich
]
}
# Exempt global services
StringNotLike = {
"aws:PrincipalArn" = "arn:aws:iam::*:role/OrganizationAdmin"
}
}
},
{
Sid = "AllowGlobalServices"
Effect = "Allow"
Action = [
"iam:*",
"sts:*",
"organizations:*",
"support:*",
"budgets:*",
"waf:*",
"cloudfront:*",
"route53:*",
"health:*"
]
Resource = "*"
}
]
})
}
resource "aws_organizations_policy_attachment" "eu_only" {
policy_id = aws_organizations_policy.eu_only.id
target_id = var.eu_ou_id # Attach to EU organizational unit
}
Region-Locked Provider Configuration
# Enforce region at the Terraform level
variable "allowed_regions" {
type = list(string)
default = ["eu-central-1", "eu-west-1"]
validation {
condition = alltrue([
for r in var.allowed_regions : can(regex("^eu-", r))
])
error_message = "Only EU regions are allowed for this deployment."
}
}
provider "aws" {
region = var.allowed_regions[0] # Primary: Frankfurt
default_tags {
tags = {
DataResidency = "EU"
Compliance = "GDPR"
ManagedBy = "Terraform"
}
}
}
provider "aws" {
alias = "dr"
region = var.allowed_regions[1] # DR: Ireland
default_tags {
tags = {
DataResidency = "EU"
Compliance = "GDPR"
}
}
}
S3 with Region Lock and Replication
resource "aws_s3_bucket" "data" {
provider = aws
bucket = "eu-customer-data-${data.aws_caller_identity.current.account_id}"
tags = {
DataClassification = "personal-data"
DataResidency = "eu-central-1"
Regulation = "GDPR-Article-44"
}
}
# Block public access
resource "aws_s3_bucket_public_access_block" "data" {
bucket = aws_s3_bucket.data.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# Replicate only within EU
resource "aws_s3_bucket_replication_configuration" "eu_replica" {
bucket = aws_s3_bucket.data.id
role = aws_iam_role.replication.arn
rule {
id = "eu-replication"
status = "Enabled"
destination {
bucket = aws_s3_bucket.data_replica.arn
storage_class = "STANDARD_IA"
encryption_configuration {
replica_kms_key_id = aws_kms_key.eu_west.arn
}
}
source_selection_criteria {
sse_kms_encrypted_objects {
status = "Enabled"
}
}
}
depends_on = [aws_s3_bucket_versioning.data]
}
resource "aws_s3_bucket" "data_replica" {
provider = aws.dr
bucket = "eu-customer-data-replica-${data.aws_caller_identity.current.account_id}"
tags = {
DataResidency = "eu-west-1"
Purpose = "disaster-recovery"
}
}
RDS with EU-Only Encryption
resource "aws_kms_key" "eu_database" {
provider = aws
description = "EU-only database encryption key"
# Key cannot be shared outside EU regions
tags = {
DataResidency = "eu-central-1"
KeyPurpose = "database-encryption"
}
}
resource "aws_db_instance" "main" {
identifier = "eu-customer-db"
engine = "postgres"
engine_version = "16.3"
instance_class = "db.r6g.large"
allocated_storage = 100
storage_encrypted = true
kms_key_id = aws_kms_key.eu_database.arn
# Multi-AZ within the same region (stays in Frankfurt)
multi_az = true
# No cross-region read replicas (data stays in EU)
# Use aws_db_instance_automated_backups_replication for EU-only backup replication
deletion_protection = true
tags = {
DataResidency = "eu-central-1"
DataClassification = "personal-data"
}
lifecycle {
prevent_destroy = true
}
}
Terraform Sentinel / OPA Policy
Enforce data residency in CI/CD:
# policy/data-residency.rego (Open Policy Agent)
package terraform.analysis
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket"
# Check region from provider config
not startswith(resource.provider_name, "aws.eu")
msg := sprintf(
"S3 bucket '%s' must be deployed in an EU region for GDPR compliance",
[resource.address]
)
}
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_db_instance"
not resource.change.after.storage_encrypted
msg := sprintf(
"RDS instance '%s' must have encryption enabled for compliance",
[resource.address]
)
}
Compliance Tagging Module
module "compliance_tags" {
source = "./modules/compliance-tags"
data_residency = "EU"
regulation = "GDPR"
data_classification = "personal-data"
data_controller = var.company_name
retention_days = 2555 # 7 years
}
# modules/compliance-tags/main.tf
variable "data_residency" { type = string }
variable "regulation" { type = string }
variable "data_classification" { type = string }
variable "data_controller" { type = string }
variable "retention_days" { type = number }
output "tags" {
value = {
DataResidency = var.data_residency
Regulation = var.regulation
DataClassification = var.data_classification
DataController = var.data_controller
RetentionDays = tostring(var.retention_days)
ManagedBy = "Terraform"
LastAudit = formatdate("YYYY-MM-DD", timestamp())
}
}
Hands-On Courses
- Terraform for Beginners on CopyPasteLearn
- Terraform By Example — practical code examples
Conclusion
Data sovereignty requires enforcement at multiple layers: SCPs to restrict regions at the AWS Organizations level, Terraform provider configuration to lock deployments to specific regions, S3 replication rules that stay within allowed geographies, and OPA/Sentinel policies in CI/CD. Terraform makes these constraints auditable and repeatable — critical as geopatriation regulations expand globally in 2026.