Skip to main content
AWS Config Architecture

Module Overview

Estimated Time: 2-3 hours | Difficulty: Intermediate | Prerequisites: IAM, basic compliance concepts
AWS Config provides a detailed view of the configuration of AWS resources in your account. It continuously monitors and records configuration changes, and evaluates them against desired configurations using rules. What You’ll Learn:
  • Config recorders and delivery channels
  • Managed and custom rules
  • Conformance packs for compliance
  • Automatic remediation
  • Advanced queries with Config Aggregator

How Config Works

┌─────────────────────────────────────────────────────────────────────────┐
│                        AWS Config Architecture                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   AWS Resources              Configuration                   Outputs    │
│   ─────────────              ─────────────                  ────────    │
│                                                                          │
│   ┌──────────────┐          ┌─────────────────┐     ┌────────────────┐  │
│   │    EC2       │─────────▶│                 │────▶│  S3 Bucket     │  │
│   │  Instances   │          │   Config        │     │ (History)      │  │
│   └──────────────┘          │   Recorder      │     └────────────────┘  │
│                              │                 │                         │
│   ┌──────────────┐          │  Captures:      │     ┌────────────────┐  │
│   │   Security   │─────────▶│  - Current      │────▶│   SNS Topic    │  │
│   │   Groups     │          │    Config       │     │ (Notifications)│  │
│   └──────────────┘          │  - Changes      │     └────────────────┘  │
│                              │  - Relationships│                         │
│   ┌──────────────┐          └────────┬────────┘                         │
│   │  S3 Buckets  │─────────▶         │                                  │
│   └──────────────┘                   │                                  │
│                                       ▼                                  │
│   ┌──────────────┐          ┌─────────────────┐     ┌────────────────┐  │
│   │  IAM Roles   │─────────▶│   Config Rules  │────▶│ Compliance     │  │
│   └──────────────┘          │                 │     │ Dashboard      │  │
│                              │  Evaluates:     │     └────────────────┘  │
│   ┌──────────────┐          │  COMPLIANT      │                         │
│   │    RDS       │─────────▶│  NON_COMPLIANT  │     ┌────────────────┐  │
│   │  Instances   │          │  NOT_APPLICABLE │────▶│ Remediation    │  │
│   └──────────────┘          └─────────────────┘     │ Actions        │  │
│                                                      └────────────────┘  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Enabling AWS Config

Console or CLI

# Create S3 bucket for config snapshots
aws s3 mb s3://my-config-bucket-123456789012

# Create IAM role for Config
aws iam create-role \
  --role-name ConfigRole \
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": {"Service": "config.amazonaws.com"},
      "Action": "sts:AssumeRole"
    }]
  }'

# Attach managed policy
aws iam attach-role-policy \
  --role-name ConfigRole \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWS_ConfigRole

# Create configuration recorder
aws configservice put-configuration-recorder \
  --configuration-recorder name=default,roleARN=arn:aws:iam::123456789012:role/ConfigRole \
  --recording-group allSupported=true,includeGlobalResourceTypes=true

# Create delivery channel
aws configservice put-delivery-channel \
  --delivery-channel name=default,s3BucketName=my-config-bucket-123456789012

# Start recording
aws configservice start-configuration-recorder --configuration-recorder-name default

CloudFormation

AWSTemplateFormatVersion: '2010-09-09'
Description: AWS Config Setup

Resources:
  ConfigBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${AWS::AccountId}-config-logs
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

  ConfigBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref ConfigBucket
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: AWSConfigBucketPermissionsCheck
            Effect: Allow
            Principal:
              Service: config.amazonaws.com
            Action: s3:GetBucketAcl
            Resource: !GetAtt ConfigBucket.Arn
          - Sid: AWSConfigBucketDelivery
            Effect: Allow
            Principal:
              Service: config.amazonaws.com
            Action: s3:PutObject
            Resource: !Sub ${ConfigBucket.Arn}/*
            Condition:
              StringEquals:
                s3:x-amz-acl: bucket-owner-full-control

  ConfigRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: AWSConfigRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: config.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWS_ConfigRole

  ConfigRecorder:
    Type: AWS::Config::ConfigurationRecorder
    Properties:
      Name: default
      RoleARN: !GetAtt ConfigRole.Arn
      RecordingGroup:
        AllSupported: true
        IncludeGlobalResourceTypes: true

  ConfigDeliveryChannel:
    Type: AWS::Config::DeliveryChannel
    DependsOn: ConfigBucketPolicy
    Properties:
      Name: default
      S3BucketName: !Ref ConfigBucket
      ConfigSnapshotDeliveryProperties:
        DeliveryFrequency: Six_Hours

Config Rules

Managed Rules

AWS provides 300+ managed rules:
Common Managed Rules:
  # Security
  - s3-bucket-public-read-prohibited
  - s3-bucket-public-write-prohibited
  - s3-bucket-ssl-requests-only
  - encrypted-volumes
  - rds-storage-encrypted
  - cloudtrail-enabled
  - root-account-mfa-enabled
  
  # IAM
  - iam-user-mfa-enabled
  - iam-password-policy
  - iam-root-access-key-check
  - access-keys-rotated
  
  # Network
  - restricted-ssh
  - vpc-sg-open-only-to-authorized-ports
  - vpc-default-security-group-closed
  
  # Compute
  - ec2-instance-managed-by-ssm
  - ec2-instance-no-public-ip
  - ebs-optimized-instance
  
  # Database
  - rds-multi-az-support
  - db-instance-backup-enabled
  - dynamodb-autoscaling-enabled

Create Managed Rule

Resources:
  S3PublicReadProhibited:
    Type: AWS::Config::ConfigRule
    DependsOn: ConfigRecorder
    Properties:
      ConfigRuleName: s3-bucket-public-read-prohibited
      Description: Checks that S3 buckets do not allow public read access
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED
      MaximumExecutionFrequency: TwentyFour_Hours

  EncryptedVolumes:
    Type: AWS::Config::ConfigRule
    DependsOn: ConfigRecorder
    Properties:
      ConfigRuleName: encrypted-volumes
      Description: Checks whether EBS volumes are encrypted
      Source:
        Owner: AWS
        SourceIdentifier: ENCRYPTED_VOLUMES

  RootAccountMFA:
    Type: AWS::Config::ConfigRule
    DependsOn: ConfigRecorder
    Properties:
      ConfigRuleName: root-account-mfa-enabled
      Description: Checks whether root account has MFA enabled
      Source:
        Owner: AWS
        SourceIdentifier: ROOT_ACCOUNT_MFA_ENABLED
      MaximumExecutionFrequency: TwentyFour_Hours

Custom Rules (Lambda)

# custom_rule.py
import boto3
import json

def lambda_handler(event, context):
    """
    Custom Config Rule: Check if EC2 instances have required tags
    """
    config = boto3.client('config')
    
    # Get configuration item
    invoking_event = json.loads(event['invokingEvent'])
    configuration_item = invoking_event['configurationItem']
    
    # Rule parameters
    rule_parameters = json.loads(event.get('ruleParameters', '{}'))
    required_tags = rule_parameters.get('requiredTags', 'Environment,Owner,CostCenter').split(',')
    
    # Evaluate compliance
    compliance_type = 'COMPLIANT'
    annotation = 'All required tags are present'
    
    if configuration_item['resourceType'] == 'AWS::EC2::Instance':
        tags = {t['key']: t['value'] for t in configuration_item.get('tags', [])}
        
        missing_tags = [tag for tag in required_tags if tag not in tags]
        
        if missing_tags:
            compliance_type = 'NON_COMPLIANT'
            annotation = f'Missing required tags: {", ".join(missing_tags)}'
    
    # Put evaluation
    config.put_evaluations(
        Evaluations=[{
            'ComplianceResourceType': configuration_item['resourceType'],
            'ComplianceResourceId': configuration_item['resourceId'],
            'ComplianceType': compliance_type,
            'Annotation': annotation,
            'OrderingTimestamp': configuration_item['configurationItemCaptureTime']
        }],
        ResultToken=event['resultToken']
    )
    
    return {
        'compliance_type': compliance_type,
        'annotation': annotation
    }
# CloudFormation for custom rule
Resources:
  CustomRuleLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: config-required-tags-rule
      Runtime: python3.11
      Handler: index.lambda_handler
      Role: !GetAtt CustomRuleLambdaRole.Arn
      Code:
        ZipFile: |
          # Lambda code here

  CustomRuleLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/service-role/AWSConfigRulesExecutionRole

  LambdaConfigPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref CustomRuleLambda
      Action: lambda:InvokeFunction
      Principal: config.amazonaws.com

  RequiredTagsRule:
    Type: AWS::Config::ConfigRule
    DependsOn: ConfigRecorder
    Properties:
      ConfigRuleName: required-tags-rule
      Description: Checks that EC2 instances have required tags
      InputParameters:
        requiredTags: "Environment,Owner,CostCenter"
      Scope:
        ComplianceResourceTypes:
          - AWS::EC2::Instance
      Source:
        Owner: CUSTOM_LAMBDA
        SourceIdentifier: !GetAtt CustomRuleLambda.Arn
        SourceDetails:
          - EventSource: aws.config
            MessageType: ConfigurationItemChangeNotification

Conformance Packs

Deploy Conformance Pack

# conformance-pack-security.yaml
ConformancePackName: SecurityBestPractices
Description: Security baseline conformance pack

Resources:
  # S3 Security
  S3BucketPublicReadProhibited:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: s3-bucket-public-read-prohibited
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED

  S3BucketSSLRequestsOnly:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: s3-bucket-ssl-requests-only
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_SSL_REQUESTS_ONLY

  # Encryption
  EncryptedVolumes:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: encrypted-volumes
      Source:
        Owner: AWS
        SourceIdentifier: ENCRYPTED_VOLUMES

  RDSStorageEncrypted:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: rds-storage-encrypted
      Source:
        Owner: AWS
        SourceIdentifier: RDS_STORAGE_ENCRYPTED

  # IAM
  IAMUserMFAEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: iam-user-mfa-enabled
      Source:
        Owner: AWS
        SourceIdentifier: IAM_USER_MFA_ENABLED

  RootAccountMFAEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: root-account-mfa-enabled
      Source:
        Owner: AWS
        SourceIdentifier: ROOT_ACCOUNT_MFA_ENABLED

  # Logging
  CloudTrailEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: cloudtrail-enabled
      Source:
        Owner: AWS
        SourceIdentifier: CLOUD_TRAIL_ENABLED
# Deploy conformance pack
aws configservice put-conformance-pack \
  --conformance-pack-name SecurityBestPractices \
  --template-body file://conformance-pack-security.yaml

# Get conformance pack status
aws configservice describe-conformance-pack-status \
  --conformance-pack-names SecurityBestPractices

# Get compliance summary
aws configservice get-conformance-pack-compliance-summary \
  --conformance-pack-names SecurityBestPractices

AWS Sample Conformance Packs

Available Sample Packs:
  # Regulatory
  - Operational-Best-Practices-for-PCI-DSS
  - Operational-Best-Practices-for-HIPAA
  - Operational-Best-Practices-for-NIST-CSF
  - Operational-Best-Practices-for-CIS-Critical-Security-Controls
  - Operational-Best-Practices-for-SOC2
  
  # Security
  - Operational-Best-Practices-for-Security-Services
  - Operational-Best-Practices-for-Encryption-and-Keys
  - Operational-Best-Practices-for-Logging
  
  # AWS Services
  - Operational-Best-Practices-for-Amazon-S3
  - Operational-Best-Practices-for-Amazon-DynamoDB
  - Operational-Best-Practices-for-AWS-Lambda

Automatic Remediation

Remediation with SSM

Resources:
  # Rule to check if EBS volumes are encrypted
  EncryptedVolumesRule:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: encrypted-volumes
      Source:
        Owner: AWS
        SourceIdentifier: ENCRYPTED_VOLUMES

  # Remediation action
  EncryptedVolumesRemediation:
    Type: AWS::Config::RemediationConfiguration
    Properties:
      ConfigRuleName: encrypted-volumes
      TargetId: AWS-DisablePublicAccessForSecurityGroup  # SSM Document
      TargetType: SSM_DOCUMENT
      Automatic: true
      MaximumAutomaticAttempts: 5
      RetryAttemptSeconds: 60
      Parameters:
        AutomationAssumeRole:
          StaticValue:
            Values:
              - !GetAtt RemediationRole.Arn

  # S3 public access remediation
  S3PublicAccessRemediationRule:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: s3-bucket-public-read-prohibited
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED

  S3PublicAccessRemediation:
    Type: AWS::Config::RemediationConfiguration
    Properties:
      ConfigRuleName: s3-bucket-public-read-prohibited
      TargetId: AWS-DisableS3BucketPublicReadWrite
      TargetType: SSM_DOCUMENT
      Automatic: true
      MaximumAutomaticAttempts: 3
      RetryAttemptSeconds: 60
      Parameters:
        S3BucketName:
          ResourceValue:
            Value: RESOURCE_ID
        AutomationAssumeRole:
          StaticValue:
            Values:
              - !GetAtt RemediationRole.Arn

Custom Remediation Lambda

# remediation.py
import boto3

def lambda_handler(event, context):
    """
    Custom remediation: Add required tags to EC2 instances
    """
    ec2 = boto3.client('ec2')
    
    resource_id = event['ResourceId']  # i-1234567890abcdef0
    
    # Add default tags
    ec2.create_tags(
        Resources=[resource_id],
        Tags=[
            {'Key': 'Environment', 'Value': 'Unknown'},
            {'Key': 'Owner', 'Value': 'Unassigned'},
            {'Key': 'CostCenter', 'Value': 'Remediated'}
        ]
    )
    
    return {
        'statusCode': 200,
        'message': f'Added default tags to {resource_id}'
    }

Config Aggregator

Multi-Account Aggregation

┌─────────────────────────────────────────────────────────────────────────┐
│                    Config Aggregator Architecture                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                    Central Security Account                       │   │
│   │                       (Aggregator)                                │   │
│   │                                                                   │   │
│   │   ┌───────────────────────────────────────────────────────────┐ │   │
│   │   │           Aggregated Compliance View                       │ │   │
│   │   │   ─ All accounts, all regions                             │ │   │
│   │   │   ─ Cross-account compliance queries                      │ │   │
│   │   │   ─ Centralized dashboards                                │ │   │
│   │   └───────────────────────────────────────────────────────────┘ │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                  ▲                                       │
│                    ┌─────────────┼─────────────┐                        │
│                    │             │             │                         │
│              ┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐                 │
│              │  Account  │ │  Account  │ │  Account  │                 │
│              │    Dev    │ │  Staging  │ │   Prod    │                 │
│              │           │ │           │ │           │                 │
│              │ Config +  │ │ Config +  │ │ Config +  │                 │
│              │ Rules     │ │ Rules     │ │ Rules     │                 │
│              └───────────┘ └───────────┘ └───────────┘                 │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Create Aggregator

# Create organization aggregator
aws configservice put-configuration-aggregator \
  --configuration-aggregator-name org-aggregator \
  --organization-aggregation-source '{
    "RoleArn": "arn:aws:iam::123456789012:role/ConfigAggregatorRole",
    "AwsRegions": ["us-east-1", "us-west-2", "eu-west-1"],
    "AllAwsRegions": false
  }'

# Or create account-based aggregator
aws configservice put-configuration-aggregator \
  --configuration-aggregator-name account-aggregator \
  --account-aggregation-sources '[{
    "AccountIds": ["111111111111", "222222222222"],
    "AllAwsRegions": true
  }]'

Advanced Queries

-- Find all non-compliant resources across accounts
SELECT
    accountId,
    awsRegion,
    resourceType,
    resourceId,
    configuration.complianceType
WHERE
    resourceType = 'AWS::Config::ResourceCompliance'
    AND configuration.complianceType = 'NON_COMPLIANT'

-- Find all public S3 buckets
SELECT
    accountId,
    resourceId,
    resourceName
WHERE
    resourceType = 'AWS::S3::Bucket'
    AND configuration.publicAccessBlockConfiguration.blockPublicAcls = false

-- Find EC2 instances without required tags
SELECT
    accountId,
    resourceId,
    tags
WHERE
    resourceType = 'AWS::EC2::Instance'
    AND tags.key != 'Environment'

-- Find unencrypted EBS volumes
SELECT
    accountId,
    awsRegion,
    resourceId
WHERE
    resourceType = 'AWS::EC2::Volume'
    AND configuration.encrypted = false

-- Resource count by type
SELECT
    resourceType,
    COUNT(resourceId) as resourceCount
GROUP BY
    resourceType
ORDER BY
    resourceCount DESC

Configuration Timeline

# Get configuration history for a resource
aws configservice get-resource-config-history \
  --resource-type AWS::EC2::SecurityGroup \
  --resource-id sg-0123456789abcdef0 \
  --limit 10

# Get relationship between resources
aws configservice get-aggregate-resource-config \
  --configuration-aggregator-name org-aggregator \
  --resource-identifier '{
    "SourceAccountId": "123456789012",
    "SourceRegion": "us-east-1",
    "ResourceId": "sg-0123456789abcdef0",
    "ResourceType": "AWS::EC2::SecurityGroup"
  }'

Best Practices

Enable All Resources

Record all resource types for complete visibility

Use Conformance Packs

Deploy rules as conformance packs for consistency

Automate Remediation

Use SSM automation for automatic fixes

Centralize with Aggregator

Use Config Aggregator for multi-account visibility

🎯 Interview Questions

CloudTrail = Who did what, when
  • Records API calls
  • Answers: “Who deleted the S3 bucket?”
  • Focus: API activity auditing
AWS Config = What is the configuration
  • Records resource configurations
  • Answers: “Is this S3 bucket public?”
  • Focus: Configuration compliance
They complement each other: CloudTrail shows who made changes, Config shows what the changes were.
  1. Enable Config in all accounts and regions
  2. Deploy conformance packs via Organizations
  3. Create aggregator for centralized view
  4. Set up notifications for non-compliant resources
  5. Automate remediation with SSM documents
  6. Track trends with compliance dashboards
Options:
  1. Scope rules: Limit to specific resource types or tags
  2. Suppression: Use resource exceptions in rule
  3. Custom rules: Write Lambda for nuanced evaluation
  4. Tags: Exclude resources with specific tags
  5. Document: Maintain exception registry

Hands-On Lab

1

Enable AWS Config

Set up Config recorder with S3 delivery channel
2

Deploy Managed Rules

Enable 5 common security rules
3

Create Custom Rule

Write Lambda-based rule for required tags
4

Set Up Remediation

Configure automatic remediation for S3 public access
5

Create Aggregator

Set up cross-account aggregator and run queries

Next Module

AWS Inspector

Automated vulnerability scanning for EC2, Lambda, and containers