2026-04-30·12 min read·

AWS CloudFormation EU Alternative 2026: Infrastructure Templates, GDPR Compliance, and CLOUD Act Risk

Post #717 in the sota.io EU Compliance Series

AWS CloudFormation is the foundational layer of most AWS deployments: you describe your infrastructure in JSON or YAML templates, and CloudFormation creates, updates, and deletes resources to match that description. It is elegant infrastructure-as-code that most AWS-native teams take for granted.

What teams less often consider is that CloudFormation, in doing its job, accumulates a comprehensive record of your entire infrastructure architecture — every template you have ever deployed, every change you have ever made, every resource relationship, and the parameter values that configure your systems. That record lives in your AWS account, under US jurisdiction, where it is subject to CLOUD Act compelled disclosure.

For organizations processing EU personal data, this creates a risk that is easy to miss: your infrastructure blueprints contain information about every system that processes personal data, potentially including connection strings, encryption key references, and service configurations. A compelled disclosure of your CloudFormation state is effectively a map of your personal data processing architecture.

What AWS CloudFormation Stores

Stack Templates and State

When you create a CloudFormation stack, AWS stores the template in S3 under your account. CloudFormation maintains the full current state of each stack — which resources exist, what their configurations are, and how they relate to each other. This is necessary for CloudFormation to calculate change sets: it needs to know the current state to determine what actions are required to move from state A to state B.

The stored state includes:

{
  "StackId": "arn:aws:cloudformation:eu-central-1:123456789:stack/production-api/abc123",
  "StackName": "production-api",
  "Description": "Production API stack — processes user profiles, payment data",
  "Parameters": [
    {
      "ParameterKey": "DatabaseEndpoint",
      "ParameterValue": "prod-db.cluster-abc123.eu-central-1.rds.amazonaws.com"
    },
    {
      "ParameterKey": "RedisEndpoint",
      "ParameterValue": "prod-cache.abc123.0001.euc1.cache.amazonaws.com"
    },
    {
      "ParameterKey": "UserDataBucketName",
      "ParameterValue": "prod-user-uploads-eu-central-1"
    }
  ],
  "Resources": {
    "UserAPIFunction": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Handler": "index.handler",
        "Role": "arn:aws:iam::123456789:role/UserAPIRole",
        "Environment": {
          "Variables": {
            "STRIPE_PUBLISHABLE_KEY": "pk_live_...",
            "SEGMENT_WRITE_KEY": "..."
          }
        }
      }
    }
  }
}

Parameter values passed to CloudFormation stacks are stored in plaintext unless explicitly marked as NoEcho. In practice, many CloudFormation deployments pass endpoint URLs, queue names, bucket names, and service identifiers as parameters — all of which reveal your data processing architecture.

Change Sets and Deployment History

CloudFormation stores the complete history of every change set: what was proposed, what was approved or rejected, what resources were modified, created, or deleted, and when. This history persists indefinitely by default.

Change set history creates a timeline of your infrastructure evolution. Reviewing it reveals when you added a new database, when you moved from one queue service to another, when you scaled up your processing capacity. Combined with the resource ARNs and service identifiers in each change set, this creates a longitudinal record of your personal data processing systems.

{
  "ChangeSetId": "arn:aws:cloudformation:eu-central-1:123456789:changeSet/add-gdpr-processor/...",
  "ChangeSetName": "add-gdpr-processor",
  "Description": "Add GDPR data export Lambda + DynamoDB table for user data requests",
  "Changes": [
    {
      "Type": "Resource",
      "ResourceChange": {
        "Action": "Add",
        "LogicalResourceId": "GDPRExportFunction",
        "ResourceType": "AWS::Lambda::Function",
        "Details": [
          {
            "Target": {
              "Attribute": "Properties",
              "Name": "Environment"
            },
            "ChangeSource": "DirectModification"
          }
        ]
      }
    }
  ]
}

The change set name in this example explicitly reveals the purpose: GDPR data export processing. CloudFormation history effectively documents your compliance architecture — and stores it under US jurisdiction.

Stack Events

Every resource creation, update, and deletion generates a stack event. CloudFormation retains these events and makes them available via API. Stack events include timestamps, resource types, resource IDs, status messages, and reason strings.

Status reason strings are particularly revealing. When a resource creation fails, CloudFormation records the error message as the reason — often including configuration details, endpoint names, and service-specific error messages that reveal what you were trying to build and why it failed.

Drift Detection Results

CloudFormation's drift detection feature compares your deployed infrastructure against the expected state defined in your template. When it detects drift, it records exactly which properties have changed and what the actual values are.

A drift detection result for a modified security group shows the actual current inbound rules — including which IP ranges can access which ports, revealing your network perimeter configuration. For a Lambda function, drift results show the current environment variables, which may include service endpoints and configuration values not in your template.

The GDPR Risk Analysis

Infrastructure State as Personal Data

The direct argument that CloudFormation state contains personal data is straightforward: if your infrastructure processes personal data, then a complete description of that infrastructure — which services exist, how they connect, what they are named, and how they are configured — constitutes information from which your data processing activities can be identified.

Under GDPR, this is relevant because:

Article 32 requires organizations to implement appropriate technical measures to ensure security of processing. This includes protecting information about your processing systems from unauthorized access. An infrastructure blueprint under extraterritorial jurisdiction is a security risk to those systems.

Article 25 (Data Protection by Design) requires considering the risks of processing at the point of system design. Designing infrastructure that places detailed records of your personal data processing systems under US jurisdiction — even if the systems themselves are in the EU — creates a structural GDPR tension.

Article 28 requires that your processors (AWS) process data only on your instructions. The CLOUD Act creates a parallel authority structure: US government agencies can compel AWS to produce data on their instructions, independently of yours. CloudFormation state held under this parallel authority structure creates an Article 28 gap.

The Parameter Value Problem

CloudFormation parameters are designed to externalize configuration from templates. In practice, parameters often contain:

Parameters marked NoEcho are not returned by the DescribeStacks API — but they are still stored by CloudFormation and are potentially accessible through internal AWS mechanisms under a CLOUD Act request.

The critical point is that NoEcho is an API parameter, not a cryptographic protection. It controls what the CloudFormation API returns to you. It does not determine what CloudFormation stores internally or what AWS can produce under a government order.

Template Secrets: A Common Antipattern

Despite security guidance discouraging it, CloudFormation templates frequently contain secrets embedded directly in resource definitions. Lambda environment variables are a common vector:

Resources:
  ProcessingFunction:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          DATABASE_PASSWORD: !Ref DatabasePassword
          JWT_SECRET: !Ref JWTSecret
          ENCRYPTION_KEY: !Ref EncryptionKey

Even when using Parameter Store or Secrets Manager references ({{resolve:ssm:/prod/db/password}}), the template itself reveals that these secrets exist and what their parameter paths are — enabling a sophisticated adversary to target them specifically.

Cross-Stack References and StackSets

CloudFormation supports cross-stack references via Outputs and Exports. When Stack A exports a value that Stack B imports, CloudFormation maintains the relationship. An export map reveals:

For multi-account deployments using CloudFormation StackSets, AWS Organizations is used to manage deployment across accounts. StackSets state reveals your account structure, which environments you have, and which regions you deploy to — all under the same CLOUD Act exposure.

CLOUD Act Risk Profile

The specific CLOUD Act risk with CloudFormation is distinct from data-at-rest risks like S3 or RDS. Here, the exposed data is architectural intelligence:

What a compelled disclosure delivers:

This is not user data in the conventional sense. But it is intelligence about your systems that process user data — intelligence that could be used to:

  1. Identify which systems hold personal data for specific user populations
  2. Understand the architecture for targeting subsequent requests more precisely
  3. Map data flows to understand which services transmit which categories of data

For regulated industries (healthcare, finance, legal), this architectural intelligence may be independently sensitive — separate from the personal data itself.

EU-Sovereign IaC Alternatives

The IaC ecosystem has several mature alternatives that can be operated entirely within EU-sovereign infrastructure.

CapabilityAWS CloudFormationOpenTofuTerraform (EU backend)Pulumi (Self-hosted)Crossplane
State storageAWS (US jurisdiction)Self-hosted (EU)Self-hosted (EU)Self-hosted (EU)Kubernetes CRDs (EU)
Provider supportAWS-onlyMulti-cloudMulti-cloudMulti-cloudMulti-cloud
Template languageJSON/YAMLHCLHCLTypeScript/Python/GoYAML
Secret handlingParameter Store / NoEchoVault / SOPS integrationVault / SOPS integrationESC (Environments, Secrets, Config)External Secrets Operator
Drift detectionBuilt-inManual (terraform plan)Manual (terraform plan)Built-inContinuous reconciliation
EU-sovereign?No (AWS US parent)Yes (Linux Foundation)No (HashiCorp/IBM) — state backend can be EUYes (self-hosted)Yes (CNCF, self-hosted)
LicenseAWS proprietaryMPL 2.0BSL 1.1 (post-1.5.x)Apache 2.0Apache 2.0

OpenTofu

OpenTofu is the Linux Foundation-governed fork of Terraform, created after HashiCorp's license change in 2023. It is functionally equivalent to Terraform for most use cases and maintains binary compatibility with existing Terraform providers and modules.

EU-sovereignty characteristics:

terraform {
  backend "s3" {
    bucket   = "your-eu-state-bucket"
    key      = "production/terraform.tfstate"
    region   = "eu-central-1"
    endpoint = "https://your-eu-s3-compatible.storage"
  }
}

For organizations currently using Terraform, migration to OpenTofu requires only changing the binary — state files and providers are compatible.

Pulumi (Self-Hosted Backend)

Pulumi allows you to define infrastructure using general-purpose programming languages: TypeScript, Python, Go, C#. This enables more expressive infrastructure definitions than HCL, with full IDE support, testing frameworks, and code reuse patterns.

EU-sovereignty characteristics:

import * as aws from "@pulumi/aws";

const vpc = new aws.ec2.Vpc("eu-vpc", {
    cidrBlock: "10.0.0.0/16",
    enableDnsHostnames: true,
    tags: { Environment: "production", DataClassification: "personal-data" },
});

const privateSubnet = new aws.ec2.Subnet("private-subnet", {
    vpcId: vpc.id,
    cidrBlock: "10.0.1.0/24",
    availabilityZone: "eu-central-1a",
});

Migration from CloudFormation: AWS provides a CloudFormation migration guide, and Pulumi's cf2pulumi tool can convert existing templates.

Crossplane

Crossplane is a CNCF project that extends Kubernetes to manage external infrastructure. Your infrastructure definitions live as Kubernetes custom resources (CRDs), and Crossplane controllers reconcile the actual state of your cloud resources to match.

EU-sovereignty characteristics:

apiVersion: ec2.aws.upbound.io/v1beta1
kind: VPC
metadata:
  name: production-vpc
  annotations:
    crossplane.io/external-name: vpc-id
spec:
  forProvider:
    region: eu-central-1
    cidrBlock: 10.0.0.0/16
    enableDnsHostnames: true
  providerConfigRef:
    name: eu-aws-provider

Crossplane is appropriate for teams already running Kubernetes, as it adds infrastructure management to an existing cluster rather than introducing a new tool chain.

Ansible (Procedural Alternative)

For organizations that prefer procedural over declarative infrastructure management, Ansible provides a mature alternative that stores no state externally. Playbook runs are stateless by default — Ansible connects to resources, reads their current state, and applies changes. There is no central state file that must be stored.

EU-sovereignty characteristics:

For EU sovereignty, Ansible + AWX hosted on EU infrastructure is a fully sovereign option with no US-jurisdiction dependencies.

Migration Strategy

Phase 1: State Backend Migration (Lowest Risk)

If you are using Terraform/OpenTofu and currently storing state in S3 or Terraform Cloud:

  1. Export current state: terraform state pull > terraform.tfstate
  2. Configure new EU-sovereign backend (MinIO on Hetzner, PostgreSQL on EU-hosted RDS, S3-compatible on OVH)
  3. Push state to new backend: terraform state push terraform.tfstate
  4. Update all CI/CD pipelines to use new backend configuration

This migration preserves all existing Terraform code and simply moves state storage to EU jurisdiction.

Phase 2: CloudFormation Template Conversion

For existing CloudFormation stacks, conversion to OpenTofu/Terraform involves:

  1. Import existing resources: terraform import aws_vpc.main vpc-abc123 — map existing resources to new Terraform definitions without recreation
  2. Generate template from state: terraform show -json | jq to understand current resource configurations
  3. Verify with plan: terraform plan should show no changes after successful import

AWS's former2 tool (community project) can generate Terraform/CDK from existing CloudFormation stacks, accelerating large migrations.

Phase 3: Secret Sanitization

Before migrating templates, audit all CloudFormation parameters and template literal values:

# Find potentially embedded secrets in CloudFormation templates
grep -r -i "password\|secret\|key\|token\|credential" cloudformation/ \
  --include="*.yaml" --include="*.json" \
  | grep -v "NoEcho\|ParameterType\|Description"

Secrets found in templates should be migrated to:

Deployment on sota.io

sota.io deploys directly from your git repository. Your IaC definitions remain in your version control system — no deployment state leaves your infrastructure. Deploy containers defined with any IaC tool, with secrets injected at runtime via environment variables you control:

# Infrastructure definition in your repo (Pulumi/OpenTofu/Ansible)
# sota.io deploys the resulting container with your env vars
sota deploy --env DATABASE_URL=$EU_DB_URL --env ENCRYPTION_KEY=$VAULT_SECRET

The stack state — what was deployed, with which configuration, when — stays in your EU-sovereign state backend. sota.io never holds your infrastructure definitions or deployment history.

Implementation Checklist

For teams evaluating CloudFormation's GDPR posture:

Immediate (1 week):

Short-term (1 month):

Strategic (3 months):

Summary

AWS CloudFormation is convenient and deeply integrated with the AWS ecosystem. That integration is also its GDPR risk: CloudFormation state is stored by AWS, subject to the same CLOUD Act exposure as any other AWS-managed data. The difference from a database backup is that CloudFormation state describes your processing systems rather than your users' data — but under GDPR's broad definition of personal data and its requirements for processing security, the distinction matters less than you might assume.

OpenTofu (for HCL users), Pulumi with a self-hosted backend (for TypeScript/Python developers), and Crossplane (for Kubernetes-native teams) all provide CloudFormation-equivalent capabilities with EU-sovereign state storage. The migration path is incremental: start with state backend migration to EU jurisdiction, then convert templates at your own pace.

The IaC migration is not urgent in the same way a live database migration is. But if you are deploying on AWS, your CloudFormation state is accumulating under US jurisdiction every day — growing in both scope and sensitivity as your infrastructure evolves.

EU-Native Hosting

Ready to move to EU-sovereign infrastructure?

sota.io is a German-hosted PaaS — no CLOUD Act exposure, no US jurisdiction, full GDPR compliance by design. Deploy your first app in minutes.