End-to-End AWS Config Governance System using Terraform

As I progress in my Terraform learning journey, I’ve moved beyond just creating EC2s and S3 buckets. Today’s learning was about governance — how AWS continuously monitors resources, enforces security rules, and stores compliance evidence automatically.
This blog documents exactly what I built, how the full AWS Config system works together.
This is not theory — it’s a real working setup, written in Terraform.
What Problem Are We Solving?
In a real AWS account:
Developers create resources
Changes happen daily
Mistakes happen (public S3, no encryption, missing MFA)
The problem:
How do we continuously watch the account and verify security rules without humans checking manually?
The answer:
👉 AWS Config
Terraform helps us install and wire this monitoring system once, and AWS Config does the rest.
High-Level Architecture
Before jumping into code, here’s the mental model:
AWS Resources
↓
Configuration Recorder (watches changes)
↓
Config Rules (check compliance)
↓
Delivery Channel
↓
Secure S3 Bucket (stores logs & results)
Now let’s break this down resource by resource.
Part 1: Secure S3 Bucket (Foundation of AWS Config)
AWS Config needs a place to store:
Configuration history
Compliance results
Audit evidence
That place is S3.
S3 Bucket
resource "aws_s3_bucket" "example" {
bucket = "my-governance-test-bucket-${random_string.name.result}"
tags = {
Name = "My bucket"
Environment = "Dev"
}
}
This bucket is not just storage — it’s an audit locker.
Bucket Policy – Who Can Access the Locker?
resource "aws_s3_bucket_policy" "config_bucket_policy" {
bucket = aws_s3_bucket.example.id
This policy does four important things:
Allow AWS Config to check bucket permissions
Action: s3:GetBucketAcl
AWS Config verifies:
“Can I safely store logs here?”
Allow AWS Config to list bucket
Action: s3:ListBucket
Required before writing objects.
Allow AWS Config to PUT objects
Action: s3:PutObject
Condition: bucket-owner-full-control
Ensures:
AWS owns the data
No cross-account ownership issues
Deny non-HTTPS access
"aws:SecureTransport": false
This denies:
HTTP uploads
Insecure traffic
Even admins are blocked.
PART 2: IAM Role – Giving AWS Config an Identity
AWS services cannot act without identity.
So we create an IAM Role.
IAM Role for AWS Config
resource "aws_iam_role" "config_role" {
name = "config-role"
The trust policy says:
Service: config.amazonaws.com
Meaning:
“AWS Config is allowed to assume this role.”
This answers:
WHO is allowed to act?
AWS Managed Policy Attachment
policy_arn = "arn:aws:iam::aws:policy/service-role/AWS_ConfigRole"
This gives AWS Config:
Permission to read AWS resources
Permission to evaluate configurations
Permission to describe services
This is mandatory.
Custom Inline Policy (S3 Access)
resource "aws_iam_role_policy" "config_s3_policy" {
Why this is needed:
Bucket policy controls who can access the bucket
IAM policy controls what AWS Config itself is allowed to do
AWS requires both to allow the action.
This is defense in depth.
PART 3: Configuration Recorder – The Camera
resource "aws_config_configuration_recorder" "foo" {
This tells AWS Config:
Which role to use
Which resources to watch
recording_group {
all_supported = true
include_global_resource_types = true
}
Meaning:
Track everything
Include IAM, root, global resources
Without this:
AWS Config has no idea what to record
PART 4: Delivery Channel – The Pipe
resource "aws_config_delivery_channel" "foo" {
This connects:
Recorder → S3 Bucket
Without delivery channel:
AWS Config records data
But has nowhere to store it
Service fails
PART 5: Recorder Status – Power Button
resource "aws_config_configuration_recorder_status" "foo" {
is_enabled = true
}
This literally:
Turns AWS Config ON
PART 6: Config Rules – The Brain
Rules define:
“What is good?”
“What is bad?”
Encryption Rule
S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
Checks:
Is encryption enabled?
Marks bucket compliant or not
Public Access Rules
S3_BUCKET_PUBLIC_READ_PROHIBITED
S3_BUCKET_PUBLIC_WRITE_PROHIBITED
Detects accidental exposure.
Root MFA Rule
ROOT_ACCOUNT_MFA_ENABLED
Ensures:
- Root account is protected
Required Tags Rule
REQUIRED_TAGS
Enforces:
Resource hygiene
Ownership
Cost tracking
Scoped only to:
AWS::S3::Bucket
PART 7: Checking Compliance in AWS Console (Real-World Validation)
After all Terraform resources are applied, the real power of AWS Config is visible inside the AWS Console.
Now do this 👇
Go to AWS Console
Search for AWS Config
Open Rules or Compliance dashboard
Here, you will clearly see:
Which rules are Compliant
Which rules are Non-Compliant
The exact AWS resource causing the violation
📺 Video That Helped Me Understand this concept:
Final Learning Outcome
This project taught me that:
Terraform + AWS Config = automated governance
I didn’t just deploy infrastructure —
I deployed continuous security enforcement.
This is exactly how real production AWS accounts are managed.



