DEV Community

Cover image for Part 2: AWS Config Conformance Packs(Hands-On Guide)
Tandap Noel Bansikah
Tandap Noel Bansikah

Posted on • Edited on

Part 2: AWS Config Conformance Packs(Hands-On Guide)

In Part 1, we explored the theory behind AWS Config and Conformance Packs — their purpose, benefits, and how they fit into your cloud governance strategy. In this second part, we'll get our hands dirty and walk through the process of enabling AWS Config and deploying a sample Conformance Pack using Terraform. Let’s automate your compliance the DevOps way!


Prerequisites

  • AWS account with permissions for AWS Config, S3
  • Terraform installed (Get started)
  • AWS CLI installed and configured (aws configure)

Step 1: Prepare Your Terraform Project

mkdir learn-terraform-conformance-packs
cd learn-terraform-conformance-packs
touch main.tf
Enter fullscreen mode Exit fullscreen mode

Step 2: Terraform Configuration

Option 1: Enable AWS Config and Deploy Conformance Pack

Paste the following into your main.tf if you have not enabled AWS Config yet:

# Configure the AWS provider
provider "aws" {
  region = "us-east-1"
}

# Toggle for enabling AES256 encryption on the S3 bucket
variable "encryption_enabled" {
  type        = bool
  default     = true
  description = "Enable AES256 encryption by default"
}

# Get current AWS region, account ID, and partition information
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
data "aws_partition" "current" {}

# IAM role for AWS Config service to assume
resource "aws_iam_role" "config_role" {
  name = "awsconfig-example"

  assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": { "Service": "config.amazonaws.com" },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
POLICY
}

# Inline policy providing AWS Config permissions to record and deliver configuration data
resource "aws_iam_role_policy" "config_inline_policy" {
  name = "awsconfig-inline-policy"
  role = aws_iam_role.config_role.id

  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Action = [
          "config:Put*",
          "config:Get*",
          "config:Describe*",
          "s3:PutObject",
          "s3:GetBucketAcl",
          "sns:Publish",
          "iam:GetRole",
          "iam:PassRole"
        ],
        Resource = "*"
      }
    ]
  })
}

# Attach AWS-managed ReadOnlyAccess policy to allow read access across AWS resources
resource "aws_iam_role_policy_attachment" "read_only_policy_attach" {
  role       = aws_iam_role.config_role.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

# Create an S3 bucket to store AWS Config logs
resource "aws_s3_bucket" "new_config_bucket" {
  bucket        = "config-bucket-${data.aws_caller_identity.current.account_id}-${data.aws_region.current.name}"
  force_destroy = true
}

# Enable AES256 server-side encryption on the S3 bucket
resource "aws_s3_bucket_server_side_encryption_configuration" "default" {
  bucket = aws_s3_bucket.new_config_bucket.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

# S3 bucket policy granting AWS Config permission to write logs and enforcing SSL
resource "aws_s3_bucket_policy" "config_logging_policy" {
  bucket = aws_s3_bucket.new_config_bucket.id
  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowBucketAcl",
      "Effect": "Allow",
      "Principal": { "Service": ["config.amazonaws.com"] },
      "Action": "s3:GetBucketAcl",
      "Resource": "${aws_s3_bucket.new_config_bucket.arn}",
      "Condition": { "Bool": { "aws:SecureTransport": "true" } }
    },
    {
      "Sid": "AllowConfigWriteAccess",
      "Effect": "Allow",
      "Principal": { "Service": ["config.amazonaws.com"] },
      "Action": "s3:PutObject",
      "Resource": "${aws_s3_bucket.new_config_bucket.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*",
      "Condition": {
        "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control" },
        "Bool": { "aws:SecureTransport": "true" }
      }
    },
    {
      "Sid": "RequireSSL",
      "Effect": "Deny",
      "Principal": { "AWS": "*" },
      "Action": "s3:*",
      "Resource": "${aws_s3_bucket.new_config_bucket.arn}/*",
      "Condition": { "Bool": { "aws:SecureTransport": "false" } }
    }
  ]
}
POLICY
}

# Configuration recorder for AWS Config that tracks changes to supported resources
resource "aws_config_configuration_recorder" "config_recorder" {
  name     = "config_recorder"
  role_arn = aws_iam_role.config_role.arn

  recording_group {
    all_supported                  = true
    include_global_resource_types = true
  }
}

# Delivery channel for AWS Config to store configuration snapshots in the S3 bucket
resource "aws_config_delivery_channel" "config_channel" {
  s3_bucket_name = aws_s3_bucket.new_config_bucket.id
  depends_on     = [aws_config_configuration_recorder.config_recorder]
}

# Enable the configuration recorder
resource "aws_config_configuration_recorder_status" "config_recorder_status" {
  name       = aws_config_configuration_recorder.config_recorder.name
  is_enabled = true
  depends_on = [aws_config_delivery_channel.config_channel]
}

# Deploy AWS Config Conformance Pack to enforce best practices for S3 buckets
resource "aws_config_conformance_pack" "s3conformancepack" {
  name = "s3conformancepack"

  template_body = <<EOT
Resources:
  S3BucketPublicReadProhibited:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketPublicReadProhibited
      Description: Checks that your Amazon S3 buckets do not allow public read access.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED
      MaximumExecutionFrequency: Six_Hours
  S3BucketPublicWriteProhibited:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketPublicWriteProhibited
      Description: Checks that your Amazon S3 buckets do not allow public write access.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_WRITE_PROHIBITED
      MaximumExecutionFrequency: Six_Hours
  S3BucketReplicationEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketReplicationEnabled
      Description: Checks whether the Amazon S3 buckets have cross-region replication enabled.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_REPLICATION_ENABLED
  S3BucketSSLRequestsOnly:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketSSLRequestsOnly
      Description: Checks whether S3 buckets have policies that require requests to use Secure Socket Layer (SSL).
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_SSL_REQUESTS_ONLY
  ServerSideEncryptionEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: ServerSideEncryptionEnabled
      Description: Checks that your Amazon S3 bucket either has S3 default encryption enabled or that the S3 bucket policy explicitly denies put-object requests without server side encryption.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
  S3BucketLoggingEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketLoggingEnabled
      Description: Checks whether logging is enabled for your S3 buckets.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_LOGGING_ENABLED
EOT

  depends_on = [aws_config_configuration_recorder.config_recorder]
}

Enter fullscreen mode Exit fullscreen mode

As a good practice for terraform, you can always create a variables.tf and output.tf to make your work cleaner and also you can create a conformance_pack_template.yaml where you will put the yaml code inside and you can use it in your main.tf like this

provider "aws" {
  region = "us-east-1"
}

resource "aws_config_conformance_pack" "TagCompliancePack" {
  name = "TagCompliancePack"

  template_body = templatefile("${path.module}/conformance_pack_template.yaml", {
    RequiredTagKeys = "Owner,Project,Environment"
  })
}
Enter fullscreen mode Exit fullscreen mode

Which is just an example, not what we have deployed


Option 2: Only Deploy Conformance Pack (If AWS Config is Already Enabled)

If you already have AWS Config enabled, you can use a minimal main.tf like this:

provider "aws" {
  region = "us-east-1"
}

resource "aws_config_conformance_pack" "s3conformancepack" {
  name = "s3conformancepack"
  template_body = <<EOT
Resources:
  S3BucketPublicReadProhibited:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketPublicReadProhibited
      Description: Checks that your Amazon S3 buckets do not allow public read access.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED
      MaximumExecutionFrequency: Six_Hours
  S3BucketPublicWriteProhibited:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketPublicWriteProhibited
      Description: Checks that your Amazon S3 buckets do not allow public write access.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_WRITE_PROHIBITED
      MaximumExecutionFrequency: Six_Hours
  S3BucketReplicationEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketReplicationEnabled
      Description: Checks whether the Amazon S3 buckets have cross-region replication enabled.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_REPLICATION_ENABLED
  S3BucketSSLRequestsOnly:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketSSLRequestsOnly
      Description: Checks whether S3 buckets have policies that require requests to use Secure Socket Layer (SSL).
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_SSL_REQUESTS_ONLY
  ServerSideEncryptionEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: ServerSideEncryptionEnabled
      Description: Checks that your Amazon S3 bucket either has S3 default encryption enabled or that the S3 bucket policy explicitly denies put-object requests without server side encryption.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
  S3BucketLoggingEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: S3BucketLoggingEnabled
      Description: Checks whether logging is enabled for your S3 buckets.
      Scope:
        ComplianceResourceTypes:
        - "AWS::S3::Bucket"
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_LOGGING_ENABLED
EOT
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Initialize, Format, Validate, and Apply

terraform init
terraform fmt
terraform validate
terraform apply
Enter fullscreen mode Exit fullscreen mode
  • Enter your AWS region (e.g., us-east-1) when prompted.
  • Type yes to confirm and apply the changes.

Step 4: Verify Deployment

  • Go to the AWS Console → AWS Config → Conformance Packs
  • You should see s3conformancepack deployed and active.

s3conformancepack


Step 5: Clean Up

To remove all resources:

terraform destroy
Enter fullscreen mode Exit fullscreen mode

Type yes when prompted to confirm destruction.
If you have some issues with the code you can check the github repository here AWS conformance pack example


Congratulations! You have automated AWS Config and Conformance Pack deployment using Terraform. This approach helps you enforce best practices and compliance at scale in your AWS environment.
Please reach out if you have any questions or recommendations

Connect with me


References

Top comments (0)