Structured guidance for AWS CloudFront distributions, WAF web ACLs, Lambda@Edge, CloudFront Functions, Firewall Manager multi-account enforcement, and IAM/IRSA patterns. Covers OAC, cache policies, security headers, managed rule groups, rate limiting, FMS FIRST/MIDDLE/LAST ownership model, and production-ready Terraform generation.
70%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./skills/aws/SKILL.mdStructured guidance for AWS CloudFront, WAF, Lambda@Edge, and multi-account security patterns.
When invoked with no arguments, ask before proceeding:
Q1 — Mode?
What do you need?
1. cloudfront — distributions, OAC, cache policies, security headers, Lambda@Edge
2. waf — web ACLs, managed rule groups, rate limiting, false positive tuning
3. lambda-edge — CloudFront Functions vs Lambda@Edge, viewer/origin events
4. multi-account — Firewall Manager, cross-account OAC, FMS WAF enforcement
5. orgs — Organizations, SCPs, OU design, account vending, Control Tower
6. review — production-readiness review of CloudFront + WAF config
7. terraform — generate a Terraform module scaffold
Enter 1–7 or mode name:Q2 — Context (after mode selected):
Describe the issue or what you want to build (distribution, OAC, cache, edge function):Describe the use case — new WebACL, false positive, adding a rule, or multi-account enforcement:What does the edge function need to do? (auth, URL rewrite, A/B test, dynamic routing):How many accounts? Do you have FMS administrator configured in the security account?Describe what you need — SCP enforcement, OU design, account vending, or Control Tower setup:Invoke with /platform-skills:aws followed by a mode, or describe your problem and the command will route automatically.
/platform-skills:aws cloudfront # CloudFront distributions, OAC, cache, security headers
/platform-skills:aws waf # WAF web ACLs, managed rules, rate limiting
/platform-skills:aws lambda-edge # Lambda@Edge and CloudFront Functions
/platform-skills:aws multi-account # Firewall Manager, cross-account, Organizations
/platform-skills:aws review # Production-readiness review of your config
/platform-skills:aws terraform # Generate Terraform module scaffoldTriggers: distribution, CDN, OAC, cache behavior, price class, CNAME, SSL, geo restriction, origin, CloudFront
Reference: references/aws-cloudfront.md
Steps:
Identify the problem layer:
Check for the common footguns:
CLOUDFRONT scope in us-east-1qualified_arn), not $LATESTus-east-1Provide: problem diagnosis, Terraform snippet, validation steps, rollback plan.
Key Terraform resources:
| Resource | Purpose |
|---|---|
aws_cloudfront_distribution | The distribution |
aws_cloudfront_origin_access_control | OAC (replaces OAI) |
aws_cloudfront_cache_policy | Custom cache key and TTL |
aws_cloudfront_origin_request_policy | What to forward to origin |
aws_cloudfront_response_headers_policy | Security headers |
aws_cloudfront_function | CloudFront Function (JS, viewer events) |
aws_cloudfront_realtime_log_config | Real-time logs to Kinesis |
Triggers: WAF, web ACL, rule group, managed rules, rate limit, Bot Control, CAPTCHA, Challenge, IP set, geo block
Reference: references/aws-waf.md
Steps:
Confirm scope:
CLOUDFRONT → must use us-east-1 provider aliasREGIONAL → same region as the protected resourceClassify the request:
rule_action_override to Count the specific ruleProvide: exact rule block, priority placement, visibility config, logging config.
Baseline rule groups (always include for CloudFront):
# Priority 5 — IP reputation (free)
AWSManagedRulesAmazonIpReputationList
# Priority 10 — Core Rule Set (free)
AWSManagedRulesCommonRuleSet
# Priority 15 — Known bad inputs: Log4Shell, SSRF (free)
AWSManagedRulesKnownBadInputsRuleGroup
# Priority 30 — Rate limit: 2000 req/5min per IP
rate_based_statement { limit = 2000; aggregate_key_type = "IP" }Paid additions (evaluate based on risk):
AWSManagedRulesBotControlRuleSet — bot traffic (Common or Targeted level)AWSManagedRulesATPRuleSet — credential stuffing on login endpointsAWSManagedRulesACFPRuleSet — account creation fraud on registration endpointsTriggers: Lambda@Edge, CloudFront Functions, viewer-request, origin-request, edge function, A/B test, auth at edge, URL rewrite
Reference: references/aws-cloudfront.md → Lambda@Edge section
Decision — CloudFront Functions vs Lambda@Edge:
Need network calls? → Lambda@Edge (CloudFront Functions have no network access)
Need body access? → Lambda@Edge (origin events only)
Need execution > 1ms? → Lambda@Edge
Need viewer-request/response only? → CloudFront Functions (6× cheaper)
Need complex logic / Node modules? → Lambda@Edge
Need dynamic config without deploy?→ CloudFront Functions + KeyValueStore
Simple URL rewrite / header add? → CloudFront Functions
Auth token validation (JWT)? → Lambda@Edge viewer-request
Dynamic origin routing? → Lambda@Edge origin-requestLambda@Edge checklist:
us-east-1publish = true in Terraformqualified_arn (not arn) in lambda_function_associationedgelambda.amazonaws.com AND lambda.amazonaws.com$LATEST version referenceus-east-1Triggers: Firewall Manager, FMS, Organizations, cross-account, OU, security account, delegated admin, centralized WAF
References: references/aws-waf.md → Multi-account section, references/aws-cloudfront.md → Multi-account patterns
Steps:
Confirm prerequisites:
Choose pattern:
| Pattern | When to use |
|---|---|
| Shared CloudFront account | Platform team owns distributions; app teams own origins |
| Per-account distributions + FMS WAF | App team autonomy; security team enforces WAF centrally |
| FMS audit mode first | Existing org — identify violations before enforcing |
FMS WAF policy structure:
preProcessRuleGroups (priority 0–19) — security team, lockedpostProcessRuleGroups (priority 80+) — security team, lockedCross-account OAC pattern (shared CDN account):
AWS:SourceArn scoped to distribution ARN works cross-accountProvide: FMS policy Terraform, OAC cross-account bucket policy, SCP to enforce WAF attachment.
Triggers: Organizations, SCPs, OU, account vending, Control Tower, delegated admin, account factory, guardrails
Steps:
Identify the request:
OU design principles:
| OU | Accounts | SCP stance |
|---|---|---|
| Security | Log archive, Audit | Deny all except security tooling |
| Infrastructure | Network, Shared services | Restricted; platform team only |
| Workloads/Prod | Production app accounts | Deny risky actions (delete trail, disable GuardDuty) |
| Workloads/SDLC | Dev, staging accounts | More permissive; deny prod data access |
| Sandbox | Developer personal accounts | Deny spend > threshold; deny production-touching actions |
Essential SCPs (apply at root or Workloads OU):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyLeavingOrg",
"Effect": "Deny",
"Action": "organizations:LeaveOrganization",
"Resource": "*"
},
{
"Sid": "DenyDisableCloudTrail",
"Effect": "Deny",
"Action": ["cloudtrail:StopLogging", "cloudtrail:DeleteTrail"],
"Resource": "*"
},
{
"Sid": "DenyDisableGuardDuty",
"Effect": "Deny",
"Action": ["guardduty:DeleteDetector", "guardduty:DisassociateFromMasterAccount"],
"Resource": "*"
},
{
"Sid": "DenyRootUser",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringLike": { "aws:PrincipalArn": "arn:aws:iam::*:root" }
}
}
]
}Account vending (Account Factory for Terraform — AFT):
module "account_request" {
source = "github.com/aws-ia/terraform-aws-control_tower_account_factory"
control_tower_parameters = {
AccountEmail = "platform+prod-payments@company.com"
AccountName = "prod-payments"
ManagedOrganizationalUnit = "Workloads/Prod"
SSOUserEmail = "admin@company.com"
}
account_tags = { env = "prod", team = "payments", cost-center = "eng" }
account_customizations_name = "prod-baseline"
}Delegated administrators — always delegate to a dedicated account, never the management account:
aws organizations register-delegated-administrator --service-principal guardduty.amazonaws.com--service-principal securityhub.amazonaws.comValidate SCP effect before attaching:
# Simulate an action under the SCP (requires aws-cli v2)
aws iam simulate-custom-policy \
--policy-input-list file://scp.json \
--action-names cloudtrail:StopLogging \
--resource-arns "*"→ Next: Run /platform-skills:aws review to audit the account configuration, or /platform-skills:compliance checklist to validate SOC 2 controls across the org.
Triggers: review, production ready, production checklist, audit my CloudFront, audit my WAF
Structured production-readiness review. Ask for:
Then evaluate against:
CloudFront:
https-only or redirect-to-httpsTLSv1.2_2021qualified_arn used, publish = trueWAF:
CLOUDFRONT, provider is us_east_1Multi-account:
Report: CRITICAL issues (must fix before launch) → WARNINGS (should fix) → INFORMATIONAL.
Triggers: generate terraform, scaffold, create module, write terraform for
Generate a Terraform module scaffold using best practices. Ask:
Then generate complete module files:
<module-name>/
├── versions.tf # terraform{} block + required_providers + provider aliases
├── variables.tf # typed inputs with validation{} blocks
├── locals.tf # computed values, name prefixes
├── main.tf # all resources
└── outputs.tf # ARNs, IDs, domain names with descriptionsNon-negotiable patterns in every generated module:
CLOUDFRONT scope WebACLs must be created in us-east-1. Any other region returns WAFInvalidParameterException. Use a provider alias aws.us_east_1 explicitlyaws_cloudfront_origin_access_control). OAI does not support non-S3 origins or newer signing protocols$LATEST — $LATEST is not a publishable version and cannot be associated with CloudFront. Set publish = true in the resource and reference aws_lambda_function.this.qualified_arnus-east-1, regardless of where the distribution serves traffic# versions.tf — always pin providers
terraform {
required_version = ">= 1.7.0"
required_providers {
aws = { source = "hashicorp/aws"; version = ">= 5.0.0" }
}
}
# variables.tf — always include description and type
variable "name" {
type = string
description = "Name prefix applied to all resources."
validation {
condition = length(var.name) <= 32
error_message = "Name must be 32 characters or fewer."
}
}
variable "default_tags" {
type = map(string)
description = "Tags applied to all resources via provider default_tags."
default = {}
}
# Provider — always use default_tags
provider "aws" {
region = var.aws_region
default_tags { tags = var.default_tags }
}
# CloudFront WAF / Lambda@Edge — always add us-east-1 alias
provider "aws" {
alias = "us_east_1"
region = "us-east-1"
default_tags { tags = var.default_tags }
}
# outputs.tf — always include description
output "distribution_arn" {
description = "ARN of the CloudFront distribution."
value = aws_cloudfront_distribution.this.arn
}nitinjain999/platform-skills
c2e75b7
Also appears in
since Oct 19, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.