โ† AWS Well-Architected Audit

Setup guide

Everything you must provision before this skill can run โ€” the exact credentials, permissions, and where to click. Links go to the official consoles and docs, which stay current.

Some setupโ‰ˆ 25-45 minaws

Provision a dedicated read-only AWS audit principal (IAM role or IAM Identity Center permission set) carrying the SecurityAudit and ViewOnlyAccess managed policies plus a small supplemental policy for Cost Explorer, Compute Optimizer, Resource Groups Tagging, Service Quotas and Support, activate IAM access to Billing data, opt in to Compute Optimizer, and configure AWS CLI v2 (plus jq) with a named profile for that principal.

You need to already have

  • An AWS account you can administer, or the management (payer) account if the audit scope is an AWS Organization
  • A principal with iam:CreateRole, iam:AttachRolePolicy and iam:PutRolePolicy (typically AdministratorAccess) to create the audit role once
  • Root-user or account-owner access to Billing and Cost Management console Account settings, to switch on 'IAM access to Billing and Cost Management' โ€” no IAM policy alone can grant Cost Explorer data without this
  • Cost Explorer enabled on the account at least 24 hours before the audit (first enablement backfills up to 12 months and is not instant)
  • Compute Optimizer opt-in completed (account or Organization level); recommendations require ~12 hours of CloudWatch history after opt-in
  • AWS Business or Enterprise Support if the full Trusted Advisor check set is expected; Basic and Developer Support return SubscriptionRequiredException and those checks must be derived manually
  • AWS CLI v2 and jq installed locally; the reference sweep script is bash and uses jq, awk and base64
  • A decision on write authorization: the audit is read-only unless the optional Well-Architected Tool workload creation in Step 9 is explicitly approved
  • Knowledge of which opt-in Regions (e.g. ap-east-1, me-south-1, af-south-1) are enabled, since disabled Regions fail with OptInRequired during the all-Region sweep

How the pieces connect

Credentials this skill needs

Set these as environment variables. Never paste secrets into a chat or commit them.

VariableWhat it isWhere to get it
AWS_PROFILE
AWS CLI named profile for the audit principal
format: Profile name string matching a [profile <name>] section in ~/.aws/config, e.g. wa-audit (skill defaults to 'default' if unset)
Created locally by running 'aws configure sso --profile wa-audit' (recommended) or 'aws configure --profile wa-audit'; the section is written to ~/.aws/config and ~/.aws/credentials. See https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
AWS_ACCESS_KEY_ID
secretoptional
AWS access key ID (only if not using a profile or SSO)
format: 20-character uppercase alphanumeric string beginning AKIA (long-lived IAM user key) or ASIA (temporary STS credentials)
AWS Management Console > IAM > Users > your audit user > Security credentials tab > Access keys > Create access key. Prefer temporary credentials from 'aws sts assume-role' or IAM Identity Center over a long-lived AKIA key. https://console.aws.amazon.com/iam/home#/users
AWS_SECRET_ACCESS_KEY
secretoptional
AWS secret access key
format: 40-character base64-style string (A-Z a-z 0-9 + /)
Shown exactly once at IAM > Users > your audit user > Security credentials > Access keys > Create access key > Retrieve access keys. It cannot be re-displayed; rotate the key if lost. https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html
AWS_SESSION_TOKEN
secretoptional
AWS session token (required whenever the access key ID starts with ASIA)
format: Long opaque base64 string, several hundred characters
Returned in the Credentials block of 'aws sts assume-role --role-arn arn:aws:iam::<account-id>:role/WellArchitectedAudit --role-session-name wa-audit', or copied from the IAM Identity Center access portal 'Command line or programmatic access' panel. https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role.html
AWS_REGION
optional
Default AWS Region for CLI calls
format: Region code such as us-east-1
Set in ~/.aws/config as 'region = us-east-1' or exported directly. Cost Explorer (ce), Support and the Trusted Advisor API only answer in us-east-1 regardless of this value. https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html
REGIONS
optional
Explicit space-separated Region list to sweep (optional override)
format: Space-separated Region codes, e.g. 'us-east-1 us-west-2 eu-west-1'
Skill-defined variable. If unset the script derives it from 'aws ec2 describe-regions --query Regions[].RegionName --output text'; set it manually to limit blast radius or to include opt-in Regions found via --all-regions.
OUT
optional
Local output directory for findings.jsonl and summary.json
format: Filesystem path; defaults to ./wa-audit
Skill-defined variable, chosen by you. Must be writable and should be excluded from version control since it contains resource identifiers.

Permissions to grant

arn:aws:iam::aws:policy/SecurityAuditIAM roleadmin consent required

Grants the read-only security posture calls the skill depends on: cloudtrail:DescribeTrails, ec2:DescribeSecurityGroups, iam:GenerateCredentialReport/GetCredentialReport, kms:GetKeyRotationStatus, config:Describe*, guardduty:List*, access-analyzer:ListAnalyzers.

โ†ณ SecurityAudit deliberately excludes s3:GetObject, kms:Decrypt and ssm:GetParameter on secret values. Never add them for an audit; the skill records unreadable data as 'not verifiable' rather than reading it.

arn:aws:iam::aws:policy/job-function/ViewOnlyAccessIAM roleadmin consent required

Supplies the broad List/Describe/Get coverage SecurityAudit omits, used for inventory, RDS, Auto Scaling, DynamoDB, AWS Backup, CloudFormation drift and CloudWatch alarm checks.

โ†ณ If you must trim, keep only the service prefixes the skill actually calls: ec2, rds, autoscaling, dynamodb, backup, cloudformation, cloudwatch, logs, s3, elasticloadbalancing, ssm, organizations.

tag:GetResourcesAPI scope

Baselines the resource inventory and computes tag coverage for Owner, Environment, Application and CostCenter in Step 2, which decides whether the audit is scoped per-workload or per-account.

โ†ณ tag:GetResources is already read-only and cannot be narrowed by resource; add tag:GetTagKeys only if you also want key enumeration.

ce:GetCostAndUsageAPI scopeadmin consent required

Produces the monthly spend breakdown by SERVICE dimension that every Cost Optimization finding is quantified against.

โ†ณ Cost Explorer actions do not support resource-level restriction. The narrower control is to grant ce:GetCostAndUsage alone and omit ce:GetCostForecast and ce:GetReservationPurchaseRecommendation.

ce:GetSavingsPlansPurchaseRecommendationAPI scopeadmin consent required

Returns AWS's own estimatedMonthlySavingsAmount for Compute Savings Plans, which the skill reports instead of hand-computing commitment savings.

โ†ณ Omit if the engagement explicitly excludes commitment purchasing advice; the rest of the cost sweep still works.

ce:GetAnomalyMonitorsAPI scopeadmin consent required

Confirms in Step 7 that at least one Cost Anomaly Detection monitor exists, which is an Operational Excellence control.

compute-optimizer:GetEnrollmentStatusAPI scope

Detects whether Compute Optimizer is Active before the skill relies on its recommendations, so it can fall back to raw CloudWatch metrics if enrollment is Inactive.

compute-optimizer:GetEC2InstanceRecommendationsAPI scope

Provides the right-sizing evidence base for the Performance Efficiency pillar; the skill also calls GetEBSVolumeRecommendations, GetLambdaFunctionRecommendations, GetAutoScalingGroupRecommendations and GetRDSDatabaseRecommendations.

โ†ณ Grant only the recommendation verbs for resource types in scope, e.g. drop GetLambdaFunctionRecommendations for a pure EC2 workload.

servicequotas:ListServiceQuotasAPI scope

Measures quota headroom for ec2, lambda and vpc in the Reliability pillar; above 70% utilization becomes a finding.

โ†ณ Pair with cloudwatch:GetMetricData on the AWS/Usage namespace if you want actual utilization rather than the quota ceiling alone.

support:DescribeTrustedAdvisorChecksAPI scopeadmin consent required

Probes the support tier and, on Business/Enterprise Support, pulls the full Trusted Advisor check set used to cross-check cost and fault-tolerance findings.

โ†ณ Add support:DescribeTrustedAdvisorCheckResult only if you want per-check results; the probe alone is enough to detect the tier. The AWS Support API is unavailable below Business Support regardless of IAM.

iam:SimulatePrincipalPolicyAPI scope

Confirms effective permissions before the skill escalates an IAM finding to Critical, since SCPs, permissions boundaries and resource policies can override a permissive-looking policy.

โ†ณ Read-only simulation; it never evaluates against real resources or performs the action.

organizations:DescribeOrganizationAPI scopeadmin consent required

Determines in Step 1 whether the scope is a standalone account or an Organization payer plus members; absence throws AWSOrganizationsNotInUseException, which the skill treats as 'standalone'.

โ†ณ Add organizations:ListAccounts only when the audit genuinely spans member accounts; otherwise this single describe is sufficient.

pricing:GetProductsAPI scope

Lets the skill verify list prices against the AWS Price List API instead of quoting the stale figures baked into its cost model.

โ†ณ Public pricing data; no account data is exposed. Safe to grant on Resource: *.

wellarchitected:CreateWorkloadAPI scopeadmin consent required

Optional Step 9 mutation that mirrors findings into the AWS Well-Architected Tool; also needs wellarchitected:ListLensReviewImprovements to read back improvement items.

โ†ณ OMIT THIS BY DEFAULT. The audit is read-only; grant it only after explicit written approval, and prefer a separate elevated profile so the sweep itself cannot write.

Step by step

  1. 1

    Create a dedicated read-only audit role

    AWS Management Console > IAM > Roles > Create role > Trusted entity type: AWS account (or Custom trust policy for a cross-account auditor) > enter the trusting account ID and require an external ID > Next. Name it WellArchitectedAudit. Never reuse an existing admin role: the skill treats an unexpectedly successful mutation as evidence the principal is over-privileged and aborts.

    Open in the console / docs โ†—
  2. 2

    Attach the two AWS managed read-only policies

    IAM > Roles > WellArchitectedAudit > Permissions tab > Add permissions > Attach policies directly. Search for and tick 'SecurityAudit', then 'ViewOnlyAccess' (it lives under the job-function path arn:aws:iam::aws:policy/job-function/ViewOnlyAccess). Click Add permissions. CLI equivalent: aws iam attach-role-policy --role-name WellArchitectedAudit --policy-arn arn:aws:iam::aws:policy/SecurityAudit

    Open in the console / docs โ†—
  3. 3

    Add the supplemental inline policy for cost, optimizer, tagging, quotas and support

    IAM > Roles > WellArchitectedAudit > Permissions tab > Add permissions > Create inline policy > JSON tab. Paste a single Allow statement on Resource "*" with Action: ["tag:GetResources","ce:GetCostAndUsage","ce:GetSavingsPlansPurchaseRecommendation","ce:GetAnomalyMonitors","compute-optimizer:GetEnrollmentStatus","compute-optimizer:Get*Recommendations","servicequotas:ListServiceQuotas","support:DescribeTrustedAdvisorChecks","iam:SimulatePrincipalPolicy","organizations:DescribeOrganization","pricing:GetProducts"]. Name it WellArchitectedAuditSupplemental. Do NOT include any wellarchitected:Create* action unless write approval was granted.

    Open in the console / docs โ†—
  4. 4

    Activate IAM access to billing data and enable Cost Explorer

    Sign in as the account root user or account owner > Billing and Cost Management console > Account settings (left nav) > IAM user and role access to Billing information > Edit > tick Activate IAM Access > Update. Then open Cost Management > Cost Explorer and click Launch Cost Explorer once. Without the account-setting toggle, ce:GetCostAndUsage returns AccessDeniedException no matter what the IAM policy says, and the first enablement can take up to 24 hours to backfill history.

    Open in the console / docs โ†—
  5. 5

    Opt in to AWS Compute Optimizer

    AWS Management Console > Compute Optimizer > Get started > choose 'Only this account' or 'All accounts within this organization' (the latter must be run from the Organization management account) > Opt in. Recommendations need roughly 12 hours of CloudWatch metric history before they populate; until then get-enrollment-status returns Active but recommendation lists come back empty and the skill falls back to raw CPUUtilization metrics.

    Open in the console / docs โ†—
  6. 6

    Confirm which Regions are enabled, including opt-in Regions

    AWS Management Console > account menu (top right) > Account > AWS Regions section, or run: aws account list-regions --region-opt-status-contains ENABLED ENABLED_BY_DEFAULT. Enable any opt-in Region that hosts workloads before the sweep, otherwise calls there fail with OptInRequired and the skill will under-report. The skill's own enumeration uses: aws ec2 describe-regions --all-regions --query 'Regions[].RegionName' --output text

    Open in the console / docs โ†—
  7. 7

    Install AWS CLI v2 and jq

    Install AWS CLI v2 from the official installer for your OS and confirm with 'aws --version' (must report aws-cli/2.x; v1 lacks several commands and default pagination behaviour the skill relies on). Install jq 1.6+ ('jq --version'); the reference sweep pipes every result through jq and will fail closed without it.

    Open in the console / docs โ†—
  8. 8

    Configure the local CLI profile for the audit role

    Preferred: run 'aws configure sso --profile wa-audit' and follow the prompts (SSO start URL, SSO Region, account, permission set), which yields short-lived credentials. Alternative for a cross-account role: add to ~/.aws/config a [profile wa-audit] section with role_arn = arn:aws:iam::<account-id>:role/WellArchitectedAudit, source_profile = <your-admin-profile>, external_id = <the value from Step 1>, region = us-east-1. Then export AWS_PROFILE=wa-audit.

    Open in the console / docs โ†—
  9. 9

    Probe the AWS Support tier before promising Trusted Advisor coverage

    Run: aws support describe-trusted-advisor-checks --language en --region us-east-1 --profile wa-audit. A SubscriptionRequiredException means the account is on Basic or Developer Support and the full Trusted Advisor set is unavailable; record that in the report and derive those checks manually rather than reporting an empty cost section.

    Open in the console / docs โ†—
  10. 10

    Decide and record write authorization for the Well-Architected Tool

    The sweep is read-only. If the deliverable must appear in AWS Well-Architected Tool (console > Well-Architected Tool > Define workload), get explicit written approval first, then run the create from a SEPARATE elevated profile so the audit profile itself can never mutate. The Well-Architected Tool has no charge; the workload record and lens review are free.

    Open in the console / docs โ†—

Check it worked

aws sts get-caller-identity --profile wa-audit --output text && aws ec2 describe-regions --all-regions --profile wa-audit --query 'length(Regions)' --output text && aws cloudtrail describe-trails --profile wa-audit --query 'length(trailList)' --output text && aws resourcegroupstaggingapi get-resources --resources-per-page 1 --profile wa-audit --query 'length(ResourceTagMappingList)' --output text && aws compute-optimizer get-enrollment-status --profile wa-audit --query status --output text && aws ce get-cost-and-usage --time-period Start=2026-06-01,End=2026-07-01 --granularity MONTHLY --metrics UnblendedCost --region us-east-1 --profile wa-audit --query 'length(ResultsByTime)' --output text && echo 'ALL SIX CHECKS PASSED'

If you hit an error

An error occurred (AccessDeniedException) when calling the GetCostAndUsage operation: User: arn:aws:sts::123456789012:assumed-role/WellArchitectedAudit/wa-audit is not authorized to perform: ce:GetCostAndUsage

Cause: Either the ce:* actions are missing from the supplemental inline policy, or โ€” far more often โ€” 'IAM user and role access to Billing information' is still deactivated in Billing Account settings, which blocks Cost Explorer for every non-root principal regardless of IAM.

Fix: Sign in as the root user, go to Billing and Cost Management > Account settings > IAM user and role access to Billing information > Edit > Activate IAM Access > Update, then re-run. Confirm the inline policy also lists ce:GetCostAndUsage.

An error occurred (NoSuchPublicAccessBlockConfiguration) when calling the GetPublicAccessBlock operation: The public access block configuration was not found

Cause: Account-level S3 Block Public Access has never been configured. This is NOT a credential problem โ€” it is the SEC-01 Critical finding the skill is looking for.

Fix: Do not 'fix' it during the audit. Record it as a Critical Security finding and hand back the aws_s3_account_public_access_block Terraform remediation. Only confirm the permission is real by checking that s3:GetAccountPublicAccessBlock is allowed (SecurityAudit grants it).

An error occurred (AWSOrganizationsNotInUseException) when calling the DescribeOrganization operation: Your account is not a member of an organization

Cause: The target is a standalone account, not an Organization member or payer.

Fix: Expected and benign. Treat the scope as a single account and skip all member-account enumeration; note it in the report's scope section.

An error occurred (SubscriptionRequiredException) when calling the DescribeTrustedAdvisorChecks operation: AWS Premium Support Subscription is required to use this service.

Cause: The account is on Basic or Developer Support. The AWS Support API and the full Trusted Advisor check set require Business or Enterprise Support.

Fix: Do not add IAM permissions โ€” this is a subscription gate, not an authorization one. Record the support tier in the report and derive the equivalent checks manually from the direct service APIs the skill already calls.

An error occurred (OptInRequired) when calling the DescribeSecurityGroups operation: You are not subscribed to this service. Please go to http://aws.amazon.com to subscribe.

Cause: The Region came from 'ec2 describe-regions --all-regions' but is an opt-in Region that is disabled for this account.

Fix: Either enable the Region under account menu > Account > AWS Regions, or drop --all-regions so only enabled Regions are enumerated. Record any Region you skipped so the report's Region list is honest.

An error occurred (OptInRequiredException) when calling the GetEC2InstanceRecommendations operation: The account is not opted in to Compute Optimizer.

Cause: Compute Optimizer enrollment was never completed, or was completed only for a different account in the Organization.

Fix: Run 'aws compute-optimizer get-enrollment-status' to confirm, then opt in from the Compute Optimizer console. If enrollment is Active but lists are empty, wait ~12 hours and meanwhile fall back to cloudwatch get-metric-statistics on AWS/EC2 CPUUtilization.

An error occurred (ExpiredToken) when calling the GetCallerIdentity operation: The security token included in the request is expired

Cause: AWS_SESSION_TOKEN came from an assume-role or IAM Identity Center session that has passed its duration (often 1 hour by default). A full multi-Region sweep can outlive it.

Fix: Re-run 'aws sso login --profile wa-audit' or re-issue 'aws sts assume-role --duration-seconds 43200' (the role's MaxSessionDuration must be raised in IAM > Roles > WellArchitectedAudit > Summary > Edit to allow more than 1 hour).

An error occurred (AuthFailure) when calling the DescribeRegions operation: AWS was not able to validate the provided access credentials

Cause: Bad or rotated access keys, an AKIA key paired with a stale AWS_SESSION_TOKEN, or local system clock skew of more than 5 minutes (SigV4 rejects skewed signatures).

Fix: Unset AWS_SESSION_TOKEN when using a long-lived AKIA key, re-sync the system clock (w32tm /resync on Windows, chronyc makestep on Linux), and confirm the key is Active under IAM > Users > Security credentials.

An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.

Cause: SecurityAudit and ViewOnlyAccess were not both attached, or a Service Control Policy / permissions boundary on the account denies the action above the identity policy.

Fix: Verify both managed policies are attached, then run 'aws iam simulate-principal-policy --policy-source-arn <role-arn> --action-names ec2:DescribeInstances' to see whether an SCP or boundary is the actual denier, and record the check as verifiable:false if it cannot be resolved.

An error occurred (ThrottlingException) when calling the ListServiceQuotas operation: Rate exceeded

Cause: The all-Region sweep issues many describe/list calls in a short window and trips per-account API rate limits.

Fix: Ensure AWS_MAX_ATTEMPTS=10 and AWS_RETRY_MODE=adaptive are exported (the reference script sets both), and serialize the per-Region loop instead of fanning out. Never pass --no-paginate to compensate; that silently under-reports on large accounts.

The config profile (wa-audit) could not be found

Cause: AWS_PROFILE points at a profile name that has no matching section in ~/.aws/config, or the section was written as [wa-audit] instead of [profile wa-audit] in the config file.

Fix: In ~/.aws/config the header must be '[profile wa-audit]'; only ~/.aws/credentials uses the bare '[wa-audit]' form. Confirm with 'aws configure list-profiles'.

An error occurred (AccessDenied) when calling the GetCredentialReport operation

Cause: iam:GetCredentialReport is granted but the report was never generated, or generation is still in progress and the call raced it.

Fix: Run 'aws iam generate-credential-report' first, poll until State is COMPLETE, then re-run get-credential-report. On a genuine AccessDenied, record the identity checks as verifiable:false rather than as a pass.

Official documentation: https://docs.aws.amazon.com/wellarchitected/latest/framework/welcome.html โ†—

API operations this skill uses (20)

Every call the skill makes, linked to its official reference page.

OperationCallPermissionRef
Identify the calling principal and account
Step 1 preflight: sets ACCOUNT_ID for every downstream call and records which principal produced the evidence.
CLI aws sts get-caller-identity --query Account --output textsts:GetCallerIdentity (allowed for every principal, no policy needed)docs โ†—
Enumerate Regions to sweep
Builds the Region loop so shadow resources in unused Regions are not missed; the Region list is reprinted in the report.
CLI aws ec2 describe-regions --all-regions --query 'Regions[].RegionName' --output textec2:DescribeRegions (ViewOnlyAccess)docs โ†—
Determine Organization vs standalone scope
Step 1 scope confirmation; AWSOrganizationsNotInUseException is treated as 'standalone account'.
CLI aws organizations describe-organizationorganizations:DescribeOrganizationdocs โ†—
Baseline resource inventory and tag coverage
Step 2: computes Owner/Environment/Application/CostCenter coverage; below 80% forces account-level rather than workload-level scoping.
CLI aws resourcegroupstaggingapi get-resources --resources-per-page 100 --region "$R"tag:GetResourcesdocs โ†—
Check for a tamper-evident multi-Region audit trail
SEC-02: an empty result is always a Critical Security finding โ€” the audit log is incomplete or tamper evidence is off.
CLI aws cloudtrail describe-trails --query 'trailList[?IsMultiRegionTrail==`true` && LogFileValidationEnabled==`true`]'cloudtrail:DescribeTrails (SecurityAudit)docs โ†—
Pull the IAM credential report
Step 3 identity checks: root access keys, missing MFA, access keys older than 90 days, users idle over 90 days.
CLI aws iam generate-credential-report ; aws iam get-credential-report --query Content --output text | base64 -diam:GenerateCredentialReport, iam:GetCredentialReport (SecurityAudit)docs โ†—
Find security groups open to the internet
SEC-03: ports 22/3389/3306/5432/6379/9200/27017 reachable from 0.0.0.0/0 are Critical; 443 is expected.
CLI aws ec2 describe-security-groups --filters Name=ip-permission.cidr,Values=0.0.0.0/0 --region "$R"ec2:DescribeSecurityGroups (SecurityAudit)docs โ†—
Read account-level S3 Block Public Access
SEC-01: a NoSuchPublicAccessBlockConfiguration error means account-level BPA is off and any bucket can be made public.
CLI aws s3control get-public-access-block --account-id "$ACCOUNT_ID"s3:GetAccountPublicAccessBlock (SecurityAudit)docs โ†—
Detect instances still reachable over IMDSv1
Step 3: http-tokens=optional leaves the classic SSRF-to-credential-theft path open.
CLI aws ec2 describe-instances --filters Name=metadata-options.http-tokens,Values=optional --region "$R"ec2:DescribeInstances (ViewOnlyAccess)docs โ†—
Check IAM Access Analyzer coverage
Step 3: with no analyzer, cross-account trust relationships cannot be proven safe โ€” the absence is itself a finding.
CLI aws accessanalyzer list-analyzers --type ACCOUNT --region "$R"access-analyzer:ListAnalyzers (SecurityAudit)docs โ†—
Check GuardDuty enablement per Region
Step 3 detective controls: an empty detector list means no threat detection in that Region.
CLI aws guardduty list-detectors --region "$R"guardduty:ListDetectors (SecurityAudit)docs โ†—
Check enabled Security Hub standards
Step 3: establishes which compliance standards (CIS, AWS FSBP, PCI DSS) are actively evaluated before mapping findings to a regime.
CLI aws securityhub get-enabled-standards --region "$R"securityhub:GetEnabledStandards (SecurityAudit)docs โ†—
Check AWS Config recorder status
Step 3: a stopped or absent recorder means no configuration history, so drift and change findings cannot be evidenced.
CLI aws configservice describe-configuration-recorder-status --region "$R"config:DescribeConfigurationRecorderStatus (SecurityAudit)docs โ†—
Assess RDS resilience and backup retention
REL-01: single-AZ instances and BackupRetentionPeriod of 0 (automated backups disabled) are High Reliability findings tied to the stated RTO/RPO.
CLI aws rds describe-db-instances --query 'DBInstances[?MultiAZ==`false`||BackupRetentionPeriod==`0`].[DBInstanceIdentifier,MultiAZ,BackupRetentionPeriod]' --region "$R"rds:DescribeDBInstances (ViewOnlyAccess)docs โ†—
Enumerate AWS Backup plans and protected resources
Step 4: the gap between protected resources and the Step 2 inventory is the unprotected surface.
CLI aws backup list-backup-plans --region "$R" ; aws backup list-protected-resources --region "$R"backup:ListBackupPlans, backup:ListProtectedResources (ViewOnlyAccess)docs โ†—
Measure service quota headroom
Step 4: also run for lambda and vpc; above 70% utilization of a quota becomes a Reliability finding.
CLI aws service-quotas list-service-quotas --service-code ec2 --region "$R"servicequotas:ListServiceQuotasdocs โ†—
Get EC2 right-sizing recommendations
Step 5 Performance Efficiency evidence base; sibling calls cover EBS volumes, Lambda functions, Auto Scaling groups and RDS databases.
CLI aws compute-optimizer get-ec2-instance-recommendations --query 'instanceRecommendations[?finding!=`OPTIMIZED`]' --region "$R"compute-optimizer:GetEC2InstanceRecommendations (plus GetEnrollmentStatus to gate the call)docs โ†—
Break down monthly spend by service
Step 6: the baseline every Cost Optimization finding is quantified against. Cost Explorer answers only in us-east-1.
CLI aws ce get-cost-and-usage --time-period Start=2026-06-01,End=2026-07-01 --granularity MONTHLY --metrics UnblendedCost --group-by Type=DIMENSION,Key=SERVICE --region us-east-1ce:GetCostAndUsage (requires IAM access to Billing activated on the account)docs โ†—
Get Compute Savings Plans purchase recommendation
Step 6: the skill reports AWS's own estimatedMonthlySavingsAmount rather than computing commitment savings by hand.
CLI aws ce get-savings-plans-purchase-recommendation --savings-plans-type COMPUTE_SP --term-in-years ONE_YEAR --payment-option NO_UPFRONT --lookback-period-in-days SIXTY_DAYS --region us-east-1ce:GetSavingsPlansPurchaseRecommendationdocs โ†—
Probe support tier and Trusted Advisor checks
Input gathering step 6: a SubscriptionRequiredException identifies Basic/Developer Support so those checks are derived manually instead of silently missing.
CLI aws support describe-trusted-advisor-checks --language en --region us-east-1support:DescribeTrustedAdvisorChecks (Business or Enterprise Support required)docs โ†—