← Back to Blog
Cloud Security Advanced 14 min

Cloud Security & IaC Engineering: Terraform Remote State Hardening & S3 Bucket Policy Defense

Protect sensitive Terraform state files, configure KMS client-side encryption, lock down public S3 access, and implement CloudTrail alert playbooks.

AWSTerraformS3KMSCloudTrailCloud Security
Terraform Remote State S3 KMS Hardening Architecture

Terraform state files (terraform.tfstate) contain plain-text database passwords, private API keys, TLS certificates, and resource IDs. Leaving an S3 remote state bucket unencrypted or publicly accessible guarantees full infrastructure compromise.

In this second part of our Practical Cloud Security & IaC Defense playlist, we harden S3 remote backends with AWS KMS Customer Managed Keys (CMK), enforce SSL-only access, and automate public bucket block enforcement.


1. Hardening S3 Terraform Remote State Backends

A secure Terraform S3 backend configuration requires:

  1. Server-Side Encryption with KMS CMK (aws:kms).
  2. Versioning (to restore state after accidental deletion or ransomware).
  3. DynamoDB State Locking (to prevent race conditions during concurrent terraform apply).
  4. Public Access Block Enabled across all four settings.
# S3 Bucket for Remote State
resource "aws_s3_bucket" "tf_state" {
  bucket        = "dynamo2k1-terraform-state-prod"
  force_destroy = false

  lifecycle {
    prevent_destroy = true # Safeguard state bucket deletion
  }
}

# Block all public access
resource "aws_s3_bucket_public_access_block" "tf_state_block" {
  bucket = aws_s3_bucket.tf_state.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

# Enforce Versioning
resource "aws_s3_bucket_versioning" "tf_state_versioning" {
  bucket = aws_s3_bucket.tf_state.id
  versioning_configuration {
    status = "Enabled"
  }
}

# KMS Encryption Policy
resource "aws_s3_bucket_server_side_encryption_configuration" "tf_state_crypto" {
  bucket = aws_s3_bucket.tf_state.id

  rule {
    apply_server_side_encryption_by_default {
      kms_master_key_id = aws_kms_key.tf_state_key.arn
      sse_algorithm     = "aws:kms"
    }
  }
}

2. Enforcing TLS/SSL Only Bucket Policy

Enforce HTTPS transport in transit by rejecting any HTTP API call (aws:SecureTransport = false):

resource "aws_s3_bucket_policy" "enforce_tls" {
  bucket = aws_s3_bucket.tf_state.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid       = "EnforceTLSRequestsOnly"
        Effect    = "Deny"
        Principal = "*"
        Action    = "s3:*"
        Resource  = [
          aws_s3_bucket.tf_state.arn,
          "${aws_s3_bucket.tf_state.arn}/*"
        ]
        Condition = {
          Bool = {
            "aws:SecureTransport" = "false"
          }
        }
      }
    ]
  })
}

3. Automated CloudTrail Alert Playbook for Bucket Policy Tampering

Monitor PutBucketPolicy or DeleteBucketPublicAccessBlock events using AWS CloudWatch Alarms & EventBridge:

{
  "source": ["aws.s3"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["s3.amazonaws.com"],
    "eventName": [
      "PutBucketPolicy",
      "DeleteBucketPublicAccessBlock",
      "PutBucketAcl"
    ]
  }
}

Summary of Playlist Curriculum

  1. Part 1: IAM Evaluation Logic, Permission Boundaries, and Checkov IaC Scanning.
  2. Part 2: S3 Remote State KMS Hardening, Enforcing SecureTransport (TLS), and Real-time CloudTrail Alerting.

// Discussion

Enjoyed this? Let us work together.

Available for Security Engineering, DevSecOps, and Penetration Testing engagements.