Skip to content
Infrastructure as Code visualization showing cloud resources defined in configuration files

Modern IaC workflows manage thousands of cloud resources through version-controlled configuration.

Last updated: April 2026 - Covers Terraform 1.14.6 under IBM, OpenTofu 1.9, Pulumi Neo AI agent, AWS CDK v2.180, and Crossplane CNCF graduation.

What Is Infrastructure as Code?

Infrastructure as Code (IaC) is the practice of defining, provisioning, and managing cloud infrastructure through declarative or imperative configuration files rather than manual console clicks. In 2026, IaC isn't optional - it's the foundation of platform engineering, GitOps, and compliance-as-code.

Why IaC Matters

  • Reproducibility - spin up identical environments in minutes
  • Version control - track every infrastructure change in Git
  • Drift detection - know when reality diverges from desired state
  • Compliance - enforce policies before deployment, not after incidents
  • Collaboration - review infra changes in PRs like application code

Declarative vs. Imperative

Declarative (Terraform, CloudFormation, Crossplane): You describe the desired end state. The engine figures out how to get there.

Imperative (Pulumi, AWS CDK, scripts): You describe the steps to execute. More flexible, but you own the ordering logic.

⚠️ Reality check: Most "imperative" tools (Pulumi, CDK) actually compile down to a declarative graph. The distinction is about authoring experience, not execution model.

Terraform (v1.14.6) - The Incumbent

HashiCorp's Terraform remains the most widely deployed IaC tool in production, now under IBM ownership following the $6.4B acquisition completed in early 2025. The controversial switch to the Business Source License (BSL 1.1) in August 2023 permanently fractured the community but hasn't slowed enterprise adoption.

What's New in 2026

  • Stacks GA - first-class multi-environment orchestration without wrapper scripts
  • Ephemeral resources - secrets and temporary credentials that never hit state
  • Terraform Cloud pricing overhaul - IBM introduced usage-based billing per managed resource
  • Provider-defined functions - custom functions shipped inside providers

HCL Example: S3 + CloudFront Static Site

# main.tf - Static site with CloudFront CDN
terraform {
  required_version = ">= 1.14.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.82"
    }
  }
}

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

resource "aws_s3_bucket" "site" {
  bucket = "my-static-site-2026"
}

resource "aws_s3_bucket_website_configuration" "site" {
  bucket = aws_s3_bucket.site.id
  index_document { suffix = "index.html" }
  error_document { key = "404.html" }
}

resource "aws_cloudfront_distribution" "cdn" {
  enabled             = true
  default_root_object = "index.html"

  origin {
    domain_name = aws_s3_bucket.site.bucket_regional_domain_name
    origin_id   = "s3-origin"

    origin_access_control_id = aws_cloudfront_origin_access_control.oac.id
  }

  default_cache_behavior {
    allowed_methods        = ["GET", "HEAD"]
    cached_methods         = ["GET", "HEAD"]
    target_origin_id       = "s3-origin"
    viewer_protocol_policy = "redirect-to-https"

    forwarded_values {
      query_string = false
      cookies { forward = "none" }
    }
  }

  restrictions {
    geo_restriction { restriction_type = "none" }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

resource "aws_cloudfront_origin_access_control" "oac" {
  name                              = "s3-oac"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

Terraform Cloud Pricing (2026)

TierManaged ResourcesPriceIncludes
FreeUp to 500$05 users, basic runs
StandardUp to 5,000$0.03/resource/moTeams, policies, SSO
PlusUnlimited$0.05/resource/moDrift detection, ephemeral workspaces
EnterpriseUnlimitedCustomSelf-hosted agents, audit logs, SLA

OpenTofu - The Open-Source Fork

Born from the BSL backlash, OpenTofu is the Linux Foundation-hosted, MPL 2.0 licensed fork of Terraform. By 2026, it's reached feature parity and added capabilities Terraform lacks - most notably native client-side state encryption.

Key Differentiators

  • MPL 2.0 license - truly open-source, no usage restrictions
  • State encryption - AES-GCM encryption at rest without external tooling
  • Registry independence - uses its own provider registry with Terraform provider compatibility
  • Community governance - steering committee with no single-vendor control

Native State Encryption Example

# opentofu.tf - State encryption configuration
terraform {
  encryption {
    method "aes_gcm" "primary" {
      keys = key_provider.pbkdf2.mykey
    }

    state {
      method   = method.aes_gcm.primary
      enforced = true
    }

    plan {
      method   = method.aes_gcm.primary
      enforced = true
    }
  }
}

key_provider "pbkdf2" "mykey" {
  passphrase = var.state_encryption_passphrase
}

# Usage: tofu init && tofu plan
# State file is encrypted at rest - no cleartext secrets
Case study: Fidelity Investments completed their migration from Terraform Cloud to OpenTofu in Q1 2026, managing 42,000+ resources across 3 clouds. They cited licensing costs and state encryption as primary drivers.

Compatibility

OpenTofu 1.9 maintains ~98% compatibility with Terraform 1.5.x HCL syntax. Most providers work without modification. The main gaps are Terraform-specific features added post-fork (Stacks, ephemeral resources) which OpenTofu implements differently.

Pulumi - Real Languages, Real Tests

Pulumi's pitch is simple: why learn HCL when you can use TypeScript, Python, Go, C#, or Java? In 2026, the Pulumi Neo AI agent can generate and deploy infrastructure from natural language prompts, and the testing story is unmatched.

TypeScript Example: S3 + CloudFront

// index.ts - Static site with CloudFront
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const bucket = new aws.s3.Bucket("site-bucket", {
    website: {
        indexDocument: "index.html",
        errorDocument: "404.html",
    },
});

const oac = new aws.cloudfront.OriginAccessControl("oac", {
    originAccessControlOriginType: "s3",
    signingBehavior: "always",
    signingProtocol: "sigv4",
});

const cdn = new aws.cloudfront.Distribution("cdn", {
    enabled: true,
    defaultRootObject: "index.html",
    origins: [{
        domainName: bucket.bucketRegionalDomainName,
        originId: "s3-origin",
        originAccessControlId: oac.id,
    }],
    defaultCacheBehavior: {
        allowedMethods: ["GET", "HEAD"],
        cachedMethods: ["GET", "HEAD"],
        targetOriginId: "s3-origin",
        viewerProtocolPolicy: "redirect-to-https",
        forwardedValues: {
            queryString: false,
            cookies: { forward: "none" },
        },
    },
    restrictions: {
        geoRestriction: { restrictionType: "none" },
    },
    viewerCertificate: {
        cloudfrontDefaultCertificate: true,
    },
});

export const cdnUrl = pulumi.interpolate`https://${cdn.domainName}`;

Pulumi Neo AI Agent

Launched in 2026, Neo generates Pulumi programs from natural language, explains existing infrastructure, and suggests security improvements. It integrates directly into pulumi up workflows and can auto-fix failing deployments.

Testing Advantage

Because Pulumi uses real languages, you get real testing frameworks:

// index.test.ts - Unit test with Vitest
import { describe, it, expect } from "vitest";
import * as pulumi from "@pulumi/pulumi/runtime";

pulumi.setMocks({ /* mock resource creation */ });

describe("Static Site", () => {
    it("bucket has website config", async () => {
        const { bucket } = await import("./index");
        const website = await bucket.website;
        expect(website?.indexDocument).toBe("index.html");
    });

    it("CDN enforces HTTPS", async () => {
        const { cdn } = await import("./index");
        const behavior = await cdn.defaultCacheBehavior;
        expect(behavior?.viewerProtocolPolicy).toBe("redirect-to-https");
    });
});

Pulumi Cloud Pricing (2026)

TierResourcesPriceFeatures
IndividualUp to 200Free1 user, basic state
TeamUnlimited$89/user/moRBAC, secrets, deployments
EnterpriseUnlimitedCustomSSO, audit logs, Neo AI, SLA

AWS CDK v2 - AWS-Native Power

The AWS Cloud Development Kit lets you define AWS infrastructure using TypeScript, Python, Java, C#, or Go. It synthesizes to CloudFormation under the hood, giving you the full power of CFN with a dramatically better authoring experience.

TypeScript Example: S3 + CloudFront

// lib/static-site-stack.ts
import * as cdk from "aws-cdk-lib";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as origins from "aws-cdk-lib/aws-cloudfront-origins";
import { Construct } from "constructs";

export class StaticSiteStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);

        const bucket = new s3.Bucket(this, "SiteBucket", {
            removalPolicy: cdk.RemovalPolicy.DESTROY,
            blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
        });

        const distribution = new cloudfront.Distribution(this, "CDN", {
            defaultBehavior: {
                origin: origins.S3BucketOrigin.withOriginAccessControl(bucket),
                viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
            },
            defaultRootObject: "index.html",
        });

        new cdk.CfnOutput(this, "DistributionUrl", {
            value: `https://${distribution.distributionDomainName}`,
        });
    }
}

L1 / L2 / L3 Constructs

  • L1 (Cfn*) - 1:1 mapping to CloudFormation resources. Verbose but complete.
  • L2 (Default) - Opinionated wrappers with sensible defaults. What you'll use 90% of the time.
  • L3 (Patterns) - Multi-resource architectures in one construct (e.g., ApplicationLoadBalancedFargateService).

Strengths & Weaknesses

StrengthsWeaknesses
Deepest AWS integrationAWS-only (no multi-cloud)
L3 patterns save massive timeCloudFormation limits (500 resources/stack)
Free - no SaaS dependencySlow deployments (CFN changeset overhead)
Type-safe with full IDE supportDrift detection requires separate tooling

Crossplane - Kubernetes-Native IaC

Crossplane graduated from the CNCF in 2025, cementing its position as the Kubernetes-native approach to infrastructure management. Instead of a CLI workflow, Crossplane uses the Kubernetes API and continuous reconciliation - your cluster is your control plane.

YAML Example: S3 Bucket

# crossplane/s3-bucket.yaml
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
  name: my-static-site
  namespace: infra
spec:
  forProvider:
    region: us-east-1
    tags:
      Environment: production
      ManagedBy: crossplane
  providerConfigRef:
    name: aws-provider
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: BucketWebsiteConfiguration
metadata:
  name: my-static-site-web
spec:
  forProvider:
    bucketRef:
      name: my-static-site
    region: us-east-1
    indexDocument:
      - suffix: index.html
    errorDocument:
      - key: 404.html

Continuous Reconciliation

Unlike Terraform's plan/apply cycle, Crossplane continuously reconciles desired state. If someone manually deletes a resource, Crossplane recreates it within seconds. This makes it ideal for:

  • Platform teams offering self-service infrastructure via Kubernetes APIs
  • Environments requiring strict drift prevention
  • Organizations already invested in the Kubernetes ecosystem
⚠️ Trade-off: Crossplane requires a running Kubernetes cluster as a prerequisite. You need infrastructure to manage infrastructure - the "bootstrapping problem."

IaC Tools Compared - 2026

Tool License Language Multi-Cloud State Drift Detection Pricing
Terraform BSL 1.1 HCL ✅ 4,000+ providers Remote (TF Cloud/S3) TF Cloud Plus tier Free CLI / $0.03-0.05/resource
OpenTofu MPL 2.0 HCL ✅ TF-compatible providers Encrypted local/remote Community tooling Free (open-source)
Pulumi Apache 2.0 (engine) TS/Python/Go/C#/Java ✅ 150+ providers Pulumi Cloud/self-managed Built-in (refresh) Free / $89/user/mo
AWS CDK Apache 2.0 TS/Python/Java/C#/Go ❌ AWS only CloudFormation CFN drift detection Free
Crossplane Apache 2.0 YAML (K8s manifests) ✅ Multi-cloud providers Kubernetes etcd Continuous reconciliation Free (open-source)
CloudFormation Proprietary JSON/YAML ❌ AWS only AWS-managed Built-in Free

CI/CD with GitHub Actions

The gold standard for IaC CI/CD in 2026: OIDC authentication (no long-lived credentials), plan-on-PR with comment output, security scanning before apply, and manual approval gates for production.

Terraform GitHub Actions Workflow

# .github/workflows/terraform.yml
name: "Terraform"
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  id-token: write   # OIDC
  contents: read
  pull-requests: write

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS Credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-terraform
          aws-region: us-east-1

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "1.14.6"

      - name: Terraform Init
        run: terraform init

      - name: Security Scan (Trivy)
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: "config"
          scan-ref: "."
          exit-code: "1"
          severity: "HIGH,CRITICAL"

      - name: Terraform Plan
        id: plan
        run: terraform plan -no-color -out=tfplan
        continue-on-error: true

      - name: Comment Plan on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const output = `#### Terraform Plan 📋
            \`\`\`
            ${{ steps.plan.outputs.stdout }}
            \`\`\`
            *Triggered by @${{ github.actor }}*`;
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: output
            });

  apply:
    needs: plan
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production  # Requires manual approval
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-terraform
          aws-region: us-east-1
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init
      - run: terraform apply -auto-approve
💡 Pro tip: Always use OIDC federation instead of storing AWS access keys as GitHub secrets. OIDC tokens are short-lived and scoped to specific repos/branches.

Security Scanning for IaC

Shift-left security means catching misconfigurations before they reach production. In 2026, three tools dominate the IaC security scanning space.

Trivy (Aqua Security)

Trivy absorbed tfsec in 2024 and is now the de facto standard for IaC scanning. It covers Terraform, CloudFormation, Kubernetes manifests, Dockerfiles, and Helm charts in a single binary.

# Scan current directory for IaC misconfigurations
$ trivy config .

# Scan with specific severity threshold
$ trivy config --severity HIGH,CRITICAL --exit-code 1 .

# Output as SARIF for GitHub Security tab
$ trivy config --format sarif --output results.sarif .

Checkov (Prisma Cloud)

Checkov offers 1,000+ built-in policies and supports custom rules in Python or YAML. It excels at compliance frameworks (CIS, SOC2, HIPAA) with out-of-the-box policy packs.

# Scan Terraform directory
$ checkov -d . --framework terraform

# Run specific compliance framework
$ checkov -d . --check CIS_AWS

# Skip specific checks
$ checkov -d . --skip-check CKV_AWS_18,CKV_AWS_19

Snyk IaC

Snyk IaC integrates with Snyk's vulnerability database and provides fix suggestions alongside findings. Best for teams already using Snyk for application security.

# Scan and get remediation advice
$ snyk iac test . --report

# Custom rules with OPA/Rego
$ snyk iac test . --rules=./custom-rules/
ToolLicenseStrengthsBest For
TrivyApache 2.0All-in-one, fast, CI-friendlyTeams wanting one scanner for everything
CheckovApache 2.0Compliance frameworks, custom policiesRegulated industries
Snyk IaCProprietaryFix suggestions, developer UXTeams already on Snyk platform

Real-World Pain Points

IaC marketing makes everything look clean. Production reality is messier. Here's what actually hurts in 2026:

1. State Conflicts

Two engineers run terraform apply simultaneously. One wins, one gets a state lock error - or worse, with misconfigured backends, both write and corrupt state. Solutions:

  • DynamoDB state locking (Terraform/OpenTofu)
  • Pulumi Cloud's built-in concurrency control
  • CI/CD serialization - only one apply runs at a time

2. Provider Version Hell

The AWS provider ships weekly. Pin versions aggressively or face breaking changes:

# Bad - will break eventually
required_providers {
  aws = { source = "hashicorp/aws", version = ">= 5.0" }
}

# Good - predictable builds
required_providers {
  aws = { source = "hashicorp/aws", version = "~> 5.82.0" }
}

3. Blast Radius

A single state file managing 2,000 resources means one bad apply can destroy everything. Mitigation:

  • Split into small, focused state files (10-50 resources each)
  • Use Terraform Stacks or Terragrunt for orchestration
  • Implement prevent_destroy lifecycle rules on critical resources
  • Require manual approval for any plan with destroys

4. The Friday Afternoon Problem

⚠️ Never deploy infrastructure changes on Friday afternoon. If a Terraform apply partially fails at 4:45 PM, you're debugging state inconsistencies all weekend. Enforce deployment windows in CI/CD and use environment protection rules.

🚀 Getting Started

New to IaC? Start with OpenTofu for the best open-source experience, or AWS CDK if you're AWS-only. Use Trivy for security scanning from day one, and implement CI/CD before your second apply.