Skip to main content
INS // Insights

AWS GovCloud with Terraform: Compliant IaC

Updated March 2026 · 8 min read

Provisioning AWS GovCloud manually creates the same problem it creates everywhere else: configuration drift, undocumented changes, and a system state that diverges from what was authorized. The difference in government environments is that configuration drift in a CMMC or IL4/IL5 system isn't just a technical debt problem — it's an authorization compliance problem.

Infrastructure as Code with Terraform is how Rutagon provisions every AWS GovCloud environment. The IaC approach isn't a preference — it's architecturally required for the kind of auditable, reproducible, and continuously compliant systems that government programs need.

Why GovCloud + IaC Is a Non-Optional Combination

AWS GovCloud (US) is a physically isolated AWS region accessible only to US persons, designed for workloads with export control, ITAR, federal regulatory, and law enforcement requirements. It supports FedRAMP High authorization baseline and serves as the standard hosting environment for IL2 through IL5 workloads depending on configuration.

GovCloud has the same Terraform provider as commercial AWS, meaning all the infrastructure patterns that work in commercial cloud are portable to GovCloud — with additional guardrails required for compliance requirements.

Without IaC, a GovCloud environment will accumulate undocumented changes through manual console access. An ISSO conducting a quarterly review can't verify that the live environment matches the authorized configuration because there's no single authoritative source of truth. IaC solves this by making the Terraform state file the authoritative system description.

The Rutagon GovCloud Terraform Architecture

Multi-Account Foundation

All production government workloads use an AWS Organizations multi-account structure. This provides account-level isolation for different trust boundaries and workload types:

govcloud-org (Management Account)
├── audit-account       # Log archive, security tooling (read-only from workloads)
├── security-account    # Security Hub aggregator, GuardDuty org admin
├── network-account     # Transit Gateway, shared VPCs, firewall
├── prod-account        # Production workloads
└── nonprod-account     # Dev/Test environments

The audit account is isolated from all workload accounts — it has no write access to them, but workloads push logs and compliance reports to it. This prevents a compromised workload account from tampering with its own audit trail.

OIDC-Based CI/CD (Zero Long-Lived Credentials)

The Terraform pipeline runs in GitLab CI with OIDC authentication to AWS. No long-lived access keys anywhere in the pipeline — no AWS_ACCESS_KEY_ID, no AWS_SECRET_ACCESS_KEY:

# Terraform provider authentication via OIDC
provider "aws" {
  region = var.aws_region

  assume_role {
    role_arn = "arn:aws-us-gov:iam::${var.account_id}:role/TerraformDeployRole"
  }
}
# GitLab CI job with OIDC identity token
terraform-apply:
  stage: deploy
  id_tokens:
    AWS_TOKEN:
      aud: "https://gitlab.example.com"
  script:
    - export AWS_ROLE_ARN="arn:aws-us-gov:iam::${ACCOUNT_ID}:role/TerraformDeployRole"
    - export AWS_WEB_IDENTITY_TOKEN_FILE="${AWS_TOKEN_FILE}"
    - terraform init
    - terraform apply -auto-approve

AWS in GovCloud validates the GitLab-issued OIDC token and grants temporary credentials scoped to the minimum required permissions for that pipeline stage. Credentials expire when the job completes.

Compliance Guard Rails at Plan Time

Before any Terraform plan reaches apply, compliance scanning runs against the configuration:

# Checkov scan on terraform plan output
compliance-scan:
  stage: validate
  script:
    - terraform plan -out=tfplan
    - terraform show -json tfplan > tfplan.json
    - checkov -f tfplan.json --framework terraform_plan
      --check CKV_AWS_*
      --output junitxml
      --output-file-path checkov-results.xml
  artifacts:
    reports:
      junit: checkov-results.xml

Checkov checks validate against hundreds of AWS security best practices mapped to NIST 800-53 controls. A plan that introduces a public S3 bucket, disables CloudTrail, or creates an overly-permissive security group fails the pipeline before it ever reaches apply.

Security Controls as Code

Every NIST 800-53 control with an infrastructure expression lives in the Terraform codebase:

# AU-2, AU-12: CloudTrail enabled for all regions with log file validation
resource "aws_cloudtrail" "org_trail" {
  name                          = "org-compliance-trail"
  s3_bucket_name                = aws_s3_bucket.audit_logs.id
  is_multi_region_trail         = true
  enable_log_file_validation    = true
  include_global_service_events = true
  is_organization_trail         = true

  tags = {
    ComplianceControls = "AU-2,AU-12,AU-9"
  }
}

# SC-28: Encryption at rest enforced on all S3 buckets
resource "aws_s3_bucket_server_side_encryption_configuration" "audit_encryption" {
  bucket = aws_s3_bucket.audit_logs.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.audit_cmk.arn
    }
    bucket_key_enabled = true
  }
}

Tagging resources with the NIST 800-53 controls they implement makes the SSP mapping programmatically queryable — when an assessor asks which resources implement AU-9, the answer is a tag filter query, not a document review.

GovCloud-Specific Considerations

GovCloud differs from commercial AWS in ways that matter for IaC:

  • ARN format: GovCloud ARNs use arn:aws-us-gov: instead of arn:aws:. Hardcoded ARNs from commercial AWS templates will fail in GovCloud — use data.aws_partition.current.partition for portable references.
  • Service availability: Not all AWS services are available in GovCloud. Always verify service availability before planning architecture on services like Bedrock, specific Sagemaker features, or newer serverless capabilities.
  • KMS key management: Customer-managed KMS keys are required for CUI encryption — AWS-managed keys are insufficient for most CMMC/IL5 requirements.
  • Access controls: GovCloud restricts access to US persons. Contractor accounts must certify US-person access compliance. This must be enforced through organizational policy and IAM permission boundaries.

Drift Detection and Continuous Compliance

The Terraform state file represents the authorized configuration. Any change to the live environment that wasn't applied through the pipeline is configuration drift — and in an authorized system, drift is a security finding.

Rutagon implements automated drift detection using scheduled Terraform plans:

# Scheduled drift detection job (every 4 hours)
drift-detection:
  stage: compliance
  schedule:
    - cron: "0 */4 * * *"
  script:
    - terraform plan -detailed-exitcode -out=drift-check.tfplan
    - |
      if [ $? -eq 2 ]; then
        echo "DRIFT DETECTED - Notifying security team"
        # Alert to security team via API
        curl -X POST "${SECURITY_ALERT_WEBHOOK}" \
          -d '{"alert": "infrastructure_drift", "severity": "high"}'
        exit 1
      fi

Drift creates an automated alert to the system ISSO. The remediation options are: apply the Terraform correction to re-align with the authorized baseline, or formally document the change through the change control process and update the IaC to reflect the approved change.

See our broader multi-account architecture work in Terraform multi-account AWS patterns and the detailed AWS cloud infrastructure capabilities page.

Frequently Asked Questions

What is AWS GovCloud and when is it required?

AWS GovCloud (US) is a physically isolated AWS region accessible only to US persons and entities, designed for workloads with ITAR, EAR, FedRAMP, DoD, and law enforcement requirements. It's required for workloads at Impact Level 4 and above (CUI and higher), and commonly used for CMMC Level 2/3 environments and federal workloads requiring FedRAMP Moderate/High authorization. For unclassified but sensitive federal data (CUI), GovCloud is the standard choice.

Why use Terraform IaC for AWS GovCloud instead of manual configuration?

Manual GovCloud configuration creates configuration drift, undocumented changes, and an authorized system state that diverges from what's actually deployed. Terraform IaC makes the infrastructure definition version-controlled, peer-reviewed, tested in CI/CD before applying, and continuously comparable against the live environment for drift detection. For government programs, IaC is a compliance enabler: it makes the system's authorized configuration verifiable, reproducible, and auditable.

How does OIDC authentication work for Terraform CI/CD in GovCloud?

OIDC-based authentication allows the CI/CD pipeline to obtain temporary AWS credentials by presenting a short-lived identity token from the CI platform (GitLab, GitHub, etc.), without storing long-lived AWS access keys. AWS in GovCloud validates the token against a configured trust relationship and issues temporary credentials scoped to the minimum required permissions. Credentials expire when the pipeline job completes, leaving no persistent secrets in the CI environment.

What Checkov checks are most important for CMMC/GovCloud compliance?

The highest-priority Checkov checks for CMMC environments include: CKV_AWS_18 (S3 access logging), CKV_AWS_19 (S3 encryption), CKV_AWS_54 (S3 public access blocking), CKV_AWS_67 (CloudTrail multiregion and log validation), CKV_AWS_50 (Lambda public access), CKV_AWS_84 (EKS security groups), and CKV_AWS_111 (IAM policies without wildcards). These map directly to the most commonly cited CMMC control deficiencies. Run these in the pipeline as blocking gates, not advisory warnings.

What is configuration drift and why is it a compliance concern in government cloud?

Configuration drift is any difference between the live infrastructure state and the IaC-defined authorized state. In government environments, the authorized system description in the SSP must match what's actually deployed — drift means the system is running in a state that wasn't authorized, which is a compliance finding. Automated drift detection (via scheduled Terraform plans or tools like Driftctl) identifies drift within hours rather than letting it accumulate for weeks between manual reviews.