100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
CI/CD, GitOps, DevSecOps & Observability
55 minintermediate

Lab — Config rule that auto-remediates public S3 buckets

What You'll Build

In this lab you will deploy a complete AWS Config auto-remediation pipeline using Terraform. The pipeline detects when an S3 bucket's public access block is removed, automatically triggers an SSM Automation document that re-enables the block, and restores compliance without human intervention. You will verify the pipeline by deliberately making a test bucket public and watching Config detect the violation and SSM Automation remediate it within minutes.

By completing this lab, you will have a production-ready Config rule and SSM Automation document deployed as infrastructure-as-code, tested end-to-end, and ready to protect all india-squad S3 buckets against accidental public exposure. The complete pipeline—detect, remediate, verify—runs automatically within minutes of a misconfiguration occurring, substantially faster than any human monitoring and response process could achieve.

Analogy🏏Cricket
Think of it like cricket: Picture setting up a remote ground management system for a cricket ground in a new city. First, the infrastructure must be installed: the pitch sensors, the scoreboard network, and the broadcast uplink—equivalent to installing ArgoCD on the EKS cluster. Then, the venue configuration must be committed to the central venue management database: the pitch dimensions, the lighting schedule, the boundary positions—equivalent to committing the Kubernetes manifests to the GitOps repository. Then, the venue must be registered with the central management system, which then automatically enforces the declared configuration at the ground—equivalent to creating the ArgoCD Application that connects the repository to the cluster. When a ground manager moves a boundary rope by hand, the sensors detect the drift and alert the management system to restore the declared position—equivalent to ArgoCD detecting and reverting the manual replica scale. This reveals why the lab sequence matters: you cannot verify GitOps until all three components—operator, repository, and Application—are connected and working together.

Prerequisites

  • Terraform >= 1.5 installed locally and configured with AWS credentials that have Config:*, SSM:*, S3:*, and IAM:* permissions.
  • AWS Config not yet enabled in the account, or enabled without a delivery channel—the lab creates its own Config recorder and delivery channel.
  • The AWS account from Exercise 27 with Security Hub enabled, so the Config rule findings appear in the Security Hub dashboard alongside other findings.
  • An S3 bucket available for testing that can be temporarily made public and then restored—the lab creates a dedicated test bucket for this purpose.
  • Familiarity with Terraform apply and output commands from previous infrastructure exercises.

Setup — Project Scaffold and Test Bucket

Create the Terraform project directory, write the provider configuration, and deploy a tagged test S3 bucket. The bucket's `Project: india-squad` tag is what the Config rule will use to scope its evaluation—without this tag, the rule will not evaluate the bucket, allowing you to test the specific bucket that you control without affecting other account buckets.

Analogy🏏Cricket
🏏 Think of it like cricket: When trialling a new safety rule you don't test it on the whole stadium at once — you rope off one clearly marked practice net and apply the rule only there, so you can prove it works without disrupting live play elsewhere. That is exactly why this scaffold deploys a single test S3 bucket tagged Project: india-squad: the Config rule is scoped to that tag, so it evaluates only the bucket you control and leaves every other bucket in the account untouched. Just as the marked-off net lets you deliberately break the rule and watch the response safely, the tagged bucket lets you trigger and observe remediation in isolation. Just as the ground markings and net are the groundwork laid before the drill, the Terraform provider config and project structure are the groundwork laid before the rule. The payoff: scoping the test to one tagged resource makes the whole experiment safe, controlled and repeatable.
bash
# Prerequisites: AWS account with Security Hub enabled from Exercise 27.
# We will deploy Config rule + SSM Automation via Terraform.

mkdir india-squad-config && cd india-squad-config

cat > main.tf << 'EOF'
terraform {
  required_providers {
    aws = { source = 'hashicorp/aws', version = '~> 5.0' }
  }
}

provider 'aws' { region = 'ap-south-1' }

data 'aws_caller_identity' 'current' {}
data 'aws_region' 'current' {}
EOF

# Initialise Terraform
terraform init

# Create a test S3 bucket to verify auto-remediation later
cat > test-bucket.tf << 'EOF'
resource 'aws_s3_bucket' 'india_squad_test' {
  bucket = 'india-squad-config-test-${data.aws_caller_identity.current.account_id}'
  tags = { Project = 'india-squad', Environment = 'test' }
}

# Output the bucket name for use in verification steps
output 'test_bucket_name' {
  value = aws_s3_bucket.india_squad_test.id
}
EOF

terraform apply -auto-approve
export TEST_BUCKET=$(terraform output -raw test_bucket_name)
echo "Test bucket: $TEST_BUCKET"

Step 1 — Deploy the Config Rule

Create the Config recorder, delivery channel, IAM role, and the managed Config rule `S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED`. The Config recorder must be running before the managed rule can evaluate resources. The delivery channel requires an S3 bucket for Config to store its snapshots and history; create a dedicated Config logs bucket separate from the test bucket.

Analogy🏏Cricket
Think of it like cricket: Deploying the Config recorder is like commissioning the ICC's automated ground monitoring system at the venue—installing the sensors, connecting them to the monitoring network, and confirming they are recording. The Config rule is the specific detection criterion—the sensor that monitors boundary rope positions. The delivery channel is the uplink that sends monitoring data to the ICC operations centre. All three components must be operational before the monitoring system provides any value; deploying them in the correct order avoids dependency failures.
bash
# Step 1: Deploy the Config rule using Terraform.

cat > config-rule.tf << 'EOF'
# IAM role for Config to use when evaluating rules
resource 'aws_iam_role' 'config' {
  name = 'india-squad-config-role'
  assume_role_policy = jsonencode({
    Version = '2012-10-17'
    Statement = [{
      Action    = 'sts:AssumeRole'
      Effect    = 'Allow'
      Principal = { Service = 'config.amazonaws.com' }
    }]
  })
}

resource 'aws_iam_role_policy_attachment' 'config_readonly' {
  role       = aws_iam_role.config.name
  policy_arn = 'arn:aws:iam::aws:policy/ReadOnlyAccess'
}

# Config recorder (required for managed rules)
resource 'aws_config_configuration_recorder' 'india_squad' {
  name     = 'india-squad'
  role_arn = aws_iam_role.config.arn
  recording_group { all_supported = true }
}

resource 'aws_config_configuration_recorder_status' 'india_squad' {
  name       = aws_config_configuration_recorder.india_squad.name
  is_enabled = true
  depends_on = [aws_config_delivery_channel.india_squad]
}

# Delivery channel (required for Config to function)
resource 'aws_config_delivery_channel' 'india_squad' {
  name           = 'india-squad'
  s3_bucket_name = aws_s3_bucket.config_logs.id
  depends_on     = [aws_config_configuration_recorder.india_squad]
}

resource 'aws_s3_bucket' 'config_logs' {
  bucket = 'india-squad-config-logs-${data.aws_caller_identity.current.account_id}'
}

# The Config rule: detect S3 buckets without block public access
resource 'aws_config_config_rule' 's3_block_public_access' {
  name       = 'india-squad-s3-block-public-access'
  depends_on = [aws_config_configuration_recorder.india_squad]
  source {
    owner             = 'AWS'
    source_identifier = 'S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED'
  }
}
EOF

terraform apply -auto-approve
# Verify the Config rule was created:
aws configservice describe-config-rules \
  --config-rule-names india-squad-s3-block-public-access \
  --query 'ConfigRules[0].{Name:ConfigRuleName,State:ConfigRuleState}'

Step 2 — Create the SSM Automation Document

Write the SSM Automation document that performs the remediation: a single-step automation that calls the S3 `put_public_access_block` API with all four block settings enabled. Create the IAM role that SSM Automation will assume when executing the document, scoped to the minimum permission needed: `s3:PutBucketPublicAccessBlock` only. This least-privilege role prevents the remediation automation from performing any action beyond its specific purpose.

Analogy🏏Cricket
Think of it like cricket: The SSM Automation document is the standing instruction issued to the ground crew for the specific remediation action: 'when the boundary rope at position X is out of tolerance, reposition it to coordinates Y.' The IAM role with `s3:PutBucketPublicAccessBlock` is the limited access key that authorises the ground crew to perform only the boundary rope repositioning—they cannot access the pitch equipment room or the player dressing rooms. Just as the standing instruction enables the ground crew to act autonomously without waiting for a match referee's explicit authorisation each time, the SSM Automation document enables the remediation to execute without a human decision for each non-compliant bucket.
bash
# Step 2: Create the SSM Automation remediation document.

cat > ssm-remediation.tf << 'EOF'
# IAM role for SSM Automation to use when remediating
resource 'aws_iam_role' 'config_remediation' {
  name = 'india-squad-config-remediation'
  assume_role_policy = jsonencode({
    Version = '2012-10-17'
    Statement = [{
      Action    = 'sts:AssumeRole'
      Effect    = 'Allow'
      Principal = { Service = 'ssm.amazonaws.com' }
    }]
  })
}

resource 'aws_iam_role_policy' 'remediation_s3' {
  role   = aws_iam_role.config_remediation.id
  policy = jsonencode({
    Version = '2012-10-17'
    Statement = [{
      Effect   = 'Allow'
      Action   = 's3:PutBucketPublicAccessBlock'
      Resource = 'arn:aws:s3:::*'
    }]
  })
}

# SSM Automation document that enables S3 Block Public Access
resource 'aws_ssm_document' 'block_s3_public' {
  name          = 'india-squad-BlockS3PublicAccess'
  document_type = 'Automation'
  content = jsonencode({
    schemaVersion = '0.3'
    description   = 'Enable S3 Block Public Access on a non-compliant bucket'
    assumeRole    = '{{ AutomationAssumeRole }}'
    parameters = {
      BucketName           = { type = 'String' }
      AutomationAssumeRole = { type = 'String', default = '' }
    }
    mainSteps = [{
      name   = 'BlockPublicAccess'
      action = 'aws:executeAwsApi'
      inputs = {
        Service = 's3'
        Api     = 'put_public_access_block'
        Bucket  = '{{ BucketName }}'
        PublicAccessBlockConfiguration = {
          BlockPublicAcls       = true
          IgnorePublicAcls      = true
          BlockPublicPolicy     = true
          RestrictPublicBuckets = true
        }
      }
    }]
  })
}
EOF
terraform apply -auto-approve

Step 3 — Link Config Rule to SSM Automation

Add the `aws_config_remediation_configuration` resource that links the Config rule to the SSM document and enables automatic execution. The `RESOURCE_ID` parameter substitution instructs Config to pass the non-compliant bucket name as the `BucketName` parameter to SSM Automation automatically—no manual parameter passing is required. Apply the Terraform configuration to deploy the complete remediation pipeline.

Analogy🏏Cricket
Think of it like cricket: The remediation configuration is the ICC's official directive that connects the detection system to the response protocol: 'when the boundary rope sensor reports an out-of-tolerance condition, immediately activate the ground crew standing instruction for that position.' Without this connection, the sensor detects the violation and reports it, but no automatic response occurs. With the connection, the detection directly triggers the response, closing the detection-to-remediation loop into a single automated workflow.
bash
# Step 3: Link the Config rule to the SSM document for auto-remediation.

cat >> config-rule.tf << 'EOF'

# Link the Config rule to the SSM document for automatic remediation
resource 'aws_config_remediation_configuration' 's3_block_public' {
  config_rule_name = aws_config_config_rule.s3_block_public_access.name
  resource_type    = 'AWS::S3::Bucket'
  target_type      = 'SSM_DOCUMENT'
  target_id        = aws_ssm_document.block_s3_public.name
  automatic        = true
  maximum_automatic_attempts = 5
  retry_attempt_seconds      = 60

  parameter {
    name           = 'BucketName'
    resource_value = 'RESOURCE_ID'  # Config passes the non-compliant bucket name
  }
  parameter {
    name         = 'AutomationAssumeRole'
    static_value = aws_iam_role.config_remediation.arn
  }

  depends_on = [aws_config_config_rule.s3_block_public_access]
}
EOF
terraform apply -auto-approve

Step 4 — Test and Verify

Delete the test bucket's public access block configuration to simulate a misconfiguration, wait for Config to detect the non-compliance, watch SSM Automation execute the remediation, and verify the bucket is back to compliant. The full cycle from misconfiguration to remediation typically takes 3-5 minutes—substantially faster than any human detection and response process.

Analogy🏏Cricket
🏏 Think of it like cricket: To prove an automatic boundary-rope repair system works, you deliberately loosen a rope, then watch: the sensor detects the gap, the ground system dispatches a fix, and the rope is re-secured — all within minutes, long before a human steward would have noticed. That is exactly this test: delete the bucket's public-access-block to simulate a misconfiguration, wait for AWS Config to detect the non-compliance, watch SSM Automation execute the remediation, and verify the bucket is compliant again. Just as the automatic system closes the gap in minutes versus a steward's slow patrol, the full detect-to-remediate cycle runs in 3–5 minutes, far faster than any human detection and response. The payoff: proving the loop self-corrects a real misconfiguration is what shows the guardrail actually protects you, rather than merely reporting on you after the fact.
bash
# Step 4: Trigger the auto-remediation by making the test bucket public.

# Make the test bucket public (removes block public access) — this triggers Config
aws s3api delete-public-access-block \
  --bucket $TEST_BUCKET

# Verify the bucket is now public (block access removed)
aws s3api get-public-access-block --bucket $TEST_BUCKET 2>&1
# Expected: NoSuchPublicAccessBlockConfiguration (the block config was deleted)

# Wait 2-3 minutes for Config to detect the change and trigger SSM Automation
echo 'Waiting for Config to detect non-compliance...'
sleep 180

# Check Config rule evaluation result
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name india-squad-s3-block-public-access \
  --compliance-types NON_COMPLIANT \
  --query 'EvaluationResults[*].{Resource:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,Compliance:ComplianceType}'

# Check SSM Automation execution history
aws ssm list-automation-executions \
  --filters 'Key=DocumentName,Values=india-squad-BlockS3PublicAccess' \
  --query 'AutomationExecutionMetadataList[0].{Status:AutomationExecutionStatus,Start:ExecutionStartTime}'

# Wait for remediation to complete (another 1-2 minutes)
sleep 120

# Verify the bucket has been automatically remediated
aws s3api get-public-access-block --bucket $TEST_BUCKET
# Expected: all four fields true — auto-remediation restored block public access

# Confirm the Config rule now shows COMPLIANT for this bucket
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name india-squad-s3-block-public-access \
  --compliance-types COMPLIANT \
  --query 'EvaluationResults[*].EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId'

Warning: The `automatic: true` setting on the remediation configuration means Config will execute the SSM Automation document without any manual approval for every non-compliant bucket that matches the rule's scope. Before enabling automatic remediation in a production account, verify that none of the in-scope buckets have a legitimate business need for public access—such as a static website hosting bucket. For buckets that must remain public, either exclude them from the rule's scope by removing the Project tag or add a rule exception. Test automatic remediation in a non-production account first before enabling it in production.

Extension Challenge: Extend the lab by adding a second Config rule that detects S3 buckets without server-side encryption enabled and an SSM Automation document that enables SSE-KMS encryption using the india-squad CMK from Lesson 23. Chain the two remediation configurations so that Config automatically enables both block public access and encryption on any newly created S3 bucket, ensuring all india-squad S3 buckets meet the CIS Level 2 encryption standard from the moment they are created.

Lesson 21 of 33
0% complete