Skip to content

Config

Chapter 44: AWS Config & Resource Compliance

Section titled “Chapter 44: AWS Config & Resource Compliance”

Resource Configuration Management and Compliance

Section titled “Resource Configuration Management and Compliance”

AWS Config is a fully managed service that provides AWS resource inventory, configuration history, and configuration change notifications to enable security and governance.

AWS Config Overview
+------------------------------------------------------------------+
| |
| +------------------------+ |
| | AWS Config | |
| +------------------------+ |
| | |
| +---------------------+---------------------+ |
| | | | | |
| v v v v |
| +----------+ +----------+ +----------+ +----------+ |
| | Resource | | Config | | Rules | | Compliance| |
| | Inventory| | History | | | | | |
| | | | | | | | | |
| | - Track | | - Changes| | - Custom | | - Audit | |
| | - Record | | - Timeline| | - Managed| | - Report | |
| | - Query | | - Version | | - Lambda | | - Remediate| |
| +----------+ +----------+ +----------+ +----------+ |
| |
+------------------------------------------------------------------+
FeatureDescription
Resource InventoryTrack all AWS resources
Configuration HistoryRecord changes over time
Config RulesEvaluate resource compliance
Compliance DashboardVisual compliance reporting

AWS Config Architecture
+------------------------------------------------------------------+
| |
| AWS Account |
| +----------------------------------------------------------+ |
| | | |
| | +----------+ +----------+ +----------+ +----------+ | |
| | | EC2 | | S3 | | RDS | | IAM | | |
| | | Resources| | Buckets | | Databases| | Roles | | |
| | +----+-----+ +----+-----+ +----+-----+ +----+-----+ | |
| | | | | | | |
| +-------+------------+------------+------------+------------+ |
| | |
| v |
| +----------------------------------------------------------+ |
| | AWS Config Service | |
| | +------------------------------------------------------+ | |
| | | Configuration Recorder | | |
| | | - Records resource changes | | |
| | | - Stores in S3 bucket | | |
| | +------------------------------------------------------+ | |
| | +------------------------------------------------------+ | |
| | | Config Rules | | |
| | | - Evaluate compliance | | |
| | | - Trigger on changes | | |
| | +------------------------------------------------------+ | |
| | +------------------------------------------------------+ | |
| | | Delivery Channel | | |
| | | - SNS notifications | | |
| | | - S3 delivery | | |
| | +------------------------------------------------------+ | |
| +----------------------------------------------------------+ |
| | |
| v |
| +----------------------------------------------------------+ |
| | S3 Bucket | |
| | - Configuration snapshots | |
| | - Configuration history | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Configuration Recording
+------------------------------------------------------------------+
| |
| Recording Process |
| +----------------------------------------------------------+ |
| | | |
| | 1. Resource Created/Changed | |
| | +-------------------------------------------------+ | |
| | | EC2 instance launched | | |
| | +-------------------------------------------------+ | |
| | | | |
| | v | |
| | 2. Config Service Detects Change | |
| | +-------------------------------------------------+ | |
| | | API call recorded via CloudTrail | | |
| | +-------------------------------------------------+ | |
| | | | |
| | v | |
| | 3. Configuration Item Created | |
| | +-------------------------------------------------+ | |
| | | Resource details captured | | |
| | +-------------------------------------------------+ | |
| | | | |
| | v | |
| | 4. Configuration History Updated | |
| | +-------------------------------------------------+ | |
| | | Change stored in S3 | | |
| | +-------------------------------------------------+ | |
| | | | |
| | v | |
| | 5. Rules Evaluated | |
| | +-------------------------------------------------+ | |
| | | Compliance status updated | | |
| | +-------------------------------------------------+ | |
| | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Terminal window
# Using AWS CLI
aws configservice put-configuration-recorder \
--configuration-recorder name=default,roleARN=arn:aws:iam::123456789012:role/ConfigRole
aws configservice put-delivery-channel \
--delivery-channel name=default,s3BucketName=config-bucket,snsTopicARN=arn:aws:sns:us-east-1:123456789012:config-topic
aws configservice start-configuration-recorder \
--configuration-recorder-name default
{
"name": "default",
"roleARN": "arn:aws:iam::123456789012:role/ConfigRole",
"recordingGroup": {
"allSupported": true,
"includeGlobalResourceTypes": true,
"resourceTypes": [
"AWS::EC2::Instance",
"AWS::EC2::SecurityGroup",
"AWS::S3::Bucket",
"AWS::IAM::Role"
]
}
}
{
"name": "default",
"s3BucketName": "config-bucket",
"s3KeyPrefix": "config/",
"snsTopicARN": "arn:aws:sns:us-east-1:123456789012:config-topic",
"configSnapshotDeliveryProperties": {
"deliveryFrequency": "Twelve_Hours"
}
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "config.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutDeliveryChannel",
"s3:PutConfigurationRecorder",
"s3:GetBucketAcl",
"s3:ListBucket"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"sns:Publish"
],
"Resource": "arn:aws:sns:*:*:config-topic"
}
]
}

AWS Config Managed Rules
+------------------------------------------------------------------+
| |
| Security Rules |
| +------------------+ +------------------+ +------------------+ |
| | root-account-mfa | | iam-mfa-policy | | access-keys-rotated| |
| | | | | | | |
| | Checks MFA on | | Checks MFA for | | Checks key | |
| | root account | | IAM users | | rotation | |
| +------------------+ +------------------+ +------------------+ |
| |
| Encryption Rules |
| +------------------+ +------------------+ +------------------+ |
| | s3-bucket-server| | rds-storage- | | ebs-encryption- | |
| | -side-encryption| | encrypted | | by-default | |
| | | | | | | |
| | Checks S3 | | Checks RDS | | Checks EBS | |
| | encryption | | encryption | | encryption | |
| +------------------+ +------------------+ +------------------+ |
| |
| Network Rules |
| +------------------+ +------------------+ +------------------+ |
| | vpc-sg-open-only| | restricted-ssh | | no-ingress-sg | |
| | -to-restricted-ports| | | | |
| | | | Checks SSH | | Checks no | |
| | Checks port | | restrictions | | public ingress | |
| | restrictions | | | | | |
| +------------------+ +------------------+ +------------------+ |
| |
+------------------------------------------------------------------+
Terminal window
# Enable managed rule
aws configservice put-config-rule \
--config-rule '{
"ConfigRuleName": "s3-bucket-server-side-encryption-enabled",
"Description": "Checks that S3 buckets have server-side encryption enabled",
"Scope": {
"ComplianceResourceTypes": ["AWS::S3::Bucket"]
},
"Source": {
"Owner": "AWS",
"SourceIdentifier": "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"
}
}'
# Enable managed rule with parameters
aws configservice put-config-rule \
--config-rule '{
"ConfigRuleName": "required-tags",
"Description": "Checks for required tags on resources",
"Scope": {
"ComplianceResourceTypes": [
"AWS::EC2::Instance",
"AWS::S3::Bucket"
]
},
"InputParameters": "{\"tag1Key\":\"Environment\",\"tag2Key\":\"Owner\"}",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "REQUIRED_TAGS"
}
}'
# List of commonly used managed rules
Security:
- root-account-mfa-required
- iam-user-mfa-enabled
- access-keys-rotated
- iam-password-policy
- multi-region-cloudtrail-enabled
Encryption:
- s3-bucket-server-side-encryption-enabled
- s3-bucket-default-lock-enabled
- rds-storage-encrypted
- ebs-volume-in-backup-plan
- cloudtrail-s3-dataevents-enabled
Network:
- vpc-default-security-group-closed
- restricted-ssh
- vpc-sg-open-only-to-restricted-ports
- no-ingress-sg-rules
- internet-gateway-authorized-vpc-only
Tagging:
- required-tags
- allowed-resource-tags
- ec2-instance-profile-attached

lambda_function.py
import json
import boto3
from datetime import datetime
def lambda_handler(event, context):
"""
Custom Config Rule: Check EC2 instance type compliance
"""
config = boto3.client('config')
# Parse invoking event
invoking_event = json.loads(event['invokingEvent'])
rule_parameters = json.loads(event.get('ruleParameters', '{}'))
# Get allowed instance types from parameters
allowed_types = rule_parameters.get('allowedInstanceTypes', ['t3.micro', 't3.small'])
# Get configuration item
configuration_item = invoking_event.get('configurationItem', {})
resource_type = configuration_item.get('resourceType')
# Only evaluate EC2 instances
if resource_type != 'AWS::EC2::Instance':
return build_evaluation(
configuration_item,
'NOT_APPLICABLE',
'Rule only applies to EC2 instances'
)
# Get instance type
instance_type = configuration_item.get('configuration', {}).get('instanceType')
# Evaluate compliance
if instance_type in allowed_types:
compliance_type = 'COMPLIANT'
annotation = f'Instance type {instance_type} is allowed'
else:
compliance_type = 'NON_COMPLIANT'
annotation = f'Instance type {instance_type} is not in allowed list: {allowed_types}'
return build_evaluation(configuration_item, compliance_type, annotation)
def build_evaluation(configuration_item, compliance_type, annotation):
"""Build evaluation result"""
return {
'evaluations': [
{
'complianceResourceType': configuration_item.get('resourceType'),
'complianceResourceId': configuration_item.get('resourceId'),
'complianceType': compliance_type,
'annotation': annotation,
'orderingTimestamp': datetime.now().isoformat()
}
]
}
Terminal window
# Create Lambda function
aws lambda create-function \
--function-name ConfigRule-InstanceTypeCheck \
--runtime python3.9 \
--role arn:aws:iam::123456789012:role/ConfigLambdaRole \
--handler lambda_function.lambda_handler \
--zip-file fileb://function.zip
# Create Config rule using Lambda
aws configservice put-config-rule \
--config-rule '{
"ConfigRuleName": "custom-instance-type-check",
"Description": "Checks that EC2 instances use allowed types",
"Scope": {
"ComplianceResourceTypes": ["AWS::EC2::Instance"]
},
"InputParameters": "{\"allowedInstanceTypes\":[\"t3.micro\",\"t3.small\",\"t3.medium\"]}",
"Source": {
"Owner": "CUSTOM_LAMBDA",
"SourceIdentifier": "arn:aws:lambda:us-east-1:123456789012:function:ConfigRule-InstanceTypeCheck",
"SourceDetails": [
{
"EventSource": "aws.config",
"MessageType": "ConfigurationItemChangeNotification"
},
{
"EventSource": "aws.config",
"MessageType": "ScheduledNotification"
}
]
}
}'
periodic_rule.py
import json
import boto3
from datetime import datetime
def lambda_handler(event, context):
"""
Periodic Config Rule: Check for unencrypted EBS volumes
"""
ec2 = boto3.client('ec2')
config = boto3.client('config')
# Get all EBS volumes
result_token = None
non_compliant_resources = []
while True:
if result_token:
response = ec2.describe_volumes(NextToken=result_token)
else:
response = ec2.describe_volumes()
for volume in response['Volumes']:
if not volume['Encrypted']:
non_compliant_resources.append({
'resourceId': volume['VolumeId'],
'resourceType': 'AWS::EC2::Volume'
})
result_token = response.get('NextToken')
if not result_token:
break
# Build evaluations
evaluations = []
for resource in non_compliant_resources:
evaluations.append({
'complianceResourceType': resource['resourceType'],
'complianceResourceId': resource['resourceId'],
'complianceType': 'NON_COMPLIANT',
'annotation': 'EBS volume is not encrypted',
'orderingTimestamp': datetime.now().isoformat()
})
# If no non-compliant resources, mark as compliant
if not evaluations:
evaluations.append({
'complianceResourceType': 'AWS::EC2::Volume',
'complianceResourceId': 'ALL',
'complianceType': 'COMPLIANT',
'annotation': 'All EBS volumes are encrypted',
'orderingTimestamp': datetime.now().isoformat()
})
# Send evaluations to Config
config.put_evaluations(
Evaluations=evaluations,
ResultToken=event['resultToken']
)
return {
'statusCode': 200,
'body': json.dumps({
'nonCompliantCount': len(non_compliant_resources)
})
}

AWS Config Remediation
+------------------------------------------------------------------+
| |
| Remediation Workflow |
| +----------------------------------------------------------+ |
| | | |
| | 1. Non-Compliant Resource Detected | |
| | +-------------------------------------------------+ | |
| | | Config rule evaluates resource | | |
| | +-------------------------------------------------+ | |
| | | | |
| | v | |
| | 2. Remediation Triggered | |
| | +-------------------------------------------------+ | |
| | | SSM Automation document executed | | |
| | +-------------------------------------------------+ | |
| | | | |
| | v | |
| | 3. Remediation Action | |
| | +-------------------------------------------------+ | |
| | | Resource modified to compliant state | | |
| | +-------------------------------------------------+ | |
| | | | |
| | v | |
| | 4. Re-evaluation | |
| | +-------------------------------------------------+ | |
| | | Config rule re-evaluates resource | | |
| | +-------------------------------------------------+ | |
| | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Terminal window
# Create remediation configuration
aws configservice put-remediation-configurations \
--remediation-configurations '[
{
"ConfigRuleName": "s3-bucket-server-side-encryption-enabled",
"TargetId": "AWS-EnableS3BucketEncryption",
"TargetType": "SSM_DOCUMENT",
"TargetVersion": "1",
"Parameters": {
"BucketName": {
"ResourceValue": {
"Value": "RESOURCE_ID"
}
},
"SSEType": {
"StaticValue": {
"Values": ["AES256"]
}
}
},
"Automatic": true,
"ExecutionControls": {
"SsmControls": {
"ConcurrentExecutionRatePercentage": 10,
"ErrorPercentage": 5
}
},
"RetryAttemptSeconds": 60,
"MaximumAutomaticAttempts": 3
}
]'
AWS-EnableS3BucketEncryption.yaml
schemaVersion: '0.3'
description: Enable S3 bucket encryption
parameters:
BucketName:
type: String
description: S3 bucket name
SSEType:
type: String
description: Server-side encryption type
allowedValues:
- AES256
- aws:kms
default: AES256
mainSteps:
- name: EnableEncryption
action: 'aws:executeAwsApi'
inputs:
Service: s3
Api: PutBucketEncryption
BucketName: '{{ BucketName }}'
ServerSideEncryptionConfiguration:
Rules:
- ApplyServerSideEncryptionByDefault:
SSEAlgorithm: '{{ SSEType }}'
outputs:
- Name: Response
Selector: '$'
Type: StringMap
- name: VerifyEncryption
action: 'aws:executeAwsApi'
inputs:
Service: s3
Api: GetBucketEncryption
BucketName: '{{ BucketName }}'
outputs:
- Name: EncryptionStatus
Selector: '$.ServerSideEncryptionConfiguration.Rules[0].ApplyServerSideEncryptionByDefault.SSEAlgorithm'
Type: String
- name: VerifySuccess
action: 'aws:assertAwsResourceProperty'
inputs:
Service: s3
Api: GetBucketEncryption
BucketName: '{{ BucketName }}'
PropertySelector: '$.ServerSideEncryptionConfiguration.Rules[0].ApplyServerSideEncryptionByDefault.SSEAlgorithm'
DesiredValues:
- '{{ SSEType }}'
Terminal window
# Start remediation execution
aws configservice start-remediation-execution \
--config-rule-name s3-bucket-server-side-encryption-enabled \
--resource-keys '[{"resourceId":"my-bucket","resourceType":"AWS::S3::Bucket"}]'
# Describe remediation executions
aws configservice describe-remediation-executions \
--config-rule-name s3-bucket-server-side-encryption-enabled \
--resource-keys '[{"resourceId":"my-bucket","resourceType":"AWS::S3::Bucket"}]'

-- Find all EC2 instances
SELECT
resourceId,
resourceName,
configuration.instanceType,
configuration.state.name as state,
tags
WHERE
resourceType = 'AWS::EC2::Instance'
-- Find unencrypted S3 buckets
SELECT
resourceId,
resourceName,
region
WHERE
resourceType = 'AWS::S3::Bucket'
AND configuration.bucketEncryption IS NULL
-- Find security groups with SSH open to world
SELECT
resourceId,
resourceName,
configuration.ipPermissions
WHERE
resourceType = 'AWS::EC2::SecurityGroup'
AND configuration.ipPermissions[*].ipRanges[*].cidrIp = '0.0.0.0/0'
AND configuration.ipPermissions[*].fromPort = 22
-- Find instances without required tags
SELECT
resourceId,
resourceName,
tags
WHERE
resourceType = 'AWS::EC2::Instance'
AND tags.Environment IS NULL
-- Find all resources with specific tag
SELECT
resourceId,
resourceName,
resourceType,
tags
WHERE
tags.Project = 'Production'
-- Count resources by type
SELECT
resourceType,
COUNT(*) as count
GROUP BY
resourceType
ORDER BY
count DESC
Terminal window
# Run aggregation query
aws configservice select-aggregate-resource-config \
--expression "SELECT resourceId, resourceName, resourceType WHERE resourceType = 'AWS::EC2::Instance'"
# Run query with aggregation
aws configservice select-aggregate-resource-config \
--expression "SELECT resourceType, COUNT(*) as count GROUP BY resourceType"
# Query specific account/region
aws configservice select-aggregate-resource-config \
--expression "SELECT resourceId, resourceName WHERE resourceType = 'AWS::S3::Bucket'" \
--configuration-aggregator-name my-aggregator

Configuration Aggregator
+------------------------------------------------------------------+
| |
| Organization Aggregator |
| +----------------------------------------------------------+ |
| | | |
| | Management Account | |
| | +------------------------------------------------------+ | |
| | | Config Aggregator | | |
| | | +--------------------------------------------------+ | | |
| | | | Aggregated Data from All Accounts | | | |
| | | +--------------------------------------------------+ | | |
| | +------------------------------------------------------+ | |
| | | |
| +--------------------------+-------------------------------+ |
| | |
| +------------------+------------------+ |
| | | | |
| v v v |
| +----------+ +----------+ +----------+ |
| | Account A| | Account B| | Account C| |
| | Dev | | Staging | | Prod | |
| +----------+ +----------+ +----------+ |
| | | | |
| v v v |
| Config Data Config Data Config Data |
| |
+------------------------------------------------------------------+
Terminal window
# Create aggregator for organization
aws configservice put-configuration-aggregator \
--configuration-aggregator-name organization-aggregator \
--organization-aggregation-source \
'{"RoleArn":"arn:aws:iam::123456789012:role/ConfigAggregatorRole","AllAwsRegions":true}'
# Create aggregator for specific accounts
aws configservice put-configuration-aggregator \
--configuration-aggregator-name multi-account-aggregator \
--account-aggregation-sources \
'[{"AccountIds":["111111111111","222222222222"],"AllAwsRegions":true}]'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "config.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"organizations:ListAccounts",
"organizations:DescribeOrganization",
"organizations:ListAWSServiceAccessForOrganization"
],
"Resource": "*"
}
]
}

Conformance Packs
+------------------------------------------------------------------+
| |
| Conformance Pack Structure |
| +----------------------------------------------------------+ |
| | | |
| | +----------+ +----------+ +----------+ +----------+ | |
| | | Rule 1 | | Rule 2 | | Rule 3 | | Rule N | | |
| | | | | | | | | | | |
| | | - Config | | - Config | | - Config | | - Config | | |
| | | - Params | | - Params | | - Params | | - Params | | |
| | +----------+ +----------+ +----------+ +----------+ | |
| | | |
| | +------------------------------------------------------+ | |
| | | Remediation Configurations | | |
| | | - Auto-remediation actions | | |
| | | - SSM Automation documents | | |
| | +------------------------------------------------------+ | |
| | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
conformance-pack.yaml
Resources:
S3BucketEncryptionRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: s3-bucket-encryption
Description: Checks S3 bucket encryption
Scope:
ComplianceResourceTypes:
- AWS::S3::Bucket
Source:
Owner: AWS
SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
S3BucketPublicReadRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: s3-bucket-public-read
Description: Checks S3 bucket public read access
Scope:
ComplianceResourceTypes:
- AWS::S3::Bucket
Source:
Owner: AWS
SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED
EC2InstanceTypeRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: ec2-instance-type
Description: Checks EC2 instance types
Scope:
ComplianceResourceTypes:
- AWS::EC2::Instance
InputParameters:
allowedInstanceTypes: t3.micro,t3.small,t3.medium
Source:
Owner: AWS
SourceIdentifier: DESIRED_INSTANCE_TYPE
S3BucketEncryptionRemediation:
Type: AWS::Config::RemediationConfiguration
Properties:
ConfigRuleName: s3-bucket-encryption
TargetId: AWS-EnableS3BucketEncryption
TargetType: SSM_DOCUMENT
Automatic: true
Parameters:
BucketName:
ResourceValue:
Value: RESOURCE_ID
SSEType:
StaticValue:
Values:
- AES256
Terminal window
# Deploy conformance pack
aws configservice put-conformance-pack \
--conformance-pack-name security-conformance-pack \
--template-body file://conformance-pack.yaml
# Deploy with delivery S3 bucket
aws configservice put-conformance-pack \
--conformance-pack-name security-conformance-pack \
--template-body file://conformance-pack.yaml \
--delivery-s3-bucket config-conformance-bucket
# Describe conformance pack
aws configservice describe-conformance-packs \
--conformance-pack-names security-conformance-pack
# Get conformance pack compliance details
aws configservice get-conformance-pack-compliance-details \
--conformance-pack-name security-conformance-pack
security-baseline.yaml
Resources:
# IAM Rules
RootMfaRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: root-mfa-enabled
Source:
Owner: AWS
SourceIdentifier: ROOT_ACCOUNT_MFA_ENABLED
IamUserMfaRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: iam-user-mfa-enabled
Source:
Owner: AWS
SourceIdentifier: IAM_USER_MFA_ENABLED
AccessKeysRotatedRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: access-keys-rotated
InputParameters:
maxAccessKeyAge: "90"
Source:
Owner: AWS
SourceIdentifier: ACCESS_KEYS_ROTATED
# Encryption Rules
S3EncryptionRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: s3-bucket-encryption
Source:
Owner: AWS
SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
RdsEncryptionRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: rds-storage-encrypted
Source:
Owner: AWS
SourceIdentifier: RDS_STORAGE_ENCRYPTED
# Network Rules
RestrictedSshRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: restricted-ssh
Source:
Owner: AWS
SourceIdentifier: INCOMING_SSH_DISABLED

# CloudWatch Events rule for Config changes
Resources:
ConfigChangeRule:
Type: AWS::Events::Rule
Properties:
Name: config-compliance-change
Description: Trigger on Config compliance changes
EventPattern:
source:
- aws.config
detail-type:
- Config Rules Compliance Change
detail:
newEvaluationResult:
complianceType:
- NON_COMPLIANT
State: ENABLED
Targets:
- Id: SnsTopic
Arn: !Ref SnsTopic
- Id: LambdaFunction
Arn: !Ref LambdaFunction
# Lambda function to process Config notifications
import json
import boto3
def lambda_handler(event, context):
"""Process Config compliance change notifications"""
sns = boto3.client('sns')
for record in event.get('Records', []):
message = json.loads(record['Sns']['Message'])
# Extract compliance details
rule_name = message.get('configRuleName')
resource_id = message.get('resourceId')
compliance = message.get('newEvaluationResult', {}).get('complianceType')
# Send alert for non-compliant resources
if compliance == 'NON_COMPLIANT':
alert_message = f"""
Compliance Alert!
Rule: {rule_name}
Resource: {resource_id}
Status: {compliance}
Action Required: Please remediate this resource.
"""
sns.publish(
TopicArn='arn:aws:sns:us-east-1:123456789012:config-alerts',
Subject='AWS Config Compliance Alert',
Message=alert_message
)
return {'statusCode': 200}
Terminal window
# Enable Security Hub integration
aws securityhub enable-security-hub \
--enable-default-standards
# Import Config findings to Security Hub
# (Automatic when both services are enabled)

AWS Config Best Practices
+------------------------------------------------------------------+
| |
| 1. Recording Strategy |
| +--------------------------------------------------------+ |
| | - Record all supported resource types | |
| | - Include global resources (IAM) | |
| | - Use S3 lifecycle policies for cost management | |
| | - Enable in all regions | |
| +--------------------------------------------------------+ |
| |
| 2. Rules Strategy |
| +--------------------------------------------------------+ |
| | - Start with managed rules | |
| | - Add custom rules for specific requirements | |
| | - Use conformance packs for compliance frameworks | |
| | - Set appropriate remediation actions | |
| +--------------------------------------------------------+ |
| |
| 3. Multi-Account Strategy |
| +--------------------------------------------------------+ |
| | - Use configuration aggregator | |
| | - Deploy conformance packs organization-wide | |
| | - Centralize compliance reporting | |
| +--------------------------------------------------------+ |
| |
| 4. Cost Optimization |
| +--------------------------------------------------------+ |
| | - Use S3 lifecycle policies | |
| | - Limit custom rule frequency | |
| | - Review rule scope | |
| +--------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
# Recommended rules by category
Security:
- root-account-mfa-required
- iam-user-mfa-enabled
- access-keys-rotated
- cloudtrail-enabled
- multi-region-cloudtrail-enabled
Encryption:
- s3-bucket-server-side-encryption-enabled
- rds-storage-encrypted
- ebs-encrypted-volume
- cloudtrail-encryption-enabled
Network:
- vpc-default-security-group-closed
- restricted-ssh
- restricted-common-ports
- no-ingress-sg-rules
Tagging:
- required-tags
- allowed-resource-tags
Cost:
- ec2-instance-type-check
- ebs-volume-size-check
- rds-instance-type-check

AWS Config Troubleshooting
+------------------------------------------------------------------+
| |
| Issue: Config Rule Not Evaluating |
| +--------------------------------------------------------+ |
| | Solutions: | |
| | - Check IAM role permissions | |
| | - Verify resource scope | |
| | - Check Lambda function logs (custom rules) | |
| | - Verify trigger configuration | |
| +--------------------------------------------------------+ |
| |
| Issue: Remediation Failing |
| +--------------------------------------------------------+ |
| | Solutions: | |
| | - Check SSM document permissions | |
| | - Verify resource exists | |
| | - Check execution controls | |
| | - Review retry settings | |
| +--------------------------------------------------------+ |
| |
| Issue: High Costs |
| +--------------------------------------------------------+ |
| | Solutions: | |
| | - Reduce recording scope | |
| | - Use S3 lifecycle policies | |
| | - Limit custom rule frequency | |
| | - Review conformance pack scope | |
| +--------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Terminal window
# Check configuration recorder status
aws configservice describe-configuration-recorders
# Check delivery channel status
aws configservice describe-delivery-channels
# Get compliance details
aws configservice get-compliance-details-by-config-rule \
--config-rule-name s3-bucket-encryption
# Get resource configuration history
aws configservice get-resource-config-history \
--resource-type AWS::EC2::Instance \
--resource-id i-1234567890abcdef0
# Describe remediation exceptions
aws configservice describe-remediation-exceptions \
--config-rule-name s3-bucket-encryption

TopicKey Points
RecordingEnable for all resources and regions
Managed RulesStart with AWS managed rules
Custom RulesUse Lambda for complex evaluations
RemediationEnable automatic remediation where safe
AggregationUse aggregator for multi-account visibility
Conformance PacksDeploy compliance frameworks as code


Next Chapter: Chapter 45 - AWS Service Catalog & Provisioning