Security
How Cloud GUI accesses your AWS account
The short version: you create a read-only role in your own account, we borrow it for fifteen minutes at a time, and you can delete it whenever you like. Editing is a second, optional role that you add only if you want it.
How connecting works
- You tell us your 12-digit AWS account number. We generate a random external ID that belongs to your connection alone.
- We send you to AWS CloudFormation with our template filled in. You review it there, in AWS, and click Create stack. It creates one IAM role.
- That role trusts Cloud GUI's AWS account (
487275459989), and only for requests that carry your external ID and name the Cloud GUI user they're for. Another Cloud GUI customer can't point us at your account: they'd need your ID, and we never let anyone choose their own. - When you open a page, we ask AWS STS for a session on that role. It lasts 15 minutes, lives only in our server's memory, and is never written to a database, file or log.
Exactly what the read-only role allows
Template v3. Every permission is a read. Nothing in it can create, change or delete anything in your account. It has four parts: a policy AWS wrote, a few reads that policy leaves out, a short list of reads it allows that we refuse, and log lines, which you can switch off.
See the names and settings of what's in your account
This is AWS's own view-only job-function policy, attached as it is. AWS wrote it for someone who should see what exists in an account without seeing inside it: it lists resources and reads their settings across about 120 services (S3, Lambda, EC2, RDS, DynamoDB, CloudFront, Route 53, IAM and many more). It's built to leave contents out (file bodies, database items, log lines, secret values), and the few reads in it that can expose secrets or details about people are denied outright. AWS maintains it and publishes every action in it.
arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
Plus these reads, which ViewOnlyAccess leaves out and Cloud GUI's pages need (some for pages on the way: servers, websites and costs):
Find which region each S3 bucket is in
So a bucket's files are listed from the right place. Not what is inside the files: there is no s3:GetObject.
s3:GetBucketLocation
View one Lambda function's settings and web address
Runtime, memory, timeout and its function URL, one function at a time. Not your code: there is no lambda:GetFunction. AWS includes environment variable values in these responses; Cloud GUI keeps only the names and discards the values before anything is displayed.
lambda:GetFunctionConfigurationlambda:GetFunctionUrlConfig
View Aurora DSQL clusters
Cluster names, status and settings. Not the data in them: connecting to a cluster needs dsql:DbConnect, which this role doesn't have.
dsql:ListClustersdsql:GetCluster
View a CloudFront distribution's full settings
Its origins, domain names, caching rules and certificate, for the Websites page (ViewOnlyAccess only lists distributions). These settings can include custom headers sent to your origin, which sometimes hold secrets: Cloud GUI keeps only the header names and discards the values, as it does for Lambda environment variables.
cloudfront:GetDistribution
See when certificates expire
Each certificate's domain names, status, expiry date and renewal, so expiring ones can be flagged. Not the private key: there is no acm:ExportCertificate.
acm:DescribeCertificate
See which servers Systems Manager can reach
Whether each server's SSM agent is online, with its platform and agent version. Not your parameters or secrets (no ssm:GetParameter), and it can't run anything on a server.
ssm:DescribeInstanceInformation
Check whether S3 buckets are public
Whether a bucket's policy makes it public, and whether S3 Block Public Access is on for the bucket and for the account. Not the policy text, and not your files.
s3:GetBucketPolicyStatuss3:GetBucketPublicAccessBlocks3:GetAccountPublicAccessBlock
See what your account costs
Spend by service and by day from Cost Explorer, and AWS's forecast for the month. AWS charges about $0.01 for each Cost Explorer request, billed to your account; Cloud GUI caches cost figures to keep that to cents.
ce:GetCostAndUsagece:GetCostForecast
Logs (on unless you switch them off)
Log lines are content: whatever your code prints, which can include customer data. So reading them is a separate policy in the template, controlled by a setting called AllowLogs on the CloudFormation page. It's true unless you change it, so a function's page can show its recent lines and errors and you can search a log group. Set it to false and that policy isn't created: Cloud GUI can still see which log groups exist and how big they are, but not what's in them. You can change it later by updating the stack.
Read log lines (only while AllowLogs is true)
The lines your functions and services write to CloudWatch Logs, so a function's page can show its recent logs and errors and you can search a log group. They pass through Cloud GUI to reach your screen and are never stored, cached or logged. Set AllowLogs to false on the stack and this permission is removed.
logs:FilterLogEventslogs:GetLogEventslogs:StartQuerylogs:GetQueryResultslogs:StopQuery
What that lets us see
One policy that covers all of AWS means a single stack update gives every new Cloud GUI page what it needs. It also means the role can see more than today's pages show, and we'd rather tell you than have you find out:
- Names and settings, across your whole account. Including things no Cloud GUI page shows yet: IAM user, group and role names and which policies they have, security groups and networks, and resources in services we may never build a page for. Names can say a lot (
acme-payroll-prod). - Your costs. The Cost Explorer reads show what you spend, by service and by day, and AWS's forecast for the month. AWS bills each Cost Explorer request (about $0.01) to your account, so Cloud GUI will cache cost figures to keep that to cents.
- CloudFront's custom headers. A distribution's settings can include headers that CloudFront sends to your origin, and people sometimes put secrets in them. Cloud GUI will show the header names only and discard the values, as it does for Lambda environment variables.
- Three reads we've kept on purpose. They can show things you'd consider private, and Cloud GUI needs what else they return:
- Lambda functions (
lambda:ListFunctions and friends) include environment variable values. Cloud GUI keeps the names and discards the values; more on that below. - API Gateway has one read action for everything (
apigateway:GET), and a stage's settings include its stage variables, which sometimes hold secrets. Denying it would rule out ever showing your APIs, so it stays. When Cloud GUI shows APIs, it will show stage variable names only and discard the values, as it does for Lambda. - Your AWS organization's account list (
organizations:ListAccounts, which only answers on an organization's management account) includes each member account's email address. A future "connect every account in your organization" feature needs it.
Every call is in your CloudTrail either way.
What we refuse, even though AWS's policy allows it
Some reads in ViewOnlyAccess count as settings to AWS but can hold secrets or details about people. We went through every read it allows, checking AWS's own API definitions for responses that carry startup scripts, environment variables or job arguments, and added the ones that expose people. The template denies all of them in a statement of its own (except the three above), and an explicit deny beats any allow in IAM, so Cloud GUI can't read these even by mistake. No Cloud GUI page needs them, and our tests check that the code never calls them.
DeniedStartup scripts
EC2 user data, on instances, launch templates, Spot requests and Auto Scaling launch configurations, and SageMaker notebook and Studio lifecycle scripts. People put passwords and keys in these.
ec2:DescribeInstanceAttributeec2:DescribeLaunchTemplateVersionsec2:DescribeSpotInstanceRequestsec2:DescribeSpotFleetRequestsautoscaling:DescribeLaunchConfigurationssagemaker:DescribeNotebookInstanceLifecycleConfigsagemaker:DescribeStudioLifecycleConfig
DeniedEnvironment variables in containers, ML jobs and test runs
ECS task definitions and running tasks, SageMaker models, jobs and endpoints, Device Farm projects and runs, and Lambda MicroVM images. Environment variables often carry connection strings and keys.
ecs:DescribeTaskDefinitionecs:DescribeTasksecs:DescribeDaemonTaskDefinitionecs:DescribeExpressGatewayServicesagemaker:DescribeAIRecommendationJobsagemaker:DescribeAlgorithmsagemaker:DescribeAutoMLJobsagemaker:DescribeAutoMLJobV2sagemaker:DescribeDataQualityJobDefinitionsagemaker:DescribeHyperParameterTuningJobsagemaker:DescribeInferenceComponentsagemaker:DescribeModelsagemaker:DescribeModelBiasJobDefinitionsagemaker:DescribeModelExplainabilityJobDefinitionsagemaker:DescribeModelPackagesagemaker:DescribeModelQualityJobDefinitionsagemaker:DescribeMonitoringSchedulesagemaker:DescribeOptimizationJobsagemaker:DescribePartnerAppsagemaker:DescribeProcessingJobsagemaker:DescribeTrainingJobsagemaker:DescribeTransformJobsagemaker:ListCandidatesForAutoMLJobdevicefarm:ListProjectsdevicefarm:ListRunslambda:ListMicrovmImageVersions
DeniedJob arguments and stack outputs
Arguments passed to Glue jobs and sessions, and CloudFormation stack parameters, outputs and exports, which often carry connection strings and keys.
glue:GetJobRunsglue:ListSessionscloudformation:DescribeStackscloudformation:ListExports
DeniedDetails about people
Your app's users in Cognito (with attributes like email addresses), who is subscribed to your SNS topics, SNS phone-number lists, and SES contact and suppression lists.
cognito-idp:ListUserscognito-idp:ListUsersInGroupsns:ListSubscriptionssns:ListSubscriptionsByTopicsns:ListPhoneNumbersOptedOutsns:ListSMSSandboxPhoneNumbersses:ListContactsses:ListSuppressedDestinations
DeniedActivity and conversations
CloudTrail's event history (who did what in your account) and what people said to Lex chatbots.
cloudtrail:LookupEventslex:GetUtterancesView
What the read-only role can't do
- Change anything. No create, update or delete permission of any kind.
- Read your files. We can see a file's name, size and date, not its contents (no
s3:GetObject). - Read your code. We can see a function's settings, not download it (no
lambda:GetFunction). - Read your data or secrets. No database items or queries (no DynamoDB
GetItem, Query or Scan, no dsql:DbConnect, no RDS Data API), no Secrets Manager or Parameter Store values, and no decrypting with your KMS keys. - Read your log lines, if AllowLogs is
false. - Read anything on the deny list: startup scripts, environment variables in containers and ML jobs, job arguments, stack outputs, your app's users, subscribers and contacts, CloudTrail history, chatbot conversations.
- Keep access after you leave. Delete the stack and the next request fails. There is nothing for us to hold on to.
Connected before version 3?
Your account keeps the version you deployed: a published template never changes. The console shows an Update banner that opens your stack's update page in AWS with the new template filled in. You review it there and submit, and nothing changes until you do. Until then, Cloud GUI can do exactly what your current version allows.
Editing (optional)
Off unless you turn it on, account by account. It's a second role, cloudgui-editor-…, in its own CloudFormation stack, and Cloud GUI uses it only for the action someone clicks. Viewing never uses it. When you set it up you choose which buckets and functions it covers, by the start of their names. Template v1 allows these four things and nothing else:
Download files
When you click Download, Cloud GUI signs a link that expires in five minutes and your browser fetches the file straight from S3. The file never passes through Cloud GUI.
s3:GetObject
Upload files
Your browser sends the file straight to S3 using a signed form. The file never passes through Cloud GUI, and an upload can replace a file with the same name.
s3:PutObject
Delete files
One file at a time, after you type its name to confirm.
s3:DeleteObject
Run functions
Runs a function once with the input you type, then shows its result and the last few lines of its log. That result passes through Cloud GUI to reach your screen; it is never stored or logged.
lambda:InvokeFunction
Delete the cloudgui-editor-… stack to turn editing off. Viewing keeps working. The template is at /cloudgui-editor.yaml.
It's all in your CloudTrail
Each session carries the email of the Cloud GUI user who opened it as its source identity, and the session name cloudgui-…. Your role enforces this: it refuses any session that doesn't name a user. In CloudTrail, filter by user name cloudgui-viewer-… or look for sourceIdentity to see what we did and who on your team did it. One caveat: listing the files inside a bucket is an S3 data event, which CloudTrail records only if you've turned on data events for S3. Everything else Cloud GUI calls, reading log lines included, is a management event, recorded by default.
What we store
Your email address, and for each connected account its number, the role name, your external ID and, if you turned on editing, the name prefixes you chose. That's all. We never store anything we read from your account. To keep pages quick, a list (of buckets, say) may be held in our server's memory for a few minutes and is then dropped. Log lines are never held at all: they pass through our server on their way to your screen, and aren't stored, cached or written to our own logs.
Things we want you to know
- Environment variables. When anyone lists Lambda functions, AWS includes their environment variables in the response, values and all, and IAM has no way to leave them out. Cloud GUI keeps only the variable names and discards the values before anything is shown or cached. If you keep secrets in environment variables, consider Secrets Manager or SSM Parameter Store, which this role can't read.
- The trust policy names our account, not one machine. The role trusts Cloud GUI's AWS account plus your external ID, the same arrangement Datadog and other AWS integrations use. Narrowing it to the single IAM role our service runs as is on our list before general availability.
- ViewOnlyAccess changes over time. AWS adds to it as services launch, so what this role can see grows with AWS, without a new template. That's what lets new Cloud GUI pages work without asking you to update again, but it means you're relying on AWS's idea of view-only. We read version 46 (September 2026) action by action and deny the risky reads we found (above); a read AWS adds later isn't on that list until we add it, in a new template version.
- We're early. Cloud GUI is in private beta and hasn't had an independent audit yet. The template is short on purpose, and the policy it builds on is AWS's own and public, so you can audit both yourself.
How to revoke access
In the AWS console, open CloudFormation → Stacks (region us-east-1), select the stack named cloudgui-viewer-… (and cloudgui-editor-…, if you turned on editing) and click Delete. Access ends as soon as the roles are gone. Disconnecting inside Cloud GUI forgets the account on our side, and the role stays until you delete the stack.
The template
This is the exact read-only file CloudFormation runs (the editing one is here), also at cloudgui-app.s3.us-east-2.amazonaws.com/templates/cloudgui-viewer-v3.yaml. Published versions are never changed. A new permission of ours means a new version that you choose to apply (ViewOnlyAccess is updated by AWS, as above).
# Cloud GUI read-only access, template v3.
#
# Creates ONE IAM role in your account that Cloud GUI (AWS account 487275459989)
# can use, for at most an hour at a time, to view what's in this account. Every
# permission is a read. Nothing here can create, change or delete anything.
#
# What the role can read:
# - AWS's own ViewOnlyAccess policy: the names and settings of resources across
# AWS services (buckets, functions, servers, databases, IAM users and roles, and
# so on), not what's inside them. AWS maintains it and lists every action:
# https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_job-functions.html#jf_view-only-user
# - A few reads that policy leaves out, listed under cloudgui-viewer below.
# - Minus the reads it would allow that can hold secrets or details about people
# (startup scripts, environment variables, job arguments, your app's users,
# subscribers): explicitly denied in the NeverReadSecretsOrPeople statement.
# - Log lines from CloudWatch Logs, only while AllowLogs is 'true'. Log lines are
# whatever your code prints, so they get their own switch: 'false' removes that
# permission and everything else keeps working.
#
# How Cloud GUI uses it:
# - Cloud GUI never receives access keys. It asks AWS STS for a short-lived session on
# this role, and only when the request carries your connection's ExternalId.
# - Each session is stamped with the Cloud GUI user's email (sts:SetSourceIdentity),
# so every call shows up in your CloudTrail under the person who made it.
# - To revoke access, delete this stack. It takes effect immediately.
#
# Plain-English version: https://cloudgui.com/security
AWSTemplateFormatVersion: '2010-09-09'
Description: >-
Cloud GUI read-only access (v3). One IAM role that Cloud GUI can use to view
this account: AWS's ViewOnlyAccess policy, a few extra reads, and log lines while
AllowLogs is true. Delete this stack to revoke access.
Parameters:
ConnectionId:
Type: String
Description: Identifies this connection in Cloud GUI. Filled in for you.
AllowedPattern: '[0-9a-f]{8}'
ExternalId:
Type: String
Description: Cloud GUI must present this value to use the role. Filled in for you.
AllowedPattern: '[0-9a-f]{32}'
AllowLogs:
Type: String
Default: 'true'
AllowedValues: ['true', 'false']
Description: Let Cloud GUI show your CloudWatch log lines. They can contain anything your code prints. 'false' keeps them out, and everything else keeps working.
Conditions:
LogsAllowed: !Equals [!Ref AllowLogs, 'true']
Resources:
ViewerRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub 'cloudgui-viewer-${ConnectionId}'
Description: Read-only access for Cloud GUI (cloudgui.com). Delete the CloudFormation stack to revoke.
MaxSessionDuration: 3600
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
# Cloud GUI may use this role only with your ExternalId, and only when the
# session names the Cloud GUI user it's for (so CloudTrail always can).
- Sid: CloudGUIWithExternalId
Effect: Allow
Principal:
AWS: 'arn:aws:iam::487275459989:root'
Action: sts:AssumeRole
Condition:
StringEquals:
sts:ExternalId: !Ref ExternalId
'Null':
sts:SourceIdentity: 'false'
# Lets that session carry the user's email as its source identity. On its
# own it grants nothing: it only applies within an AssumeRole allowed above.
- Sid: NameTheUser
Effect: Allow
Principal:
AWS: 'arn:aws:iam::487275459989:root'
Action: sts:SetSourceIdentity
# AWS's view-only job-function policy: names and settings, not contents.
ManagedPolicyArns:
- arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
Policies:
- PolicyName: cloudgui-viewer
PolicyDocument:
Version: '2012-10-17'
Statement:
# Find which region each S3 bucket is in
- Sid: FindBucketRegions
Effect: Allow
Action:
- s3:GetBucketLocation
Resource: '*'
# View one Lambda function's settings and web address
- Sid: ViewFunctionSettings
Effect: Allow
Action:
- lambda:GetFunctionConfiguration
- lambda:GetFunctionUrlConfig
Resource: '*'
# View Aurora DSQL clusters
- Sid: ViewDsqlClusters
Effect: Allow
Action:
- dsql:ListClusters
- dsql:GetCluster
Resource: '*'
# View a CloudFront distribution's full settings
- Sid: ViewWebsites
Effect: Allow
Action:
- cloudfront:GetDistribution
Resource: '*'
# See when certificates expire
- Sid: ViewCertificates
Effect: Allow
Action:
- acm:DescribeCertificate
Resource: '*'
# See which servers Systems Manager can reach
- Sid: ViewServerAgents
Effect: Allow
Action:
- ssm:DescribeInstanceInformation
Resource: '*'
# Check whether S3 buckets are public
- Sid: CheckPublicBuckets
Effect: Allow
Action:
- s3:GetBucketPolicyStatus
- s3:GetBucketPublicAccessBlock
- s3:GetAccountPublicAccessBlock
Resource: '*'
# See what your account costs
- Sid: ReadCosts
Effect: Allow
Action:
- ce:GetCostAndUsage
- ce:GetCostForecast
Resource: '*'
# NEVER, even though ViewOnlyAccess allows them: settings and lists that can
# hold secrets or details about people. An explicit Deny overrides any Allow.
- Sid: NeverReadSecretsOrPeople
Effect: Deny
Action:
# Startup scripts
- ec2:DescribeInstanceAttribute
- ec2:DescribeLaunchTemplateVersions
- ec2:DescribeSpotInstanceRequests
- ec2:DescribeSpotFleetRequests
- autoscaling:DescribeLaunchConfigurations
- sagemaker:DescribeNotebookInstanceLifecycleConfig
- sagemaker:DescribeStudioLifecycleConfig
# Environment variables in containers, ML jobs and test runs
- ecs:DescribeTaskDefinition
- ecs:DescribeTasks
- ecs:DescribeDaemonTaskDefinition
- ecs:DescribeExpressGatewayService
- sagemaker:DescribeAIRecommendationJob
- sagemaker:DescribeAlgorithm
- sagemaker:DescribeAutoMLJob
- sagemaker:DescribeAutoMLJobV2
- sagemaker:DescribeDataQualityJobDefinition
- sagemaker:DescribeHyperParameterTuningJob
- sagemaker:DescribeInferenceComponent
- sagemaker:DescribeModel
- sagemaker:DescribeModelBiasJobDefinition
- sagemaker:DescribeModelExplainabilityJobDefinition
- sagemaker:DescribeModelPackage
- sagemaker:DescribeModelQualityJobDefinition
- sagemaker:DescribeMonitoringSchedule
- sagemaker:DescribeOptimizationJob
- sagemaker:DescribePartnerApp
- sagemaker:DescribeProcessingJob
- sagemaker:DescribeTrainingJob
- sagemaker:DescribeTransformJob
- sagemaker:ListCandidatesForAutoMLJob
- devicefarm:ListProjects
- devicefarm:ListRuns
- lambda:ListMicrovmImageVersions
# Job arguments and stack outputs
- glue:GetJobRuns
- glue:ListSessions
- cloudformation:DescribeStacks
- cloudformation:ListExports
# Details about people
- cognito-idp:ListUsers
- cognito-idp:ListUsersInGroup
- sns:ListSubscriptions
- sns:ListSubscriptionsByTopic
- sns:ListPhoneNumbersOptedOut
- sns:ListSMSSandboxPhoneNumbers
- ses:ListContacts
- ses:ListSuppressedDestinations
# Activity and conversations
- cloudtrail:LookupEvents
- lex:GetUtterancesView
Resource: '*'
Tags:
- Key: cloudgui:connection
Value: !Ref ConnectionId
- Key: cloudgui:template-version
Value: '3'
# Reading log lines. This policy exists only while AllowLogs is 'true'.
LogsPolicy:
Type: AWS::IAM::RolePolicy
Condition: LogsAllowed
Properties:
RoleName: !Ref ViewerRole
PolicyName: cloudgui-viewer-logs
PolicyDocument:
Version: '2012-10-17'
Statement:
# Read log lines (only while AllowLogs is true)
- Sid: ReadLogEvents
Effect: Allow
Action:
- logs:FilterLogEvents
- logs:GetLogEvents
- logs:StartQuery
- logs:GetQueryResults
- logs:StopQuery
Resource: '*'
Outputs:
RoleArn:
Description: The role Cloud GUI uses. Cloud GUI finds it on its own; nothing to copy.
Value: !GetAtt ViewerRole.Arn