Verify your email to continue.
Enter your work email. We'll send a 6-digit one-time code.
Enter the 6-digit code sent to
Didn't receive the code?
check_circle Email verified
Which AWS account?
We'll use this to generate your read-only role.
Connect a read-only AWS role.
plainfra uses this role to query AWS metadata, metrics, costs, and security findings. It cannot read your application data or change your resources.
Granting access to account .
Nothing is charged. This is the free tier.
visibility What plainfra can see
- Resource metadata: instances, buckets, databases, IAM settings, VPCs, security groups, certificates, and DNS records.
- Operational signals: CloudWatch metrics, Cost Explorer spend, CloudTrail event metadata, and security findings.
- Enough context to answer AWS questions with resource IDs, costs, regions, and risk notes.
block What plainfra cannot touch
- No create, update, start, stop, or delete actions are allowed.
- plainfra can list that a bucket exists. It cannot read the objects inside it.
- Explicit denies block database rows, log events, secrets, SSM parameters, KMS decrypt, Lambda invocation, source code, SQL execution, and API key values.
handshake Why ExternalId matters
ExternalId binds this role to your plainfra customer record. The role can only be assumed by plainfra's AWS account and only with your unique ExternalId. Each session lasts up to 1 hour and is issued on demand.
undo How to disconnect
Delete the plainfra-ReadOnly CloudFormation stack from your AWS Console. AWS removes the role, and plainfra loses access immediately.
"I built this with the read-only model from day one. It is the same access model I'd want before installing a tool in my own AWS account."
Tim Fraser · Cloud Operations Lead at Triont
Want to inspect it first?
Review the JSON policy, CloudFormation template, and CloudShell script before you deploy anything.
expand_more
Want to inspect it first?
Review the JSON policy, CloudFormation template, and CloudShell script before you deploy anything.
Copy the policy into your AI assistant, ChatGPT, Claude, or Gemini, and ask what it allows and denies. The important part is the explicit deny list: it blocks data contents, secrets, logs, code, and execution.
{
"TrustPolicy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPlainfraAssumeWithExternalId",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::921514166437:root" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "sts:ExternalId": "<your-unique-external-id>" }
}
}
]
},
"PlainfraInfrastructureDiscovery": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ComputeContainersAndServerless",
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"elasticloadbalancing:Describe*",
"autoscaling:Describe*",
"application-autoscaling:Describe*",
"ecs:Describe*", "ecs:List*",
"eks:Describe*", "eks:List*",
"ecr:Describe*", "ecr:List*",
"ecr:GetRepositoryPolicy",
"ecr:GetLifecyclePolicy",
"ecr:GetRegistryPolicy",
"lambda:List*", "lambda:Get*",
"states:Describe*", "states:List*",
"apprunner:Describe*", "apprunner:List*"
],
"Resource": "*"
},
{
"Sid": "DataStorageAndDatabases",
"Effect": "Allow",
"Action": [
"s3:Get*", "s3:List*",
"elasticfilesystem:Describe*", "elasticfilesystem:List*",
"backup:Describe*", "backup:Get*", "backup:List*",
"rds:Describe*", "rds:List*",
"dynamodb:Describe*", "dynamodb:List*",
"elasticache:Describe*", "elasticache:List*",
"redshift:Describe*"
],
"Resource": "*"
},
{
"Sid": "SecurityIdentityAndCompliance",
"Effect": "Allow",
"Action": [
"iam:Get*", "iam:List*",
"iam:GenerateCredentialReport",
"iam:GenerateServiceLastAccessedDetails",
"cloudtrail:Describe*", "cloudtrail:Get*", "cloudtrail:List*",
"cloudtrail:LookupEvents",
"config:Describe*", "config:Get*", "config:List*",
"guardduty:Describe*", "guardduty:Get*", "guardduty:List*",
"securityhub:Describe*", "securityhub:Get*", "securityhub:List*",
"access-analyzer:Get*", "access-analyzer:List*",
"secretsmanager:ListSecrets",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds",
"secretsmanager:GetResourcePolicy",
"ssm:Describe*", "ssm:List*",
"ssm:GetInventory", "ssm:GetInventorySchema",
"kms:Describe*", "kms:Get*", "kms:List*"
],
"Resource": "*"
},
{
"Sid": "NetworkingObservabilityAndGovernance",
"Effect": "Allow",
"Action": [
"cloudfront:Get*", "cloudfront:List*",
"cloudfront:DescribeFunction",
"route53:Get*", "route53:List*",
"route53domains:Get*", "route53domains:List*",
"route53resolver:Get*", "route53resolver:List*",
"acm:Describe*", "acm:Get*", "acm:List*",
"wafv2:Get*", "wafv2:List*",
"apigateway:GET",
"cloudwatch:Describe*", "cloudwatch:Get*", "cloudwatch:List*",
"logs:Describe*", "logs:List*",
"xray:Get*", "xray:List*",
"sns:Get*", "sns:List*",
"sqs:Get*", "sqs:List*",
"events:Describe*", "events:List*",
"scheduler:Get*", "scheduler:List*",
"kinesis:Describe*", "kinesis:List*",
"firehose:Describe*", "firehose:List*",
"cloudformation:Describe*", "cloudformation:List*",
"cloudformation:Get*", "cloudformation:ValidateTemplate",
"ce:Get*", "ce:List*",
"cur:Describe*",
"budgets:Describe*", "budgets:View*",
"organizations:Describe*", "organizations:List*",
"account:Get*", "account:List*",
"support:Describe*",
"trustedadvisor:Get*", "trustedadvisor:List*",
"health:Describe*",
"tag:Get*", "tag:Describe*"
],
"Resource": "*"
}
]
},
"PlainfraDataAccessDeny": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyDataContents",
"Effect": "Deny",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:GetObjectTorrent",
"s3:GetObjectVersionTorrent",
"s3:SelectObjectContent",
"dynamodb:GetItem",
"dynamodb:BatchGetItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:GetRecords",
"dynamodb:PartiQLSelect",
"kinesis:GetRecords",
"kinesis:GetShardIterator",
"kinesis:SubscribeToShard",
"sqs:ReceiveMessage",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
],
"Resource": "*"
},
{
"Sid": "DenySecretsLogsAndDecryption",
"Effect": "Deny",
"Action": [
"secretsmanager:GetSecretValue",
"ssm:GetParameter",
"ssm:GetParameters",
"ssm:GetParametersByPath",
"ssm:GetParameterHistory",
"logs:GetLogEvents",
"logs:FilterLogEvents",
"logs:StartQuery",
"logs:StopQuery",
"logs:GetQueryResults",
"logs:StartLiveTail",
"kms:Decrypt",
"kms:GenerateDataKey",
"kms:GenerateDataKeyPair",
"kms:GenerateDataKeyWithoutPlaintext"
],
"Resource": "*"
},
{
"Sid": "DenyCodeExecutionAndConsoleAccess",
"Effect": "Deny",
"Action": [
"lambda:InvokeFunction",
"lambda:InvokeFunctionUrl",
"lambda:GetFunction",
"cloudformation:GetTemplate",
"states:GetExecutionHistory",
"ec2:GetConsoleOutput",
"ec2:GetConsoleScreenshot",
"ec2:GetPasswordData",
"rds-data:ExecuteStatement",
"rds-data:BatchExecuteStatement",
"glacier:GetJobOutput",
"glacier:InitiateJob"
],
"Resource": "*"
},
{
"Sid": "DenyAPIKeyValueAccess",
"Effect": "Deny",
"Action": [ "apigateway:GET" ],
"Resource": [
"arn:aws:apigateway:*::/apikeys",
"arn:aws:apigateway:*::/apikeys/*"
]
}
]
}
}
Tip: paste it into your AI assistant and ask "what can this AWS IAM policy read, and what does it deny?"
Install the role
Two ways. Pick whichever you prefer. Both deploy the same plainfra-ReadOnly CloudFormation stack.
Option A: CloudShell Recommended
Sign in to AWS in this browser, click below, paste the copied command, and press Enter. The stack usually finishes in about 60 seconds.
Option B: CloudFormation Console
Opens the AWS CloudFormation console with the template pre-filled. Review the stack details and click Create stack.
open_in_new Deploy via CloudFormationThe role is yours. Delete the plainfra-ReadOnly stack at any time. No emails or support calls needed.
Verify connection
Once the stack shows CREATE_COMPLETE in CloudShell or CloudFormation, click below.
You're connected.
Your free-tier account is active. Head to the console to start asking questions.
Trial · 50K tokens · 48 hours
Signed in as . We'll auto-discover your AWS footprint in the background.
Payment received. Your beta is active.
Your account is being activated. This usually takes a few seconds.
terminal Go to plainfra ConsolePayment cancelled.
Your account has been created but is not yet active. You can complete payment later.
Try Again