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:
- Server-Side Encryption with KMS CMK (
aws:kms). - Versioning (to restore state after accidental deletion or ransomware).
- DynamoDB State Locking (to prevent race conditions during concurrent
terraform apply). - 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
- Part 1: IAM Evaluation Logic, Permission Boundaries, and Checkov IaC Scanning.
- Part 2: S3 Remote State KMS Hardening, Enforcing SecureTransport (TLS), and Real-time CloudTrail Alerting.
// Discussion