
This project came from a real frustration: Security Hub and GuardDuty surface useful signals, but the gap between "finding detected" and "something was actually done about it" is wide. I built this to close that loop — aggregate findings from all the native AWS detectors, add custom IAM posture checks on top, and wire it to an event-driven remediation path that runs safely by default.
Architecture
The platform has two sides — detection and response — joined by Security Hub as the central ASFF aggregator.
Detection pulls from four native sources that integrate with Security Hub automatically:
- AWS Config — configuration recorder with a required-tags managed rule
- Amazon GuardDuty — threat intelligence against CloudTrail events, VPC Flow Logs, and DNS logs, publishing every 15 minutes
- Amazon Inspector v2 — ECR scan-on-push for HIGH/CRITICAL CVEs; findings routed to Security Hub automatically
- IAM Access Analyzer — cross-account and public resource exposure findings
On top of these, a custom IAM Posture Lambda (Python 3.12, EventBridge-scheduled) performs four additional checks that the native services don't cover: root MFA status, account password policy against a configurable minimum length and complexity, access keys older than a configurable threshold (default 90 days), and inline policies with Action:* / Resource:*. Findings are formatted as ASFF and imported via BatchImportFindings.
Response is handled by EventBridge routing findings in two directions:
- SNS Alerts Topic — KMS-encrypted, receives all findings at or above the configured severity threshold (default: HIGH)
- Remediation Lambda — opt-in, only created when
remediation_patternsis explicitly set. Can disable an IAM access key (iam:UpdateAccessKey → Inactive) or revoke a public SSH/RDP security group ingress rule (ec2:RevokeSecurityGroupIngress). Runs in Safe Mode by default — every execution writes aSIMULATED/EXECUTED/FAILED/SKIPPEDrecord to DynamoDB without touching resources, so you can build confidence in the decision logic before enabling enforce mode.
IAM role separation
The posture and remediation Lambdas have completely separate execution roles. The posture Lambda can read IAM metadata and write to Security Hub — nothing else. The remediation Lambda can disable keys and revoke ingress rules — it has no IAM read permissions at all. Neither role can do what the other does. This is deliberate: limiting blast radius if either function receives unexpected input.
The CI/CD pipeline also uses three separate OIDC roles: a read-only plan role for pull requests, an isolated security-triage role that can invoke exactly one Bedrock inference profile (for AI-assisted PR security review), and a deployment role scoped to only the IAM and service actions the current module set actually requires.
DevSecOps pipeline
Every push and pull request runs five required checks via GitHub Actions before anything can merge:
pytest— unit tests plus property-based tests using Hypothesis that generate arbitrary finding payloads to validate Lambda handler invariants (e.g. aDenystatement can never be flagged as overly-broad regardless ofAction/Resourcevalues)terraform fmt -checkandterraform validateacross both root modules- Checkov (
3.2.526) — IaC scan onmodules/andenvironments/, SARIF output uploaded as artifact - Trivy (
0.69.3) — IaC scan for HIGH/CRITICAL findings - Trivy image scan — demo container built from
app/Dockerfile,--ignore-unfixedflag so only actionable CVEs block the build
AWS credentials are never stored as repository secrets — short-lived tokens are generated per workflow run via GitHub OIDC federation.
Terraform module structure
modules/
├── alerts/ # SNS topic, EventBridge publish policy
├── cicd-oidc/ # GitHub OIDC provider, 3 IAM roles (plan/triage/apply)
├── config/ # Config recorder, required-tags managed rule
├── ecr/ # Immutable tags, scan-on-push repository
├── eventbridge/ # Alert + remediation routing rules, SQS DLQ, retry policy
├── guardduty/ # Detector, 15-minute publishing frequency
├── iam-posture/ # IAM Access Analyzer + posture Lambda + EventBridge schedule
├── inspector/ # ECR scanning enabler
├── remediation/ # Remediation Lambda, DynamoDB audit table, Safe Mode config
├── securityhub/ # Hub enablement, CIS v1.4 standard subscription
└── storage/ # Config history S3 bucket
Stack
AWS Security Hub (CIS v1.4) · GuardDuty · Config · Inspector v2 · IAM Access Analyzer · EventBridge · SNS · DynamoDB · Lambda (Python 3.12) · Amazon ECR · S3 · Terraform · GitHub Actions · Checkov · Trivy · Hypothesis