AWS Accounts
Connect your AWS accounts to CostLens using an IAM Role or Access Keys.
CostLens reads your AWS cost data and resource configurations using a cross-account IAM role. The setup takes about 5 minutes and requires no code changes or agents in your AWS environment.
How it works
| Step | What happens |
|---|---|
| 1. You create an IAM Role | In your AWS Console, create a role that trusts CostLens's AWS account and attach read-only permissions. |
| 2. External ID prevents hijacking | Your unique External ID is required to assume the role — it prevents any other party from using CostLens's identity to access your account. |
| 3. CostLens scans automatically | Billing data syncs every 6 hours. Optimisation checks and AI explanations run every 12 hours. You can trigger a manual sync at any time. |
What is the External ID?
When you click Add Account, a unique External ID (a UUID like 550e8400-e29b-41d4-a716-446655440000) is generated and displayed in the form. You must paste this value into your AWS IAM role trust policy. It acts as a shared secret — without it, no one can assume your role, even if they know your Role ARN. Keep it private and treat it like a password. It is always visible on your account card if you need to copy it again.
Step-by-step: IAM Role setup (recommended)
Step 1 — Open CostLens → Accounts → Add Account
Click Add Account in the top-right corner of the Accounts page. Select IAM Role (recommended). Your unique External ID is shown in the form — copy it now, you will paste it into AWS Console in step 3.
Step 2 — Go to AWS Console → IAM → Roles → Create role
Log in to console.aws.amazon.com. Search for IAM in the top bar, open Roles in the left nav, and click Create role.
Step 3 — Configure the trusted entity
On the "Select trusted entity" screen:
| Field | Value |
|---|---|
| Trusted entity type | AWS account |
| Which AWS account | Another AWS account |
| Account ID | Enter the CostLens AWS account ID (shown in the trust policy JSON in the connect dialog) |
| Options | Check "Require external ID" |
| External ID | Paste the External ID you copied from CostLens in Step 1 |
Leave MFA unchecked. Click Next.
Step 4 — Attach ReadOnlyAccess + Apply Fix policy
Step 4a — Scan only
Search for ReadOnlyAccess and select the AWS-managed policy. This lets CostLens scan for waste and surface recommendations.
# Covered by ReadOnlyAccess (scanning)
ce:GetCostAndUsage, ce:GetCostForecast
ec2:DescribeInstances, DescribeVolumes, DescribeAddresses
rds:DescribeDBInstances
cloudwatch:GetMetricStatistics
Step 4b — Apply Fix permissions (recommended)
After attaching ReadOnlyAccess, click Next → Create role. Then open the role → Add permissions → Create inline policy → JSON and paste:
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "CostlensApplyFix",
"Effect": "Allow",
"Action": [
"ec2:DeleteVolume",
"ec2:DeleteSnapshot",
"ec2:TerminateInstances",
"ec2:ModifyVolume",
"ec2:ModifyInstanceAttribute",
"ec2:StopInstances",
"ec2:StartInstances",
"ec2:ReleaseAddress",
"ec2:CreateTags",
"ssm:SendCommand",
"ssm:GetCommandInvocation",
"rds:DeleteDBInstance",
"rds:StopDBInstance",
"rds:StartDBInstance",
"rds:AddTagsToResource",
"scheduler:CreateSchedule",
"scheduler:CreateScheduleGroup",
"scheduler:GetScheduleGroup",
"iam:GetRole",
"iam:CreateRole",
"iam:PutRolePolicy",
"iam:PassRole",
"logs:PutRetentionPolicy",
"logs:DescribeLogGroups"
],
"Resource": "*"
}]
}Name the inline policy CostlensApplyFix and save.
What each permission enables:
ec2:DeleteVolume / DeleteSnapshot— remove unused EBS volumes & snapshotsec2:TerminateInstances— terminate long-stopped EC2 instancesec2:StopInstances / StartInstances / ModifyInstanceAttribute— schedule & rightsize EC2 instancesec2:ModifyVolume + ssm:*— expand full EBS volumes live (no downtime)ec2:ReleaseAddress— release unattached Elastic IPsrds:DeleteDBInstance— delete idle RDS databasesrds:StopDBInstance / StartDBInstance— schedule RDS stop-startscheduler:* + iam:*— create EventBridge schedules for automated stop-startlogs:PutRetentionPolicy / DescribeLogGroups— set 30-day retention on CloudWatch Log Groups
Step 5 — Name the role and create it
On the "Name, review, and create" screen, set the role name to AezonaCostlens. Scroll down and verify the Trusted entities section shows the CostLens Account ID and your External ID condition. Click Create role.
Step 6 — Copy the Role ARN back into CostLens
In AWS Console, open the newly created role. Copy the ARN shown at the top:
arn:aws:iam::123456789012:role/AezonaCostlens
Go back to the CostLens connect dialog, paste it into the Role ARN field, optionally enter an account name, then click Test Connection. Once the test passes, click Connect Account to save.
First sync phases
After saving, a first-sync progress panel appears. It runs three phases in sequence:
| Phase | Duration |
|---|---|
| Fetching billing data | 10 s – 2 min — pulls monthly and daily cost history from AWS Cost Explorer |
| Running optimisation checks | 30 s – 3 min — scans EC2, EBS, RDS, networking, Lambda, and CloudWatch for waste |
| Generating AI explanations | 20 s – 1 min — Aevi writes plain-English explanations and savings estimates |
The panel auto-dismisses after completion. The account card then shows In sync and a last-synced timestamp.
Option B — Access Keys (not recommended)
Create a dedicated IAM User
In AWS IAM, create a dedicated IAM User (not your personal user). Attach the ReadOnlyAccess policy.
Generate access keys
Under the user's Security credentials tab, click Create access key. Select "Third-party service" as the use case. Copy both the Access Key ID and Secret Access Key.
Paste into CostLens
In CostLens, click Add Account, select Access Keys in the auth method toggle, and paste both values. CostLens encrypts them at rest using AES-256.
Tip
Rotate access keys every 90 days. Never use AWS root account credentials. Create a dedicated IAM user with only the minimum permissions required.
Adding Apply Fix permissions later
If you skipped Step 4b, you can add the CostlensApplyFix inline policy at any time by opening your AezonaCostlens IAM role in AWS → Add permissions → Create inline policy → JSON and pasting the JSON from Step 4b.
Without the Apply Fix policy, the "Apply Fix" button on recommendations is disabled. Scanning and recommendations work fully with ReadOnlyAccess alone.
Managing connected accounts
| Action | Who can do it | Description |
|---|---|---|
| Sync Now | Operators, Admins | Triggers an immediate billing sync |
| Edit Credentials | Admins only | Opens the connect dialog to update the Role ARN or swap auth method |
| Setup Guide | Admins only (IAM Role accounts) | Opens the full IAM role setup guide with your External ID pre-filled |
| Remove Account | Admins only | Disconnects and permanently deletes all associated data — cannot be undone |
Sync status reference
| Status | Meaning |
|---|---|
| Not synced | Account has never been synced |
| Syncing… | A sync is in progress |
| In sync | Last sync completed successfully |
| Sync failed | The sync encountered an error — expand the card to see details and a Try again button |
Common errors and fixes
| Error | Fix |
|---|---|
| AccessDenied: not authorized to assume role | The External ID in your IAM trust policy doesn't match. Open the role in AWS → Trust relationships → verify sts:ExternalId matches exactly. |
| AWS Cost Explorer not enabled | Go to AWS Console → Cost Explorer → Enable Cost Explorer. It can take up to 24 hours for data to appear. |
| InvalidClientTokenId / no such access key | The Access Key ID is wrong or deactivated. Regenerate a new access key and use Edit Credentials to update it. |
| The requested resource does not exist (role ARN) | Double-check the Role ARN is copied exactly as shown in the AWS Console, including the correct 12-digit account number. |
| Sync stuck in one phase for more than 10 minutes | Click Force retry or click Sync Now on the account card to restart. |