AWS
AWS permissions
What the access key needs to be allowed to do, screen by screen, and how to stay read-only.
The key you give DevOps Agent can do exactly what its IAM user is allowed to do, and nothing more. This page tells you what to allow.
The simple answer
Attach the AWS-managed policy ReadOnlyAccess to the IAM user, plus one
small inline policy for Cost Explorer:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ce:GetCostAndUsage",
"ce:GetCostAndUsageWithResources",
"ce:GetDimensionValues"
],
"Resource": "*"
}
]
}
That gives you every screen in read-only form: dashboard, cost, security findings, IAM review, logs, S3 browsing, CloudFormation viewing. Nothing can be changed, deleted or terminated — by you, by a team member, or by the assistant.
Most people should stop here. Add write permissions later, deliberately, for the specific things you want to do.
If you prefer a minimal policy
These are the calls each area actually makes.
Always needed
sts:GetCallerIdentity, ec2:DescribeRegions
Dashboard
ec2:DescribeInstances, rds:DescribeDBInstances, s3:ListAllMyBuckets,
plus the Cost Explorer actions above, plus the security checks below.
Security checks on the dashboard
cloudtrail:DescribeTrails, cloudtrail:GetTrailStatus,
cloudtrail:GetEventSelectors, guardduty:ListDetectors,
guardduty:GetDetector, iam:GetAccountSummary, iam:ListUsers,
iam:ListMFADevices, s3control:GetPublicAccessBlock
Cost and FinOps
ce:GetCostAndUsage, ce:GetCostAndUsageWithResources,
ce:GetDimensionValues, and for the inventory behind savings advice:
ec2:DescribeInstances, ec2:DescribeVolumes, ec2:DescribeSnapshots,
ec2:DescribeAddresses, ec2:DescribeNatGateways, rds:DescribeDBInstances
Users / IAM
iam:ListUsers, iam:GetUser, iam:GetLoginProfile, iam:ListAccessKeys,
iam:GetAccessKeyLastUsed, iam:ListMFADevices, iam:ListGroupsForUser,
iam:ListAttachedUserPolicies, iam:ListUserPolicies, and for the activity
report cloudtrail:LookupEvents
GuardDuty and Inspector
guardduty:ListDetectors, guardduty:ListFindings, guardduty:GetFindings,
inspector2:ListFindings
CloudWatch and Logs
logs:DescribeLogGroups, logs:StartQuery, logs:GetQueryResults,
cloudwatch:DescribeAlarms, cloudwatch:GetMetricData
S3
Read: s3:ListAllMyBuckets, s3:GetBucketLocation, s3:ListBucket,
s3:GetObject, s3:GetBucketVersioning, s3:GetBucketEncryption
Write (only if you want upload, new folder, new bucket, delete):
s3:PutObject, s3:DeleteObject, s3:CreateBucket
CloudFormation
Read: cloudformation:DescribeStacks, DescribeStackResources,
DescribeStackEvents, GetTemplate, ListChangeSets, DescribeChangeSet,
DetectStackDrift, ValidateTemplate
Write (only if you want to create or change stacks):
cloudformation:CreateStack, CreateChangeSet, ExecuteChangeSet,
DeleteStack, ContinueUpdateRollback — note that CloudFormation then acts
with your key's permissions on whatever the template describes.
EC2 servers
Listing needs ec2:DescribeInstances. Connecting over SSH does not use AWS
permissions at all — it uses the PEM key you save.
What "read-only" does and does not protect
Read-only stops anything being created, changed or deleted in AWS. It does
not stop things being read, and some reads are sensitive:
secretsmanager:GetSecretValue and ssm:GetParameter --with-decryption are
both reads, and both are included in ReadOnlyAccess.
That matters because the assistant's Read mode treats AWS
get-* calls as reads. If your account holds secrets you would not want
appearing in a chat transcript, deny those actions explicitly:
{
"Effect": "Deny",
"Action": [
"secretsmanager:GetSecretValue",
"ssm:GetParameter",
"ssm:GetParameters",
"kms:Decrypt"
],
"Resource": "*"
}
An explicit Deny always beats an Allow, so this is safe to add alongside
ReadOnlyAccess.
Common errors and what they mean
| Error contains | Fix |
|---|---|
is not authorized to perform: ce:GetCostAndUsage | Add the Cost Explorer policy above. Also enable Cost Explorer once in the AWS billing console |
AccessDenied on a region | The key lacks permission there, or the region is not enabled for your account |
InvalidClientTokenId | The access key is wrong or has been deleted |
SignatureDoesNotMatch | The secret key is wrong — usually a copy-paste with a space |
OptInRequired | The region needs enabling in the AWS console |
The dashboard reports per-region errors rather than failing silently, so the message usually names the exact call that was refused.
Good practice
- One IAM user per DevOps Agent project.
- No console access on that user.
- Start read-only, add write access deliberately.
- Rotate the key periodically — replace it in Settings → Project.
- Never use root account credentials.
