You are viewing a preview of this lesson. Sign in to start learning
Back to Mastering AWS

Security, Governance & Observability

Master zero-trust security, compliance automation, observability, and cost optimization for production systems

AWS Security, Governance & Observability

Master AWS security, governance, and observability with free flashcards and spaced repetition practice. This lesson covers IAM policies, CloudWatch monitoring, CloudTrail auditing, AWS Config compliance, and AWS Organizationsβ€”essential concepts for the AWS Solutions Architect and Security Specialty certifications.

Welcome πŸ”

Security, governance, and observability form the foundation of well-architected AWS infrastructure. Without proper identity management, monitoring, and compliance mechanisms, even the most sophisticated applications become vulnerable to breaches, cost overruns, and regulatory violations.

This lesson takes you through the core AWS services that protect your infrastructure, ensure compliance, and provide visibility into system behavior. You'll learn practical implementation patterns, common misconfigurations to avoid, and how these services work together to create a comprehensive security posture.

Core Concepts πŸ’‘

Identity and Access Management (IAM) πŸ”‘

AWS IAM controls who can access your AWS resources and what they can do with them. It's the first line of defense in your security architecture.

Key IAM Components:

ComponentPurposeBest Practice
UsersIndividual identitiesEnable MFA for all users
GroupsCollection of usersAssign permissions to groups, not users
RolesTemporary credentials for services/appsUse roles instead of access keys
PoliciesJSON documents defining permissionsFollow least privilege principle

IAM Policy Structure:

Every IAM policy follows this JSON structure:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "203.0.113.0/24"
        }
      }
    }
  ]
}

Policy Components Breakdown:

  • Effect: Allow or Deny (explicit deny always wins)
  • Action: What operations are permitted (e.g., s3:GetObject, ec2:*)
  • Resource: Which AWS resources the policy applies to (ARN format)
  • Condition: Optional constraints (IP addresses, time of day, MFA, etc.)

πŸ’‘ Tip: Use the AWS Policy Simulator to test policies before deploying them to production.

IAM Best Practices:

  1. Root account protection: Never use root for daily tasks; enable MFA
  2. Least privilege: Grant only the permissions needed for a specific task
  3. Role-based access: Use IAM roles for EC2 instances and Lambda functions
  4. Password policies: Enforce strong passwords with rotation requirements
  5. Access key rotation: Rotate credentials regularly (max 90 days)
  6. CloudTrail logging: Monitor all IAM actions
IAM PERMISSION EVALUATION FLOW

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  Is there an explicit DENY?     β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
           β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”
           β”‚               β”‚
        β”Œβ”€β”€β”΄β”€β”€β”         β”Œβ”€β”€β”΄β”€β”€β”
        β”‚ YES β”‚         β”‚ NO  β”‚
        β””β”€β”€β”¬β”€β”€β”˜         β””β”€β”€β”¬β”€β”€β”˜
           β”‚               β”‚
           β–Ό               β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  ❌ DENY β”‚   β”‚ Is there an    β”‚
    β”‚          β”‚   β”‚ explicit ALLOW?β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚               β”‚
                 β”Œβ”€β”€β”΄β”€β”€β”         β”Œβ”€β”€β”΄β”€β”€β”
                 β”‚ YES β”‚         β”‚ NO  β”‚
                 β””β”€β”€β”¬β”€β”€β”˜         β””β”€β”€β”¬β”€β”€β”˜
                    β”‚               β”‚
                    β–Ό               β–Ό
             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
             β”‚ βœ… ALLOW β”‚    β”‚  ❌ DENY β”‚
             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚(implicit)β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

AWS CloudWatch πŸ“Š

Amazon CloudWatch is AWS's comprehensive monitoring and observability service. It collects metrics, logs, and events from your AWS resources and applications.

CloudWatch Core Services:

ServicePurposeUse Case
MetricsNumerical data points over timeCPU utilization, network traffic
LogsText-based log file storageApplication logs, VPC flow logs
AlarmsAutomated actions based on thresholdsAuto-scaling triggers, notifications
DashboardsVisual representation of metricsOperations center displays
Events/EventBridgeEvent-driven automationRespond to AWS API calls

CloudWatch Metrics Hierarchy:

Namespace (AWS/EC2)
  |
  β”œβ”€ Metric Name (CPUUtilization)
  |   |
  |   β”œβ”€ Dimension: InstanceId=i-1234567890abcdef0
  |   |   └─ Data Points: [(timestamp, value, unit)]
  |   |
  |   └─ Dimension: InstanceType=t3.micro
  |       └─ Data Points: [(timestamp, value, unit)]

Creating a CloudWatch Alarm:

import boto3

cloudwatch = boto3.client('cloudwatch')

cloudwatch.put_metric_alarm(
    AlarmName='HighCPUAlarm',
    ComparisonOperator='GreaterThanThreshold',
    EvaluationPeriods=2,
    MetricName='CPUUtilization',
    Namespace='AWS/EC2',
    Period=300,
    Statistic='Average',
    Threshold=80.0,
    ActionsEnabled=True,
    AlarmActions=['arn:aws:sns:us-east-1:123456789012:my-topic'],
    Dimensions=[
        {
            'Name': 'InstanceId',
            'Value': 'i-1234567890abcdef0'
        }
    ]
)

CloudWatch Logs Insights Query:

CloudWatch Logs Insights uses a SQL-like query language:

fields @timestamp, @message
| filter @message like /ERROR/
| stats count() by bin(5m)
| sort @timestamp desc
| limit 20

πŸ’‘ Tip: Use CloudWatch Logs Insights to search and analyze logs without exporting them. It's significantly faster than downloading logs locally.

CloudWatch Agent for Custom Metrics:

{
  "metrics": {
    "namespace": "MyApp/Performance",
    "metrics_collected": {
      "mem": {
        "measurement": [
          {"name": "mem_used_percent", "rename": "MemoryUtilization", "unit": "Percent"}
        ],
        "metrics_collection_interval": 60
      },
      "disk": {
        "measurement": [
          {"name": "used_percent", "rename": "DiskUtilization", "unit": "Percent"}
        ],
        "metrics_collection_interval": 60
      }
    }
  }
}

AWS CloudTrail πŸ”

AWS CloudTrail records AWS API calls and related events for your account. It's your audit logβ€”essential for security analysis, compliance, and troubleshooting.

What CloudTrail Captures:

  • Who: IAM user/role that made the request
  • What: API action performed (e.g., RunInstances, PutObject)
  • When: Timestamp of the request
  • Where: Source IP address and AWS region
  • Result: Success or failure with error codes

CloudTrail Event Example:

{
  "eventVersion": "1.08",
  "userIdentity": {
    "type": "IAMUser",
    "principalId": "AIDACKCEVSQ6C2EXAMPLE",
    "arn": "arn:aws:iam::123456789012:user/Alice",
    "accountId": "123456789012",
    "userName": "Alice"
  },
  "eventTime": "2024-01-15T10:30:00Z",
  "eventSource": "s3.amazonaws.com",
  "eventName": "DeleteBucket",
  "awsRegion": "us-east-1",
  "sourceIPAddress": "203.0.113.42",
  "requestParameters": {
    "bucketName": "my-important-bucket"
  },
  "responseElements": null,
  "errorCode": "BucketNotEmpty",
  "errorMessage": "The bucket you tried to delete is not empty"
}

CloudTrail Trail Types:

Trail TypeScopeUse Case
Management EventsControl plane operationsTrack resource creation/deletion
Data EventsResource-level operationsS3 object access, Lambda invocations
Insights EventsUnusual activity detectionAnomaly detection (requires additional cost)

Creating a Multi-Region Trail with Terraform:

resource "aws_cloudtrail" "main" {
  name                          = "organization-trail"
  s3_bucket_name                = aws_s3_bucket.cloudtrail.id
  include_global_service_events = true
  is_multi_region_trail         = true
  enable_log_file_validation    = true
  
  event_selector {
    read_write_type           = "All"
    include_management_events = true

    data_resource {
      type   = "AWS::S3::Object"
      values = ["arn:aws:s3:::sensitive-bucket/*"]
    }
  }
}

πŸ’‘ Tip: Enable log file validation to ensure CloudTrail logs haven't been tampered withβ€”critical for compliance.

AWS Config πŸ“‹

AWS Config continuously monitors and records AWS resource configurations. It evaluates whether resources comply with desired configurations and tracks changes over time.

AWS Config Workflow:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           AWS CONFIG WORKFLOW                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

    πŸ“¦ AWS Resource Created/Modified
           |
           ↓
    πŸ” Config Records Configuration Snapshot
           |
           ↓
    πŸ“Š Config Stores in S3 Bucket
           |
           ↓
    πŸ“ Config Rules Evaluate Compliance
           |
      β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”
      ↓         ↓
   βœ… Compliant  ❌ Non-Compliant
      |         |
      |         ↓
      |    πŸ”” SNS Notification
      |         |
      |         ↓
      |    πŸ”§ Auto-Remediation (optional)
      |         |
      β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
           ↓
    πŸ“ˆ Compliance Dashboard Updated

AWS Config Rules Examples:

RulePurposeRemediation
encrypted-volumesEnsure EBS volumes are encryptedEnable encryption on non-compliant volumes
s3-bucket-public-read-prohibitedBlock public S3 bucketsRemove public access permissions
rds-storage-encryptedRequire encrypted RDS instancesSnapshot, recreate with encryption
required-tagsEnforce tagging standardsApply missing tags automatically
vpc-flow-logs-enabledEnsure VPC loggingEnable flow logs for non-compliant VPCs

Creating a Custom Config Rule:

import boto3
import json

config = boto3.client('config')

config.put_config_rule(
    ConfigRule={
        'ConfigRuleName': 'require-ec2-instance-tags',
        'Description': 'Ensures EC2 instances have required tags',
        'Source': {
            'Owner': 'AWS',
            'SourceIdentifier': 'REQUIRED_TAGS'
        },
        'InputParameters': json.dumps({
            'tag1Key': 'Environment',
            'tag2Key': 'Owner',
            'tag3Key': 'CostCenter'
        }),
        'Scope': {
            'ComplianceResourceTypes': [
                'AWS::EC2::Instance'
            ]
        },
        'ConfigRuleState': 'ACTIVE'
    }
)

Config Aggregator for Multi-Account Visibility:

{
  "ConfigurationAggregatorName": "OrganizationAggregator",
  "OrganizationAggregationSource": {
    "RoleArn": "arn:aws:iam::123456789012:role/ConfigAggregatorRole",
    "AwsRegions": ["us-east-1", "us-west-2", "eu-west-1"],
    "AllAwsRegions": false
  }
}

AWS Organizations 🏒

AWS Organizations enables central governance and management across multiple AWS accounts. It provides consolidated billing, hierarchical account structure, and policy-based access controls.

Organization Hierarchy:

                    🏒 Root
                       |
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚              β”‚              β”‚
    πŸ“ Production   πŸ“ Development  πŸ“ Security
        |              |              |
    β”Œβ”€β”€β”€β”΄β”€β”€β”€β”      β”Œβ”€β”€β”€β”΄β”€β”€β”€β”         β”‚
    β”‚       β”‚      β”‚       β”‚         β”‚
  πŸ’Ό App1 πŸ’Ό App2 πŸ’Ό Test1 πŸ’Ό Test2  πŸ” Audit

Service Control Policies (SCPs):

SCPs are JSON policies that set maximum permissions for accounts in an OU (Organizational Unit). Even if an IAM policy grants access, an SCP can deny it.

SCP Example - Deny Regions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": [
            "us-east-1",
            "us-west-2",
            "eu-west-1"
          ]
        }
      }
    }
  ]
}

SCP Example - Prevent Root User Access:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "StringLike": {
          "aws:PrincipalArn": "arn:aws:iam::*:root"
        }
      }
    }
  ]
}

πŸ’‘ Tip: SCPs affect all users and roles in an account, including administrators. Always test in a non-production environment first.

Organizations Best Practices:

  1. Separate accounts by workload: Production, development, security, logging
  2. Use SCPs at OU level: Apply policies to groups of accounts
  3. Centralize logging: Send CloudTrail and Config data to a security account
  4. Enable CloudTrail at organization level: Automatic for all accounts
  5. Tag-based cost allocation: Track spending by project/team

AWS Security Hub πŸ›‘οΈ

AWS Security Hub aggregates security findings from multiple AWS services and third-party tools into a single dashboard. It provides automated compliance checks against industry standards.

Security Hub Integrations:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         AWS SECURITY HUB                    β”‚
β”‚    (Central Security Dashboard)             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚          β”‚          β”‚          β”‚
    β–Ό          β–Ό          β–Ό          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚GuardDutyβ”‚ β”‚Inspectorβ”‚ β”‚ Macie  β”‚ β”‚ Config β”‚
β”‚Threats β”‚ β”‚Vulns    β”‚ β”‚Data    β”‚ β”‚Complianceβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Security Standards Supported:

  • CIS AWS Foundations Benchmark: Industry best practices
  • PCI DSS: Payment card industry standards
  • AWS Foundational Security Best Practices: AWS-specific recommendations

Example Security Hub Finding:

{
  "SchemaVersion": "2018-10-08",
  "Id": "arn:aws:securityhub:us-east-1:123456789012:finding/...",
  "ProductArn": "arn:aws:securityhub:us-east-1::product/aws/guardduty",
  "GeneratorId": "arn:aws:guardduty:us-east-1:123456789012:detector/...",
  "AwsAccountId": "123456789012",
  "Types": ["TTPs/Initial Access/UnauthorizedAccess:IAMUser-InstanceCredentialExfiltration"],
  "CreatedAt": "2024-01-15T10:30:00.000Z",
  "UpdatedAt": "2024-01-15T10:30:00.000Z",
  "Severity": {
    "Product": 8,
    "Label": "HIGH",
    "Normalized": 70
  },
  "Title": "Unusual API call from EC2 instance",
  "Description": "EC2 instance credentials used from external IP",
  "Remediation": {
    "Recommendation": {
      "Text": "Rotate instance credentials and investigate access"
    }
  }
}

AWS Systems Manager πŸ”§

AWS Systems Manager provides unified operations management for AWS and on-premises resources. It includes capabilities for patching, configuration management, and operational insights.

Key Systems Manager Features:

FeaturePurposeCommon Use
Session ManagerBrowser-based shell accessConnect to EC2 without SSH keys
Patch ManagerAutomated OS patchingSchedule monthly security updates
Parameter StoreSecure configuration storageStore database passwords, API keys
State ManagerMaintain configuration stateEnsure software always installed
Run CommandExecute commands at scaleInstall software on 100s of instances

Parameter Store vs. Secrets Manager:

FeatureParameter StoreSecrets Manager
CostFree (standard), $0.05/advanced$0.40/secret/month
RotationManualAutomatic (Lambda-based)
Size Limit4KB (standard), 8KB (advanced)64KB
EncryptionOptional (KMS)Always encrypted (KMS)
Best ForConfig values, non-sensitive dataDatabase credentials, API keys

Retrieving a Secure Parameter:

import boto3

ssm = boto3.client('ssm')

response = ssm.get_parameter(
    Name='/myapp/database/password',
    WithDecryption=True
)

db_password = response['Parameter']['Value']

Run Command Example:

aws ssm send-command \
    --document-name "AWS-RunShellScript" \
    --targets "Key=tag:Environment,Values=Production" \
    --parameters 'commands=["sudo yum update -y","sudo systemctl restart nginx"]' \
    --comment "Apply security patches to production web servers"

AWS Trusted Advisor βœ…

AWS Trusted Advisor provides real-time guidance to help you provision resources following AWS best practices. It checks your AWS environment across five categories.

Trusted Advisor Categories:

        TRUSTED ADVISOR CHECK CATEGORIES

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ’° Cost      β”‚  β”‚ πŸ”’ Security  β”‚  β”‚ ⚑ Performanceβ”‚
β”‚ Optimization β”‚  β”‚              β”‚  β”‚              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚β€’Idle RDS DBs β”‚  β”‚β€’S3 public    β”‚  β”‚β€’High util EC2β”‚
β”‚β€’Underused    β”‚  β”‚β€’IAM keys old β”‚  β”‚β€’EBS IOPS     β”‚
β”‚  EBS volumes β”‚  β”‚β€’Security     β”‚  β”‚β€’CloudFront   β”‚
β”‚β€’Reserved Instβ”‚  β”‚  groups open β”‚  β”‚  config      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ›‘οΈ Fault     β”‚  β”‚ πŸ“Š Service   β”‚
β”‚ Tolerance    β”‚  β”‚ Limits       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚β€’EBS snapshotsβ”‚  β”‚β€’VPC limits   β”‚
β”‚β€’Multi-AZ RDS β”‚  β”‚β€’EC2 on-demandβ”‚
β”‚β€’ELB health   β”‚  β”‚β€’IAM groups   β”‚
β”‚β€’Route 53     β”‚  β”‚β€’S3 buckets   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ’‘ Tip: Business and Enterprise support plans get access to all Trusted Advisor checks. Basic/Developer plans only see 7 core checks.

Examples πŸ“

Example 1: Implementing Least Privilege with IAM Policies

Scenario: You need to grant a developer read-only access to S3 buckets in the development environment, but not production.

Poorly Designed Policy (Too Permissive):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": "*"
    }
  ]
}

⚠️ Problem: This grants full S3 access to all buckets, including production data and the ability to delete objects.

Well-Designed Policy (Least Privilege):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::dev-*",
        "arn:aws:s3:::dev-*/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "us-east-1"
        }
      }
    },
    {
      "Effect": "Deny",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::prod-*",
        "arn:aws:s3:::prod-*/*"
      ]
    }
  ]
}

βœ… Improvements:

  • Only read actions (no write/delete)
  • Limited to buckets starting with "dev-"
  • Explicit deny for production buckets
  • Region restriction

Example 2: Setting Up Multi-Account CloudTrail Logging

Scenario: Your organization has 50 AWS accounts. You need centralized audit logging with tamper-proof storage.

Architecture:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         SECURITY ACCOUNT (123456789012)         β”‚
β”‚                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚   CloudTrail S3 Bucket                β”‚     β”‚
β”‚  β”‚   (organization-cloudtrail-logs)      β”‚     β”‚
β”‚  β”‚   β€’ MFA Delete enabled                β”‚     β”‚
β”‚  β”‚   β€’ Object Lock enabled               β”‚     β”‚
β”‚  β”‚   β€’ Encryption: KMS                   β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                    ↑                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚                β”‚                β”‚
    β–Ό                β–Ό                β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚Account β”‚      β”‚Account β”‚      β”‚Account β”‚
β”‚  001   β”‚      β”‚  002   β”‚  ... β”‚  050   β”‚
β”‚        β”‚      β”‚        β”‚      β”‚        β”‚
β”‚CloudTrail      β”‚CloudTrail      β”‚CloudTrail
β”‚ (disabled,     β”‚ (disabled,     β”‚ (disabled,
β”‚ org trail      β”‚ org trail      β”‚ org trail
β”‚ covers it)     β”‚ covers it)     β”‚ covers it)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Implementation Steps:

Step 1: Create S3 Bucket in Security Account

aws s3 mb s3://organization-cloudtrail-logs --region us-east-1

Step 2: Apply Bucket Policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSCloudTrailAclCheck",
      "Effect": "Allow",
      "Principal": {"Service": "cloudtrail.amazonaws.com"},
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::organization-cloudtrail-logs"
    },
    {
      "Sid": "AWSCloudTrailWrite",
      "Effect": "Allow",
      "Principal": {"Service": "cloudtrail.amazonaws.com"},
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::organization-cloudtrail-logs/AWSLogs/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}

Step 3: Create Organization Trail

aws cloudtrail create-trail \
    --name organization-trail \
    --s3-bucket-name organization-cloudtrail-logs \
    --is-multi-region-trail \
    --is-organization-trail \
    --enable-log-file-validation

aws cloudtrail start-logging --name organization-trail

Step 4: Enable S3 Object Lock (Compliance Mode)

aws s3api put-object-lock-configuration \
    --bucket organization-cloudtrail-logs \
    --object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Years":7}}}'

βœ… Result: All 50 accounts now have centralized, immutable audit logs stored for 7 years (meeting most compliance requirements).

Example 3: Automated Compliance Remediation with AWS Config

Scenario: Your security team requires all S3 buckets to have encryption enabled and public access blocked. You want automatic remediation.

Step 1: Deploy Config Rules

## CloudFormation template
Resources:
  S3EncryptionRule:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: s3-bucket-server-side-encryption-enabled
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
      Scope:
        ComplianceResourceTypes:
          - AWS::S3::Bucket

  S3PublicAccessRule:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: s3-bucket-public-read-prohibited
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED
      Scope:
        ComplianceResourceTypes:
          - AWS::S3::Bucket

Step 2: Create Remediation Lambda Function

import boto3
import json

s3 = boto3.client('s3')

def lambda_handler(event, context):
    # Extract bucket name from Config event
    config_item = json.loads(event['configurationItem'])
    bucket_name = config_item['resourceName']
    
    # Enable default encryption
    try:
        s3.put_bucket_encryption(
            Bucket=bucket_name,
            ServerSideEncryptionConfiguration={
                'Rules': [{
                    'ApplyServerSideEncryptionByDefault': {
                        'SSEAlgorithm': 'AES256'
                    },
                    'BucketKeyEnabled': True
                }]
            }
        )
        
        # Block public access
        s3.put_public_access_block(
            Bucket=bucket_name,
            PublicAccessBlockConfiguration={
                'BlockPublicAcls': True,
                'IgnorePublicAcls': True,
                'BlockPublicPolicy': True,
                'RestrictPublicBuckets': True
            }
        )
        
        return {
            'statusCode': 200,
            'body': f'Remediated bucket: {bucket_name}'
        }
    except Exception as e:
        print(f"Error remediating {bucket_name}: {str(e)}")
        raise

Step 3: Configure Auto-Remediation

aws configservice put-remediation-configurations \
    --remediation-configurations '[
      {
        "ConfigRuleName": "s3-bucket-server-side-encryption-enabled",
        "TargetType": "SSM_DOCUMENT",
        "TargetIdentifier": "AWS-PublishSNSNotification",
        "Automatic": true,
        "MaximumAutomaticAttempts": 3,
        "RetryAttemptSeconds": 60
      }
    ]'

βœ… Result: Any new S3 bucket created without encryption is automatically remediated within 60 seconds.

Example 4: Cross-Account CloudWatch Dashboards

Scenario: Your operations team needs a single dashboard showing metrics from 10 different AWS accounts.

Solution Using CloudWatch Cross-Account Observability:

Step 1: Set Up Monitoring Account as Sink

## In monitoring account (999999999999)
aws oam create-sink \
    --name central-observability-sink \
    --tags Key=Environment,Value=Production

Step 2: Create Sink Policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::111111111111:root",
          "arn:aws:iam::222222222222:root",
          "arn:aws:iam::333333333333:root"
        ]
      },
      "Action": [
        "oam:CreateLink",
        "oam:UpdateLink"
      ],
      "Resource": "*",
      "Condition": {
        "ForAllValues:StringEquals": {
          "oam:ResourceTypes": [
            "AWS::CloudWatch::Metric",
            "AWS::Logs::LogGroup"
          ]
        }
      }
    }
  ]
}

Step 3: Link Source Accounts

## In each source account (111111111111, 222222222222, etc.)
aws oam create-link \
    --label-template '$AccountName-$Region' \
    --resource-types 'AWS::CloudWatch::Metric' 'AWS::Logs::LogGroup' \
    --sink-identifier 'arn:aws:oam:us-east-1:999999999999:sink/abc123'

Step 4: Create Unified Dashboard

{
  "widgets": [
    {
      "type": "metric",
      "properties": {
        "metrics": [
          [ { "expression": "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)", "id": "e1", "accountId": "111111111111" } ],
          [ { "expression": "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)", "id": "e2", "accountId": "222222222222" } ],
          [ { "expression": "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)", "id": "e3", "accountId": "333333333333" } ]
        ],
        "region": "us-east-1",
        "title": "Cross-Account EC2 CPU Utilization",
        "period": 300
      }
    }
  ]
}

βœ… Result: Single dashboard shows real-time metrics from all 10 accounts without manual switching.

Common Mistakes ⚠️

1. Overly Permissive IAM Policies

❌ Mistake:

{
  "Effect": "Allow",
  "Action": "*",
  "Resource": "*"
}

βœ… Fix: Always specify exact actions and resources:

{
  "Effect": "Allow",
  "Action": [
    "s3:GetObject",
    "s3:PutObject"
  ],
  "Resource": "arn:aws:s3:::my-app-bucket/*"
}

2. Not Enabling CloudTrail Log File Validation

❌ Mistake: Creating trails without log file validation allows attackers to modify audit logs.

βœ… Fix: Always enable validation:

aws cloudtrail create-trail \
    --name my-trail \
    --s3-bucket-name my-bucket \
    --enable-log-file-validation

3. Ignoring CloudWatch Alarm States

❌ Mistake: Setting alarms to "INSUFFICIENT_DATA" action as OK state:

AlarmActions=['arn:aws:sns:us-east-1:123456789012:my-topic'],
InsufficientDataActions=[]  # Missing!

βœ… Fix: Treat insufficient data as a problem:

AlarmActions=['arn:aws:sns:us-east-1:123456789012:my-topic'],
InsufficientDataActions=['arn:aws:sns:us-east-1:123456789012:my-topic']

4. Using Root Account for Daily Operations

❌ Mistake: Logging in with root account credentials for routine tasks.

βœ… Fix:

  • Create IAM users with appropriate permissions
  • Enable MFA on root account
  • Store root credentials in a secure location (password manager)
  • Use root only for account-level tasks (billing, support plan changes)

5. Not Aggregating Config Data Across Accounts

❌ Mistake: Checking compliance in each account individuallyβ€”time-consuming and error-prone.

βœ… Fix: Use Config Aggregators:

aws configservice put-configuration-aggregator \
    --configuration-aggregator-name OrgAggregator \
    --organization-aggregation-source RoleArn=arn:aws:iam::123456789012:role/ConfigRole,AllAwsRegions=true

6. Storing Secrets in Parameter Store Without Encryption

❌ Mistake:

aws ssm put-parameter \
    --name /myapp/db/password \
    --value "plaintext_password" \
    --type String  # Not encrypted!

βœ… Fix: Use SecureString with KMS:

aws ssm put-parameter \
    --name /myapp/db/password \
    --value "secure_password" \
    --type SecureString \
    --key-id alias/aws/ssm

7. Not Setting CloudWatch Log Retention

❌ Mistake: Leaving logs with infinite retention leads to unnecessary costs.

βœ… Fix: Set appropriate retention periods:

logs = boto3.client('logs')
logs.put_retention_policy(
    logGroupName='/aws/lambda/my-function',
    retentionInDays=30  # or 90, 180, 365 based on requirements
)

8. Forgetting to Enable GuardDuty in All Regions

❌ Mistake: Enabling GuardDuty only in your primary regionβ€”threats can come from anywhere.

βœ… Fix: Enable in all active regions:

for region in us-east-1 us-west-2 eu-west-1 ap-southeast-1; do
  aws guardduty create-detector --enable --region $region
done

Key Takeaways 🎯

πŸ“‹ Quick Reference Card

ServicePrimary PurposeKey Feature
IAMIdentity & access controlPolicies, roles, MFA
CloudWatchMonitoring & observabilityMetrics, logs, alarms
CloudTrailAudit loggingAPI call recording
ConfigConfiguration complianceRules, remediation
OrganizationsMulti-account managementSCPs, consolidated billing
Security HubCentralized securityFinding aggregation
Systems ManagerOperations managementParameter Store, patching
Trusted AdvisorBest practice checksCost, security recommendations

Security Best Practices:

  1. βœ… Enable MFA on all accounts (especially root)
  2. βœ… Use IAM roles instead of access keys
  3. βœ… Enable CloudTrail in all regions with log validation
  4. βœ… Encrypt all data at rest and in transit
  5. βœ… Implement least privilege access
  6. βœ… Use SCPs to enforce organization-wide restrictions
  7. βœ… Set up automated Config remediation
  8. βœ… Monitor Security Hub findings daily
  9. βœ… Rotate credentials every 90 days
  10. βœ… Tag all resources for accountability

Monitoring Essentials:

  • πŸ“Š Create dashboards for business-critical metrics
  • πŸ”” Set up alarms with appropriate thresholds
  • πŸ“ Centralize logs in a dedicated security account
  • πŸ” Use Logs Insights for rapid troubleshooting
  • πŸ“ˆ Enable detailed monitoring for critical resources

Compliance Fundamentals:

  • πŸ“‹ Deploy Config rules for your industry standards
  • πŸ”„ Enable automatic remediation where possible
  • πŸ“Š Use Config Aggregators for multi-account visibility
  • πŸ›‘οΈ Subscribe to Security Hub security standards
  • πŸ“… Schedule regular compliance reviews

🧠 Memory Device - The "COPS" Framework:

CloudTrail = Captures API calls (audit trail)
Organizations = Oversees multiple accounts
Parameter Store = Preserves configuration securely
Security Hub = Summarizes security findings

πŸ’‘ Pro Tip: Always implement security in layers (defense in depth). No single service provides complete protectionβ€”use IAM + CloudTrail + Config + GuardDuty + Security Hub together.

πŸ“š Further Study

  1. AWS Security Best Practices: https://aws.amazon.com/architecture/security-identity-compliance/
  2. AWS Well-Architected Framework - Security Pillar: https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/welcome.html
  3. AWS Config Developer Guide: https://docs.aws.amazon.com/config/latest/developerguide/WhatIsConfig.html

Ready to test your knowledge? Complete the practice questions below to reinforce these AWS security, governance, and observability concepts! πŸš€