AWS Config Compliance & Governance

🎯 Mục tiêu Task 15: Setup AWS Config - TRACK CHANGES + COMPLIANCE RULES

15.0 Config Overview

Task 15 enable governance:

  • 📊 Config History: Track resource changes
  • 🛡️ Compliance Rules: Auto-check security
  • 🚨 Alerts: Detect misconfigurations
  • 📋 Dashboard: Central compliance view

Flow: Resource Changes → Config Recording → Compliance Check → Alerts

15.1 Prerequisites

  • ✅ S3 bucket cho storage
  • ✅ CloudWatch Events
  • ✅ SNS notifications

15.2 Enable Config

15.2.1 Setup Config

AWS Config Console → Get started:

  1. Recorder Settings:

    • ✅ Record all resources supported in this region
    • ✅ Include global resource types (IAM users, roles, policies)
    • ✅ Record all current and future resource types
  2. Delivery Channel:

    • S3 bucket: “vinashoes-aws-config-ap-southeast-1” (tạo mới)
    • S3 key prefix: “config-history/”
  3. SNS Topic:

    • Create new: “vinashoes-config-notifications”
  4. Service Role:

    • ✅ Create AWS Config service-linked role

CLI Reference:

# Tạo bucket cho Config (optional)
aws s3 mb s3://vinashoes-aws-config-ap-southeast-1 --region ap-southeast-1

15.3 Security Rules

15.3.1 Add AWS Managed Rules

Config Console → Rules → Add rule:

  1. Choose AWS Managed Rules:

    • s3-bucket-public-read-prohibited
    • s3-bucket-public-write-prohibited
    • restricted-ssh
    • iam-user-no-policies-check
    • root-access-key-check
    • vpc-default-security-group-closed
    • encrypted-volumes
    • ec2-instance-no-public-ip
    • cloudtrail-enabled
    • multi-region-cloudtrail-enabled
    • s3-bucket-server-side-encryption-enabled
    • rds-storage-encrypted
    • lambda-function-public-access-prohibited
    • api-gw-execution-logging-enabled
    • cloudformation-stack-notification-check
  2. For each rule:

    • Select rule → Configure parameters (if any) → Save
    • Set remediation action if available
    • Configure triggers (configuration changes vs periodic)

Advanced Rule Configuration:

# Example: encrypted-volumes rule with parameters
Parameters:
  kmsKeyArns: "arn:aws:kms:ap-southeast-1:ACCOUNT:key/KEY-ID"

# Example: restricted-ssh with custom IP ranges
Parameters:
  allowedIps: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"

Essential Rules Summary:

Critical Security Rules:
  1. S3 bucket public access prohibited (Block public S3 buckets)
  2. S3 bucket public write prohibited (Prevent unauthorized writes)
  3. SSH restricted to specific IPs (Network security)
  4. IAM users no direct policies (Use groups/roles)
  5. Root account no access keys (Security best practice)
  6. VPC default security group closed (Network isolation)
  7. Encrypted volumes (Data at rest encryption)
  8. EC2 instances no public IP (Network security)
  9. CloudTrail enabled (Audit logging)
  10. Multi-region CloudTrail (Comprehensive logging)
  11. S3 SSE enabled (Storage encryption)
  12. RDS storage encrypted (Database security)
  13. Lambda public access prohibited (Function security)
  14. API Gateway logging enabled (API monitoring)
  15. CloudFormation notifications (Infrastructure monitoring)

15.3.2 Rule Remediation Actions

Config Console → Rules → [Rule Name] → Actions → Manage remediation:

  1. Automatic Remediation Setup:

    • Choose remediation action (AWS managed or custom)
    • Configure parameters
    • Set retry attempts and timeout
  2. Common Remediation Actions:

    • AWS-EnableS3BucketEncryption - Enable SSE on S3 buckets
    • AWS-EnableEncryptionOnRDSDBInstance - Enable RDS encryption
    • AWS-ConfigureS3BucketPublicAccessBlock - Block public access
    • AWS-EnableCloudTrail - Enable CloudTrail logging

Custom Remediation with SSM Automation:

AutomationDocument:
  Name: AWS-ConfigRemediation-EnableS3Versioning
  Parameters:
    - BucketName: "$.ResourceId"
  Actions:
    - Name: EnableVersioning
      Action: aws:executeAwsApi
      Inputs:
        Service: s3
        Api: PutBucketVersioning
        Bucket: "{{BucketName}}"
        VersioningConfiguration:
          Status: Enabled

15.3.3 Rule Dependencies & Conflicts

Rule Interaction Matrix:

Rule Dependencies:
  - cloudtrail-enabled → multi-region-cloudtrail-enabled
  - s3-bucket-public-read-prohibited → s3-bucket-public-write-prohibited
  
Rule Conflicts:
  - ec2-instance-no-public-ip ↔ vpc-default-security-group-closed
  - encrypted-volumes ↔ rds-storage-encrypted (different services)

Resolution Strategies:

  • Use rule parameters to customize behavior
  • Implement rule precedence with tags
  • Create composite rules for complex scenarios

15.4 Custom Rules

15.4.1 ECR Image Compliance Rule

🐳 Custom Rule: ECR Internal Images ECS tasks chỉ được dùng images từ ECR nội bộ để đảm bảo security và compliance

Lambda Console → Create function:

  1. Function Name: config-ecr-internal-images
  2. Runtime: Python 3.9
  3. Role: Create role với Config permissions + ECR read access

Advanced Function Code:

import json
import boto3
import re
from botocore.exceptions import ClientError

def lambda_handler(event, context):
    config = boto3.client('config')
    ecr = boto3.client('ecr')
    configuration_item = event['configurationItem']
    
    compliance_type = 'COMPLIANT'
    annotation = 'ECS task definition uses approved ECR images'
    
    if configuration_item['resourceType'] == 'AWS::ECS::TaskDefinition':
        task_definition = json.loads(configuration_item['configuration'])
        account_id = event['accountId']
        region = event['region']
        
        # Get approved repositories
        try:
            approved_repos = ecr.describe_repositories(
                repositoryName='vinashoes-*'
            )['repositories']
            approved_repo_names = [repo['repositoryName'] for repo in approved_repos]
        except ClientError:
            approved_repo_names = ['vinashoes-web', 'vinashoes-api', 'vinashoes-worker']
        
        for container in task_definition.get('containerDefinitions', []):
            image = container.get('image', '')
            
            # Check if image is from approved ECR
            expected_pattern = f"{account_id}\.dkr\.ecr\.{region}\.amazonaws\.com/({'|'.join(approved_repo_names)})"
            
            if not re.match(expected_pattern, image):
                compliance_type = 'NON_COMPLIANT'
                annotation = f'Container {container["name"]} uses non-approved image: {image}'
                break
            
            # Additional checks: tag validation
            if ':' not in image or image.endswith(':latest'):
                compliance_type = 'NON_COMPLIANT'
                annotation = f'Container {container["name"]} uses latest tag or no tag: {image}'
                break
    
    evaluation = {
        'ComplianceResourceType': configuration_item['resourceType'],
        'ComplianceResourceId': configuration_item['resourceId'],
        'ComplianceType': compliance_type,
        'Annotation': annotation,
        'OrderingTimestamp': configuration_item['configurationItemCaptureTime']
    }
    
    config.put_evaluations(
        Evaluations=[evaluation],
        ResultToken=event['resultToken']
    )
    
    return {'statusCode': 200}

15.4.2 Advanced Custom Rules

Rule 2: Security Group Compliance

Lambda Function: config-security-group-compliance

def lambda_handler(event, context):
    config = boto3.client('config')
    ec2 = boto3.client('ec2')
    configuration_item = event['configurationItem']
    
    if configuration_item['resourceType'] == 'AWS::EC2::SecurityGroup':
        sg_id = configuration_item['resourceId']
        
        # Get security group details
        sg_details = ec2.describe_security_groups(GroupIds=[sg_id])['SecurityGroups'][0]
        
        compliance_type = 'COMPLIANT'
        violations = []
        
        # Check for overly permissive rules
        for permission in sg_details.get('IpPermissions', []):
            if permission.get('IpProtocol') == '-1':  # All traffic
                violations.append('All traffic allowed')
            
            for ip_range in permission.get('IpRanges', []):
                if ip_range.get('CidrIp') == '0.0.0.0/0':
                    violations.append(f'Port {permission.get("FromPort", "N/A")} open to world')
        
        if violations:
            compliance_type = 'NON_COMPLIANT'
            annotation = f'Security violations: {", ".join(violations)}'
        else:
            annotation = 'Security group follows best practices'
    
    # Submit evaluation
    evaluation = {
        'ComplianceResourceType': configuration_item['resourceType'],
        'ComplianceResourceId': configuration_item['resourceId'],
        'ComplianceType': compliance_type,
        'Annotation': annotation,
        'OrderingTimestamp': configuration_item['configurationItemCaptureTime']
    }
    
    config.put_evaluations(Evaluations=[evaluation], ResultToken=event['resultToken'])
    return {'statusCode': 200}

Rule 3: Cost Optimization Rule

Lambda Function: config-cost-optimization

def lambda_handler(event, context):
    config = boto3.client('config')
    configuration_item = event['configurationItem']
    
    compliance_type = 'COMPLIANT'
    annotation = 'Resource follows cost optimization practices'
    
    if configuration_item['resourceType'] == 'AWS::EC2::Instance':
        instance_config = json.loads(configuration_item['configuration'])
        
        # Check instance type
        instance_type = instance_config.get('instanceType', '')
        if instance_type.startswith(('t2.', 't3.')) and instance_config.get('state', {}).get('name') == 'running':
            # Check if instance has been running for more than 24 hours
            launch_time = instance_config.get('launchTime')
            if launch_time:
                import datetime
                launch_dt = datetime.datetime.fromisoformat(launch_time.replace('Z', '+00:00'))
                now = datetime.datetime.now(datetime.timezone.utc)
                runtime = now - launch_dt
                
                if runtime.days > 1:
                    compliance_type = 'NON_COMPLIANT'
                    annotation = f'Burstable instance {instance_type} running for {runtime.days} days - consider reserved instance'
    
    evaluation = {
        'ComplianceResourceType': configuration_item['resourceType'],
        'ComplianceResourceId': configuration_item['resourceId'],
        'ComplianceType': compliance_type,
        'Annotation': annotation,
        'OrderingTimestamp': configuration_item['configurationItemCaptureTime']
    }
    
    config.put_evaluations(Evaluations=[evaluation], ResultToken=event['resultToken'])
    return {'statusCode': 200}

15.4.3 Config Conformance Packs

Advanced Compliance Frameworks:

  1. Create Conformance Pack:
# conformance-pack.yaml
Resources:
  - AWSConfigRule:
      Properties:
        ConfigRuleName: s3-bucket-encryption-enabled
        Description: Checks that S3 buckets have encryption enabled
        Source:
          Owner: AWS
          SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
        Scope:
          ComplianceResourceTypes:
            - AWS::S3::Bucket

  - AWSConfigRule:
      Properties:
        ConfigRuleName: ec2-instance-detailed-monitoring-enabled
        Description: Checks that EC2 instances have detailed monitoring enabled
        Source:
          Owner: AWS
          SourceIdentifier: EC2_INSTANCE_DETAILED_MONITORING_ENABLED
  1. Deploy Conformance Pack:
# Upload to S3
aws s3 cp conformance-pack.yaml s3://vinashoes-config-conformance-packs/

# Deploy pack
aws configservice put-conformance-pack \
  --conformance-pack-name VinaShoesSecurityPack \
  --template-s3-uri s3://vinashoes-config-conformance-packs/conformance-pack.yaml \
  --delivery-s3-bucket vinashoes-aws-config-ap-southeast-1

15.4.4 Rule Testing & Validation

Test Custom Rules:

# Test Lambda function locally
aws lambda invoke \
  --function-name config-ecr-internal-images \
  --payload '{"test": "data"}' \
  output.json

# Validate Config rule
aws configservice describe-config-rules \
  --config-rule-names ecr-internal-images-only

# Test rule evaluation
aws configservice start-config-rules-evaluation \
  --config-rule-names ecr-internal-images-only
  1. Config Console → Rules → Add rule → Custom Lambda rule
    • Rule name: ecr-internal-images-only
    • Lambda function: config-ecr-internal-images
    • Trigger: ECS Task Definition changes

CLI Reference:

# Deploy Lambda function
aws lambda create-function \
  --function-name config-ecr-internal-images \
  --runtime python3.9 \
  --role arn:aws:iam::ACCOUNT:role/lambda-config-role \
  --handler lambda_function.lambda_handler \
  --zip-file fileb://function.zip

# Create Config rule
aws configservice put-config-rule \
  --config-rule '{
    "ConfigRuleName": "ecr-internal-images-only",
    "Source": {
      "Owner": "AWS_LAMBDA",
      "SourceIdentifier": "arn:aws:lambda:ap-southeast-1:ACCOUNT:function:config-ecr-internal-images"
    },
    "Scope": {
      "ComplianceResourceTypes": ["AWS::ECS::TaskDefinition"]
    }
  }'

15.5 Compliance Monitoring

15.5.1 CloudWatch Events Integration

CloudWatch Console → Events → Rules → Create rule:

  1. Event Source:

    • Service Name: Config
    • Event Type: Config Rules Compliance Change
  2. Advanced Event Pattern:

{
  "source": ["aws.config"],
  "detail-type": ["Config Rules Compliance Change"],
  "detail": {
    "newEvaluationResult": {
      "complianceType": ["NON_COMPLIANT"]
    },
    "configRuleName": [
      "s3-bucket-public-read-prohibited",
      "iam-user-no-policies-check",
      "root-access-key-check"
    ]
  }
}
  1. Targets:
    • SNS Topic: vinashoes-config-alerts (Email notifications)
    • Lambda Function: config-auto-remediation (Automatic fixes)
    • Systems Manager: Run remediation runbooks

15.5.2 Advanced Compliance Dashboard

CloudWatch Console → Dashboards → Create dashboard:

  1. Dashboard Name: VinaShoesCompliance

  2. Compliance Overview Widget:

{
  "type": "metric",
  "properties": {
    "metrics": [
      ["AWS/Config", "ComplianceByConfigRule", "ConfigRuleName", "s3-bucket-public-read-prohibited", "ComplianceType", "NON_COMPLIANT"],
      [".", ".", ".", "iam-user-no-policies-check", ".", "."],
      [".", ".", ".", "root-access-key-check", ".", "."]
    ],
    "view": "timeSeries",
    "stacked": false,
    "region": "ap-southeast-1",
    "title": "Critical Security Violations"
  }
}
  1. Resource Inventory Widget:

    • Query: Config resource inventory
    • Group by: Resource type and compliance status
  2. Trend Analysis Widget:

    • Show compliance trends over time
    • Identify worsening areas

15.5.3 Integration with AWS Security Hub

Security Hub Console → Integrations → AWS Config:

  1. Enable Security Hub Integration:
aws securityhub enable-security-hub

# Enable Config findings in Security Hub
aws securityhub batch-enable-standards \
  --standards-subscription-requests '[
    {"StandardsArn": "arn:aws:securityhub:ap-southeast-1::standards/aws-foundations-benchmark/v/1.2.0"}
  ]'
  1. Config Rules to Security Hub Findings:
    • Automatic mapping of Config compliance to Security Hub
    • Centralized security findings dashboard
    • Integration with ticketing systems

15.5.4 Multi-Account Compliance Monitoring

AWS Organizations Setup:

  1. Enable Config in Management Account:
aws configservice put-organization-config-rule \
  --organization-config-rule-name s3-bucket-public-read-prohibited \
  --trigger-types ConfigurationItemChangeNotification \
  --description "Checks that S3 buckets do not allow public read access"
  1. Delegate Config Administration:
aws organizations register-delegated-administrator \
  --account-id DELEGATED_ACCOUNT_ID \
  --service-principal config.amazonaws.com
  1. Organization-wide Compliance Dashboard:
    • Aggregate compliance across all accounts
    • Centralized reporting and alerting

15.5.5 Advanced Alerting & Escalation

SNS Topic Configuration:

{
  "TopicName": "vinashoes-config-alerts",
  "Attributes": {
    "DeliveryPolicy": "{\"healthyRetryPolicy\":{\"numRetries\":3}}",
    "DisplayName": "Config Compliance Alerts"
  },
  "Subscriptions": [
    {
      "Protocol": "email",
      "Endpoint": "[email protected]"
    },
    {
      "Protocol": "https",
      "Endpoint": "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
    }
  ]
}

Escalation Rules:

  • Critical violations: Immediate email + Slack alert
  • High violations: Email within 1 hour
  • Medium violations: Daily summary
  • Low violations: Weekly report

15.6 Auto-Remediation

15.6.1 Lambda Auto-Remediation

Lambda Console → Create function:

  1. Basic Information:

    • Function Name: config-s3-auto-remediation
    • Runtime: Python 3.9
    • Role: Create new role với Config + S3 permissions
  2. Advanced Function Code:

import boto3
import json
from botocore.exceptions import ClientError

def lambda_handler(event, context):
    s3 = boto3.client('s3')
    config = boto3.client('config')
    
    # Parse Config event
    detail = event.get('detail', {})
    resource_id = detail.get('resourceId')
    config_rule_name = detail.get('configRuleName')
    
    remediation_actions = {
        's3-bucket-public-read-prohibited': remediate_s3_public_access,
        's3-bucket-server-side-encryption-enabled': remediate_s3_encryption,
        'vpc-default-security-group-closed': remediate_default_sg
    }
    
    if config_rule_name in remediation_actions:
        try:
            result = remediation_actions[config_rule_name](resource_id)
            print(f"Remediation successful for {config_rule_name}: {resource_id}")
            return {'statusCode': 200, 'body': json.dumps(result)}
        except Exception as e:
            print(f"Remediation failed for {config_rule_name}: {str(e)}")
            # Send alert for failed remediation
            send_remediation_alert(config_rule_name, resource_id, str(e))
            return {'statusCode': 500, 'body': json.dumps({'error': str(e)})}
    
    return {'statusCode': 400, 'body': json.dumps({'error': 'Unsupported rule'})}

def remediate_s3_public_access(bucket_name):
    s3 = boto3.client('s3')
    
    # Block all public access
    s3.put_public_access_block(
        Bucket=bucket_name,
        PublicAccessBlockConfiguration={
            'BlockPublicAcls': True,
            'IgnorePublicAcls': True,
            'BlockPublicPolicy': True,
            'RestrictPublicBuckets': True
        }
    )
    
    # Remove existing public policies
    try:
        policy = s3.get_bucket_policy(Bucket=bucket_name)
        # Analyze and remove public statements
        policy_doc = json.loads(policy['Policy'])
        filtered_statements = []
        
        for statement in policy_doc.get('Statement', []):
            if is_public_statement(statement):
                continue  # Skip public statements
            filtered_statements.append(statement)
        
        if filtered_statements:
            policy_doc['Statement'] = filtered_statements
            s3.put_bucket_policy(Bucket=bucket_name, Policy=json.dumps(policy_doc))
        else:
            s3.delete_bucket_policy(Bucket=bucket_name)
            
    except ClientError:
        pass  # No policy to remove
    
    return {'remediated': bucket_name, 'action': 'blocked_public_access'}

def remediate_s3_encryption(bucket_name):
    s3 = boto3.client('s3')
    
    s3.put_bucket_encryption(
        Bucket=bucket_name,
        ServerSideEncryptionConfiguration={
            'Rules': [{
                'ApplyServerSideEncryptionByDefault': {
                    'SSEAlgorithm': 'AES256'
                },
                'BucketKeyEnabled': True
            }]
        }
    )
    
    return {'remediated': bucket_name, 'action': 'enabled_encryption'}

def remediate_default_sg(sg_id):
    ec2 = boto3.client('ec2')
    
    # Remove all inbound rules from default security group
    ec2.revoke_security_group_ingress(
        GroupId=sg_id,
        IpPermissions=[{
            'IpProtocol': '-1'  # All protocols
        }]
    )
    
    return {'remediated': sg_id, 'action': 'closed_default_sg'}

def is_public_statement(statement):
    """Check if IAM policy statement allows public access"""
    principal = statement.get('Principal', '')
    if principal == '*' or principal == {'AWS': '*'}:
        return True
    
    # Check conditions for public access
    conditions = statement.get('Condition', {})
    if not conditions:
        return True
    
    # More complex logic for conditional public access
    return False

def send_remediation_alert(rule_name, resource_id, error):
    sns = boto3.client('sns')
    sns.publish(
        TopicArn='arn:aws:sns:ap-southeast-1:ACCOUNT:vinashoes-config-alerts',
        Subject=f'Config Remediation Failed: {rule_name}',
        Message=f'Failed to remediate {resource_id}\nError: {error}'
    )

15.6.2 Systems Manager Automation Remediation

Create Automation Document:

description: Remediate non-compliant EC2 instances
schemaVersion: '0.3'
parameters:
  InstanceId:
    type: String
    description: The ID of the EC2 instance to remediate
  AutomationAssumeRole:
    type: String
    description: The ARN of the role that allows Automation to perform the actions
mainSteps:
  - name: StopInstance
    action: aws:executeAwsApi
    inputs:
      Service: ec2
      Api: StopInstances
      InstanceIds:
        - '{{InstanceId}}'
    description: Stop the non-compliant instance
  - name: CreateImage
    action: aws:executeAwsApi
    inputs:
      Service: ec2
      Api: CreateImage
      InstanceId: '{{InstanceId}}'
      Name: 'remediated-{{InstanceId}}-{{global:DATE_TIME}}'
    description: Create an AMI before remediation
  - name: TerminateInstance
    action: aws:executeAwsApi
    inputs:
      Service: ec2
      Api: TerminateInstances
      InstanceIds:
        - '{{InstanceId}}'
    description: Terminate the non-compliant instance

15.6.3 Remediation Approval Workflows

AWS Step Functions for Approval:

{
  "Comment": "Config Remediation Approval Workflow",
  "StartAt": "CheckSeverity",
  "States": {
    "CheckSeverity": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.severity",
          "StringEquals": "CRITICAL",
          "Next": "AutoRemediate"
        }
      ],
      "Default": "ManualApproval"
    },
    "AutoRemediate": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "config-s3-auto-remediation"
      },
      "End": true
    },
    "ManualApproval": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "arn:aws:sns:ap-southeast-1:ACCOUNT:remediation-approval",
        "Message": "Config violation requires approval for remediation"
      },
      "End": true
    }
  }
}

15.6.4 Remediation Monitoring & Reporting

CloudWatch Alarms for Remediation:

# Alarm for failed remediations
aws cloudwatch put-metric-alarm \
  --alarm-name ConfigRemediationFailures \
  --alarm-description "Alert when Config remediation fails" \
  --metric-name RemediationFailureCount \
  --namespace AWS/Config \
  --statistic Sum \
  --period 300 \
  --threshold 1 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 1

Remediation Success Dashboard:

  • Success rate by rule type
  • Average remediation time
  • Failed remediation trends
  • Cost impact of remediation actions

15.7 Advanced Config Features

15.7.1 Config Aggregators for Multi-Account

Create Config Aggregator:

# In management account
aws configservice put-configuration-aggregator \
  --configuration-aggregator-name VinaShoesOrgAggregator \
  --organization-source \
    OrganizationSourceType=ORGANIZATION \
    RoleArn=arn:aws:iam::MANAGEMENT_ACCOUNT:role/ConfigAggregatorRole

Aggregator Permissions:

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

15.7.2 Advanced Queries with AWS Config Advanced Query

Config Console → Advanced queries:

SELECT
  resourceId,
  resourceType,
  configuration.instanceType,
  configuration.state.name
WHERE
  resourceType = 'AWS::EC2::Instance'
  AND configuration.state.name = 'running'
  AND configuration.instanceType LIKE 't2.%'
ORDER BY
  configuration.launchTime DESC

15.7.3 Config Rules with AWS Config Rules Development Kit (RDK)

Install RDK:

pip install rdk

Create Custom Rule:

rdk create ec2-instance-tags-check --runtime python3.9 --resource-types AWS::EC2::Instance

# Edit rule code in rules/ec2-instance-tags-check/ec2-instance-tags-check.py

rdk deploy ec2-instance-tags-check

15.7.4 Integration with AWS Control Tower

Control Tower Preventive Controls:

  • Mandatory Config rules across accounts
  • Automated deployment via CloudFormation StackSets
  • Centralized compliance monitoring

Custom Controls:

# Landing Zone customizations
OrganizationalUnits:
  - Name: Security
    Controls:
      - ControlIdentifier: CONFIG_RULE
        Parameters:
          RuleName: s3-bucket-public-read-prohibited
          RuleParameters:
            - Key: severity
              Value: CRITICAL

15.8 Troubleshooting & Best Practices

15.8.1 Common Issues & Solutions

Issue: Config recorder not recording changes

# Check recorder status
aws configservice describe-configuration-recorders

# Check IAM permissions
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::ACCOUNT:role/ConfigRole \
  --action-names config:PutConfigurationRecorder

Issue: Rules not evaluating

# Force rule evaluation
aws configservice start-config-rules-evaluation \
  --config-rule-names RULE_NAME

# Check rule status
aws configservice describe-config-rule-evaluation-status \
  --config-rule-names RULE_NAME

Issue: High Config costs

  • Reduce configuration item retention period
  • Use selective recording for specific resource types
  • Disable Config in development accounts
  • Implement resource tagging for targeted monitoring

15.8.2 Performance Optimization

Config Recorder Optimization:

# Selective recording configuration
RecordingGroup:
  AllSupported: false
  IncludeGlobalResourceTypes: true
  ResourceTypes:
    - AWS::EC2::Instance
    - AWS::S3::Bucket
    - AWS::IAM::Role
  ExcludeResourceTypes:
    - AWS::Config::ResourceCompliance

Rule Performance Tuning:

  • Use periodic evaluation for non-critical rules
  • Implement rule caching for expensive operations
  • Optimize Lambda function memory and timeout
  • Use batch operations for multiple resources

15.8.3 Security Best Practices

Config Security Hardening:

  • Use least-privilege IAM roles
  • Enable encryption for Config data
  • Implement access logging
  • Regular security assessments

Data Protection:

  • Encrypt configuration history
  • Implement retention policies
  • Secure S3 bucket access
  • Regular backup of Config data

15.8.4 Monitoring & Alerting Best Practices

Advanced Monitoring Setup:

# Config delivery failed alarm
aws cloudwatch put-metric-alarm \
  --alarm-name ConfigDeliveryFailed \
  --alarm-description "Config delivery to S3 failed" \
  --metric-name ConfigDeliveryFailed \
  --namespace AWS/Config \
  --statistic Maximum \
  --period 3600 \
  --threshold 1 \
  --comparison-operator GreaterThanThreshold

Compliance Trend Analysis:

  • Weekly compliance reports
  • Monthly trend analysis
  • Quarterly compliance reviews
  • Annual compliance audits

⚠️ Cảnh báo: Việc clean up sẽ xóa tất cả Config rules, recorder và data. Hãy đảm bảo không còn cần thiết trước khi thực hiện!

CLI Commands for Clean Up

Xóa Config rules:

# Xóa managed rules
aws configservice delete-config-rule --config-rule-name s3-bucket-public-read-prohibited
aws configservice delete-config-rule --config-rule-name s3-bucket-public-write-prohibited
aws configservice delete-config-rule --config-rule-name restricted-ssh
aws configservice delete-config-rule --config-rule-name iam-user-no-policies-check
aws configservice delete-config-rule --config-rule-name root-access-key-check
aws configservice delete-config-rule --config-rule-name vpc-default-security-group-closed

# Xóa custom rule
aws configservice delete-config-rule --config-rule-name ecr-internal-images-only

Xóa Lambda functions:

# Xóa Lambda functions
aws lambda delete-function --function-name config-ecr-internal-images
aws lambda delete-function --function-name config-s3-auto-remediation

Disable Config recorder:

# Stop configuration recorder
aws configservice stop-configuration-recorder --configuration-recorder-name default

# Delete configuration recorder
aws configservice delete-configuration-recorder --configuration-recorder-name default

Xóa S3 bucket và SNS topic:

# Xóa tất cả objects trong Config bucket
aws s3 rm s3://vinashoes-aws-config-ap-southeast-1 --recursive

# Xóa bucket
aws s3 rb s3://vinashoes-aws-config-ap-southeast-1

# Xóa SNS topic
aws sns delete-topic --topic-arn arn:aws:sns:ap-southeast-1:ACCOUNT:vinashoes-config-notifications

📋 Lưu ý khi clean up:

  • Config data sẽ bị mất vĩnh viễn
  • Không thể khôi phục configuration history
  • Rules và alerts sẽ ngừng hoạt động
  • S3 bucket chứa important compliance data

15.10 Cost Analysis

💰 Advanced Cost Analysis for AWS Config

15.10.1 Detailed Cost Breakdown

Cost Component Pricing Factors Monthly Estimate
Configuration Items $0.003/item Resource changes, evaluations $50-200
Configuration Recorder Free Base service $0
S3 Storage $0.023/GB History retention (1 year) $10-50
Lambda Invocations $0.20/1M requests Custom rules $5-20
CloudWatch Events Free Event delivery $0
SNS Notifications $0.50/100K requests Alerts $1-5
Data Transfer $0.09/GB Cross-region replication $5-15

15.10.2 Cost Optimization Strategies

Retention Policy Optimization:

# Set retention period to 1 year instead of indefinite
aws configservice put-retention-configuration \
  --retention-period-in-days 365

Selective Recording Configuration:

# Only record critical resources
RecordingGroup:
  AllSupported: false
  ResourceTypes:
    - AWS::EC2::Instance
    - AWS::S3::Bucket
    - AWS::RDS::DBInstance
    - AWS::Lambda::Function
  ExcludeResourceTypes:
    - AWS::EC2::NetworkInterface
    - AWS::EC2::Volume
    - AWS::CloudWatch::Alarm

Rule Evaluation Optimization:

  • Use configuration change triggers instead of periodic
  • Implement rule caching for expensive checks
  • Batch evaluations for similar resources
  • Disable rules in development environments

15.10.3 Cost Monitoring & Alerting

Config Cost Dashboard:

# CloudWatch metrics for Config costs
aws cloudwatch get-metric-statistics \
  --namespace AWS/Config \
  --metric-name ConfigurationItemsRecorded \
  --start-time 2024-01-01T00:00:00Z \
  --end-time 2024-01-31T23:59:59Z \
  --period 86400 \
  --statistics Sum

Cost Anomaly Detection:

  • Set up billing alerts for Config costs
  • Monitor cost per rule evaluation
  • Track storage growth trends
  • Alert on unexpected cost increases

15.10.4 ROI Analysis with Advanced Metrics

Metric Without Config With Config Advanced Benefits
Security Incidents High risk Low risk Automated prevention
Compliance Violations Unknown Monitored Real-time detection
Audit Preparation Manual (weeks) Automated (hours) 90% time reduction
Configuration Drift Uncontrolled Tracked Immediate alerts
Remediation Time Days Minutes 99% faster response
Annual Cost $0 $500 Cost of security vs breaches

15.10.5 Cost Scenarios by Organization Size

Startup (10-50 resources):

  • Monthly cost: $20-50
  • Focus: Essential security rules
  • ROI: High (prevents major incidents)

Small Business (50-200 resources):

  • Monthly cost: $50-150
  • Focus: Comprehensive security + compliance
  • ROI: Very high (automated compliance)

Enterprise (200+ resources):

  • Monthly cost: $200-500+
  • Focus: Advanced automation + multi-account
  • ROI: Excellent (centralized governance)

Enterprise (1000+ resources):

  • Monthly cost: $1000+
  • Focus: Full governance + advanced analytics
  • ROI: Critical (regulatory compliance)

15.10.6 Cost-Benefit Analysis Framework

Quantitative Benefits:

  • Reduced security incident response time: 80%
  • Compliance audit preparation time: 90% reduction
  • Automated remediation success rate: 95%
  • False positive reduction: 70%

Qualitative Benefits:

  • Improved security posture
  • Regulatory compliance assurance
  • Operational efficiency gains
  • Risk mitigation confidence

Break-even Analysis:

  • Typical break-even period: 3-6 months
  • ROI multiple: 5-10x over 2 years
  • Risk-adjusted ROI: Significantly higher

15.11 Clean Up Resources

⚠️ Cảnh báo: Việc clean up sẽ xóa tất cả Config rules, recorder và data. Hãy đảm bảo không còn cần thiết trước khi thực hiện!

15.11.1 Comprehensive Clean Up Script

Create cleanup script:

#!/bin/bash

# AWS Config Complete Cleanup Script
# Run with caution - this will remove all Config resources

echo "Starting AWS Config cleanup..."

# 1. Delete all Config rules
echo "Deleting Config rules..."
RULES=$(aws configservice describe-config-rules --query 'ConfigRules[].ConfigRuleName' --output text)

for RULE in $RULES; do
    echo "Deleting rule: $RULE"
    aws configservice delete-config-rule --config-rule-name "$RULE"
done

# 2. Delete Conformance Packs
echo "Deleting Conformance Packs..."
PACKS=$(aws configservice describe-conformance-packs --query 'ConformancePackNames' --output text)

for PACK in $PACKS; do
    echo "Deleting conformance pack: $PACK"
    aws configservice delete-conformance-pack --conformance-pack-name "$PACK"
done

# 3. Delete Organization Config Rules (if applicable)
echo "Deleting Organization Config Rules..."
ORG_RULES=$(aws configservice describe-organization-config-rules --query 'OrganizationConfigRules[].OrganizationConfigRuleName' --output text 2>/dev/null || echo "")

for ORG_RULE in $ORG_RULES; do
    echo "Deleting org rule: $ORG_RULE"
    aws configservice delete-organization-config-rule --organization-config-rule-name "$ORG_RULE"
done

# 4. Stop and delete Configuration Recorder
echo "Stopping Configuration Recorder..."
aws configservice stop-configuration-recorder --configuration-recorder-name default

echo "Deleting Configuration Recorder..."
aws configservice delete-configuration-recorder --configuration-recorder-name default

# 5. Delete Config Aggregator (if exists)
echo "Deleting Config Aggregator..."
AGGREGATORS=$(aws configservice describe-configuration-aggregators --query 'ConfigurationAggregators[].ConfigurationAggregatorName' --output text 2>/dev/null || echo "")

for AGG in $AGGREGATORS; do
    echo "Deleting aggregator: $AGG"
    aws configservice delete-configuration-aggregator --configuration-aggregator-name "$AGG"
done

# 6. Delete Lambda functions
echo "Deleting Lambda functions..."
LAMBDAS="config-ecr-internal-images config-s3-auto-remediation config-security-group-compliance config-cost-optimization"

for LAMBDA in $LAMBDAS; do
    if aws lambda get-function --function-name "$LAMBDA" &>/dev/null; then
        echo "Deleting Lambda: $LAMBDA"
        aws lambda delete-function --function-name "$LAMBDA"
    fi
done

# 7. Delete CloudWatch Events rules
echo "Deleting CloudWatch Events rules..."
RULES="ConfigComplianceChange ConfigRemediationApproval"

for RULE in $RULES; do
    if aws events describe-rule --name "$RULE" &>/dev/null; then
        echo "Deleting Event Rule: $RULE"
        aws events delete-rule --name "$RULE"
    fi
done

# 8. Delete SNS Topics
echo "Deleting SNS Topics..."
TOPICS="vinashoes-config-notifications vinashoes-config-alerts remediation-approval"

for TOPIC in $TOPICS; do
    TOPIC_ARN=$(aws sns list-topics --query "Topics[?contains(TopicArn, '$TOPIC')].TopicArn" --output text)
    if [ -n "$TOPIC_ARN" ]; then
        echo "Deleting SNS Topic: $TOPIC"
        aws sns delete-topic --topic-arn "$TOPIC_ARN"
    fi
done

# 9. Delete S3 bucket (CAUTION: Contains historical data)
BUCKET="vinashoes-aws-config-ap-southeast-1"
echo "WARNING: About to delete S3 bucket $BUCKET containing Config history!"
read -p "Are you sure you want to delete the Config history bucket? (yes/no): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    echo "Deleting S3 bucket: $BUCKET"
    aws s3 rb s3://"$BUCKET" --force
else
    echo "Skipping S3 bucket deletion"
fi

# 10. Delete IAM Roles
echo "Deleting IAM Roles..."
ROLES="VinaShoesConfigRole ConfigAggregatorRole config-lambda-role"

for ROLE in $ROLES; do
    if aws iam get-role --role-name "$ROLE" &>/dev/null; then
        echo "Deleting IAM Role: $ROLE"
        # Detach all policies first
        POLICIES=$(aws iam list-attached-role-policies --role-name "$ROLE" --query 'AttachedPolicies[].PolicyArn' --output text)
        for POLICY in $POLICIES; do
            aws iam detach-role-policy --role-name "$ROLE" --policy-arn "$POLICY"
        done
        # Delete role
        aws iam delete-role --role-name "$ROLE"
    fi
done

# 11. Clean up CloudWatch resources
echo "Cleaning up CloudWatch resources..."
DASHBOARDS="VinaShoesCompliance"
ALARMS="ConfigDeliveryFailed ConfigRemediationFailures ConfigComplianceViolation"

for DASH in $DASHBOARDS; do
    if aws cloudwatch describe-dashboards --dashboard-name "$DASH" &>/dev/null; then
        echo "Deleting Dashboard: $DASH"
        aws cloudwatch delete-dashboards --dashboard-names "$DASH"
    fi
done

for ALARM in $ALARMS; do
    if aws cloudwatch describe-alarms --alarm-names "$ALARM" &>/dev/null; then
        echo "Deleting Alarm: $ALARM"
        aws cloudwatch delete-alarms --alarm-names "$ALARM"
    fi
done

echo "AWS Config cleanup completed!"
echo "Note: Some resources may take time to fully delete."

15.11.2 Selective Clean Up Commands

Delete specific rules:

# Delete single rule
aws configservice delete-config-rule --config-rule-name s3-bucket-public-read-prohibited

# Delete multiple rules
aws configservice delete-config-rule --config-rule-name rule1
aws configservice delete-config-rule --config-rule-name rule2

Clean up Lambda functions:

# List all Config-related Lambdas
aws lambda list-functions --query 'Functions[?contains(FunctionName, `config-`)]'

# Delete specific function
aws lambda delete-function --function-name config-s3-auto-remediation

Clean up CloudWatch resources:

# Delete specific alarm
aws cloudwatch delete-alarms --alarm-names ConfigDeliveryFailed

# Delete dashboard
aws cloudwatch delete-dashboards --dashboard-names VinaShoesCompliance

15.11.3 Data Retention Considerations

Before Cleanup:

  • Export compliance reports
  • Backup configuration history
  • Document rule configurations
  • Archive audit logs

Data Recovery Options:

  • S3 bucket versioning for history
  • Config snapshots before deletion
  • CloudWatch Logs retention
  • External backup systems

📋 Lưu ý quan trọng khi clean up:

  • Config data không thể khôi phục sau khi xóa
  • Configuration history bị mất vĩnh viễn
  • Compliance reports cần export trước
  • IAM permissions cần kiểm tra kỹ
  • Multi-account setup cần clean up ở tất cả accounts