Skip to main content

AWS Well-Architected Review — automated assessment and PDF report generator

Project description

AWS WAR Lens

Automated AWS Well-Architected Review assessments. Scans your AWS account across all six pillars, produces risk-rated findings, and generates a PDF report — with optional LLM-powered narrative and prioritization.

Features

  • 175 programmatic checks across all 6 Well-Architected pillars
  • Risk-rated findings — CRITICAL / HIGH / MEDIUM / LOW / PASS
  • PDF report with executive summary, top priorities, and cross-finding correlations
  • Multi-region scanning--region all scans every opted-in region in parallel
  • No infrastructure required — runs locally or in Docker against any AWS account

Pillars

Pillar Checks
Security 61
Reliability 44
Operational Excellence 34
Performance Efficiency 14
Sustainability 11
Cost Optimization 11

Installation

pip install aws-war-lens

Note: WeasyPrint (used for PDF generation) requires native system libraries on Linux/macOS. See WeasyPrint installation docs if you hit dependency errors.

Usage

# Scan a single region (security pillar by default)
aws-war-lens --region eu-west-1

# Scan multiple pillars
aws-war-lens --region eu-west-1 --pillars security reliability cost_optimization

# Scan all opted-in regions
aws-war-lens --region all

# Skip LLM analysis (no ANTHROPIC_API_KEY needed)
aws-war-lens --region eu-west-1 --no-llm

# Use a named AWS profile
aws-war-lens --region eu-west-1 --profile myprofile

# Use explicit credentials
aws-war-lens --region eu-west-1 --access-key AKIA... --secret-key xxxx

The PDF report is saved to output/ by default. Use --output <dir> to change it.

Authentication

Credentials are resolved in this order:

  1. --access-key / --secret-key / --session-token flags
  2. --profile named profile from ~/.aws/credentials
  3. AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY environment variables
  4. Default AWS CLI profile
  5. IAM instance profile / ECS task role / Lambda execution role

LLM Analysis

Set ANTHROPIC_API_KEY in your environment (or a .env file) to enable LLM-powered narrative, executive summary, and cross-finding correlation in the report. Without it, the report renders with raw findings only.

export ANTHROPIC_API_KEY=sk-ant-...
aws-war-lens --region eu-west-1

Docker

docker run --rm \
  -e ANTHROPIC_API_KEY=sk-ant-... \
  -e AWS_ACCESS_KEY_ID=... \
  -e AWS_SECRET_ACCESS_KEY=... \
  -e AWS_SESSION_TOKEN=... \
  -v "$(pwd)/output:/app/output" \
  aws-war-lens --region eu-west-1

Available Pillars

Value Description
security IAM, S3, GuardDuty, CloudTrail, KMS, VPC, ACM, and more
reliability Auto Scaling, RDS multi-AZ, backups, Route 53, quotas
performance Instance families, Graviton, DynamoDB, CloudFront, ElastiCache
cost_optimization Idle resources, rightsizing, reserved capacity, orphaned snapshots
operational_excellence CloudWatch alarms, SSM, tagging, CI/CD, ECS configuration
sustainability Graviton adoption, Fargate, auto-scaling, S3 intelligent tiering

IAM Permissions

Option 1 — Recommended (least privilege): Create a dedicated IAM policy using the JSON provided below and attach it to a new user or role.

AWS Console: IAM → Policies → Create policy → JSON tab → paste the policy below → name it AWSScannerReadOnly

AWS CLI:

aws iam create-policy \
  --policy-name AWSScannerReadOnly \
  --policy-document file://policy.json

Option 2 — Use existing credentials: If the credentials you already have (admin, power user, or an existing role) include at least the permissions listed below, you can use them directly without creating a new policy.


Copy IAM policy JSON
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "STSAuthentication",
      "Effect": "Allow",
      "Action": ["sts:GetCallerIdentity"],
      "Resource": "*"
    },
    {
      "Sid": "EC2ReadOnly",
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeRegions", "ec2:DescribeInstances", "ec2:DescribeSecurityGroups",
        "ec2:DescribeVolumes", "ec2:DescribeSnapshots", "ec2:DescribeImages",
        "ec2:DescribeAddresses", "ec2:GetEbsEncryptionByDefault", "ec2:DescribeVpcs",
        "ec2:DescribeSubnets", "ec2:DescribeNetworkAcls", "ec2:DescribeVpcEndpoints",
        "ec2:DescribeFlowLogs", "ec2:DescribeNatGateways", "ec2:DescribePlacementGroups"
      ],
      "Resource": "*"
    },
    {
      "Sid": "IAMReadOnly",
      "Effect": "Allow",
      "Action": [
        "iam:GetAccountSummary", "iam:GetAccountPasswordPolicy", "iam:GetCredentialReport",
        "iam:GenerateCredentialReport", "iam:GetRole", "iam:ListUsers",
        "iam:ListAttachedUserPolicies", "iam:ListUserPolicies", "iam:ListRoles",
        "iam:ListPolicies", "iam:GetPolicyVersion"
      ],
      "Resource": "*"
    },
    {
      "Sid": "S3ReadOnly",
      "Effect": "Allow",
      "Action": [
        "s3:ListAllMyBuckets", "s3:GetAccountPublicAccessBlock", "s3:GetPublicAccessBlock",
        "s3:GetBucketAcl", "s3:GetBucketPolicy", "s3:GetEncryptionConfiguration",
        "s3:GetBucketVersioning", "s3:GetBucketLogging", "s3:GetLifecycleConfiguration",
        "s3:GetReplicationConfiguration", "s3:GetBucketObjectLockConfiguration",
        "s3:GetBucketTagging", "s3:GetBucketAccelerateConfiguration",
        "s3:ListBucketIntelligentTieringConfigurations", "s3:ListBucket"
      ],
      "Resource": "*"
    },
    {
      "Sid": "RDSReadOnly",
      "Effect": "Allow",
      "Action": [
        "rds:DescribeDBInstances", "rds:DescribeDBSnapshots", "rds:DescribeDBClusters",
        "rds:DescribeReservedDBInstances", "rds:DescribeDBProxies"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ECSReadOnly",
      "Effect": "Allow",
      "Action": [
        "ecs:ListClusters", "ecs:DescribeClusters", "ecs:ListServices",
        "ecs:DescribeServices", "ecs:ListTaskDefinitionFamilies", "ecs:DescribeTaskDefinition"
      ],
      "Resource": "*"
    },
    {
      "Sid": "LambdaReadOnly",
      "Effect": "Allow",
      "Action": [
        "lambda:ListFunctions", "lambda:GetAccountSettings", "lambda:GetFunctionConcurrency",
        "lambda:GetFunctionEventInvokeConfig", "lambda:ListTags"
      ],
      "Resource": "*"
    },
    {
      "Sid": "SecretsManagerReadOnly",
      "Effect": "Allow",
      "Action": ["secretsmanager:ListSecrets", "secretsmanager:DescribeSecret"],
      "Resource": "*"
    },
    {
      "Sid": "KMSReadOnly",
      "Effect": "Allow",
      "Action": [
        "kms:ListKeys", "kms:DescribeKey", "kms:GetKeyRotationStatus", "kms:GetKeyPolicy"
      ],
      "Resource": "*"
    },
    {
      "Sid": "GuardDutyReadOnly",
      "Effect": "Allow",
      "Action": ["guardduty:ListDetectors", "guardduty:GetDetector", "guardduty:ListFindings"],
      "Resource": "*"
    },
    {
      "Sid": "SecurityHubReadOnly",
      "Effect": "Allow",
      "Action": ["securityhub:DescribeHub", "securityhub:ListStandardsSubscriptions"],
      "Resource": "*"
    },
    {
      "Sid": "ConfigReadOnly",
      "Effect": "Allow",
      "Action": [
        "config:DescribeConfigurationRecorders", "config:DescribeConfigurationRecorderStatus",
        "config:DescribeConfigRules"
      ],
      "Resource": "*"
    },
    {
      "Sid": "InspectorReadOnly",
      "Effect": "Allow",
      "Action": ["inspector2:BatchGetAccountStatus"],
      "Resource": "*"
    },
    {
      "Sid": "MacieReadOnly",
      "Effect": "Allow",
      "Action": ["macie2:GetMacieSession"],
      "Resource": "*"
    },
    {
      "Sid": "AccessAnalyzerReadOnly",
      "Effect": "Allow",
      "Action": ["access-analyzer:ListAnalyzers"],
      "Resource": "*"
    },
    {
      "Sid": "CloudTrailReadOnly",
      "Effect": "Allow",
      "Action": [
        "cloudtrail:DescribeTrails", "cloudtrail:GetTrailStatus", "cloudtrail:GetEventSelectors"
      ],
      "Resource": "*"
    },
    {
      "Sid": "CloudFrontReadOnly",
      "Effect": "Allow",
      "Action": ["cloudfront:ListDistributions", "cloudfront:GetDistribution"],
      "Resource": "*"
    },
    {
      "Sid": "ACMReadOnly",
      "Effect": "Allow",
      "Action": ["acm:ListCertificates", "acm:DescribeCertificate"],
      "Resource": "*"
    },
    {
      "Sid": "ELBReadOnly",
      "Effect": "Allow",
      "Action": [
        "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeLoadBalancerAttributes",
        "elasticloadbalancing:DescribeTargetGroups", "elasticloadbalancing:DescribeTargetGroupAttributes",
        "elasticloadbalancing:DescribeTargetHealth"
      ],
      "Resource": "*"
    },
    {
      "Sid": "AutoScalingReadOnly",
      "Effect": "Allow",
      "Action": [
        "autoscaling:DescribeAutoScalingGroups", "autoscaling:DescribePolicies",
        "autoscaling:DescribeScheduledActions"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ApplicationAutoScalingReadOnly",
      "Effect": "Allow",
      "Action": [
        "application-autoscaling:DescribeScalableTargets",
        "application-autoscaling:DescribeScalingPolicies"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ElastiCacheReadOnly",
      "Effect": "Allow",
      "Action": ["elasticache:DescribeReplicationGroups"],
      "Resource": "*"
    },
    {
      "Sid": "DynamoDBReadOnly",
      "Effect": "Allow",
      "Action": [
        "dynamodb:ListTables", "dynamodb:DescribeTable", "dynamodb:DescribeContinuousBackups"
      ],
      "Resource": "*"
    },
    {
      "Sid": "EFSReadOnly",
      "Effect": "Allow",
      "Action": ["elasticfilesystem:DescribeFileSystems", "elasticfilesystem:DescribeBackupPolicy"],
      "Resource": "*"
    },
    {
      "Sid": "SQSReadOnly",
      "Effect": "Allow",
      "Action": ["sqs:ListQueues", "sqs:GetQueueAttributes"],
      "Resource": "*"
    },
    {
      "Sid": "Route53ReadOnly",
      "Effect": "Allow",
      "Action": [
        "route53:ListHealthChecks", "route53:ListHostedZones", "route53:ListResourceRecordSets"
      ],
      "Resource": "*"
    },
    {
      "Sid": "BackupReadOnly",
      "Effect": "Allow",
      "Action": ["backup:ListBackupPlans"],
      "Resource": "*"
    },
    {
      "Sid": "ServiceQuotasReadOnly",
      "Effect": "Allow",
      "Action": ["servicequotas:GetServiceQuota"],
      "Resource": "*"
    },
    {
      "Sid": "ECRReadOnly",
      "Effect": "Allow",
      "Action": ["ecr:DescribeRepositories", "ecr:ListImages", "ecr:GetLifecyclePolicy"],
      "Resource": "*"
    },
    {
      "Sid": "CloudWatchReadOnly",
      "Effect": "Allow",
      "Action": ["cloudwatch:DescribeAlarms", "cloudwatch:ListDashboards"],
      "Resource": "*"
    },
    {
      "Sid": "CloudWatchLogsReadOnly",
      "Effect": "Allow",
      "Action": ["logs:DescribeLogGroups"],
      "Resource": "*"
    },
    {
      "Sid": "SSMReadOnly",
      "Effect": "Allow",
      "Action": [
        "ssm:DescribeInstanceInformation", "ssm:DescribeMaintenanceWindows",
        "ssm:ListAssociations", "ssm:DescribeParameters"
      ],
      "Resource": "*"
    },
    {
      "Sid": "SNSReadOnly",
      "Effect": "Allow",
      "Action": ["sns:ListTopics", "sns:GetTopicAttributes"],
      "Resource": "*"
    },
    {
      "Sid": "EventBridgeReadOnly",
      "Effect": "Allow",
      "Action": ["events:ListRules"],
      "Resource": "*"
    },
    {
      "Sid": "CloudFormationReadOnly",
      "Effect": "Allow",
      "Action": ["cloudformation:DescribeStacks"],
      "Resource": "*"
    },
    {
      "Sid": "SyntheticsReadOnly",
      "Effect": "Allow",
      "Action": ["synthetics:DescribeCanaries"],
      "Resource": "*"
    },
    {
      "Sid": "CostExplorerReadOnly",
      "Effect": "Allow",
      "Action": ["ce:ListCostAllocationTags"],
      "Resource": "*"
    },
    {
      "Sid": "SavingsPlansReadOnly",
      "Effect": "Allow",
      "Action": ["savingsplans:DescribeSavingsPlans"],
      "Resource": "*"
    }
  ]
}

Checks that lack permission are reported as Scanner Coverage Gaps in the PDF — they never fail silently.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aws_war_lens-0.1.5.tar.gz (172.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aws_war_lens-0.1.5-py3-none-any.whl (115.8 kB view details)

Uploaded Python 3

File details

Details for the file aws_war_lens-0.1.5.tar.gz.

File metadata

  • Download URL: aws_war_lens-0.1.5.tar.gz
  • Upload date:
  • Size: 172.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for aws_war_lens-0.1.5.tar.gz
Algorithm Hash digest
SHA256 33affeccc0bc9ff5c519aa8f920ddd42f9d2f6fe2cc7a8871c2e8b1c54ac8be8
MD5 607f92b089b21281724cb55c73ecc5fd
BLAKE2b-256 24d9a099323bc3e76cccc78ee9e76997d34f1bbc16187f663a4f1ae1621d57d1

See more details on using hashes here.

File details

Details for the file aws_war_lens-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: aws_war_lens-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 115.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for aws_war_lens-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 e3cb811fba58a61b3452cdbb439ff74148de6ea6aa95eac1d72765a40eec306f
MD5 821f336f30cbce1b400858a981638319
BLAKE2b-256 94287126bbd981401dcdca0502e1f4d6a972d65af815e509e86f56bb263d414c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page