If you have ever connected a third-party platform to your AWS account, you have probably seen a setup step that asks you to add an External ID to an IAM role trust policy.
Most people copy it, paste it, and move on.
That is understandable. The AWS setup works, the connection verifies, and the dashboard starts loading data.
But External ID is not a random setup value. It exists for a specific security reason, and it matters most when you are granting access to a SaaS product that serves many AWS customers.
If a cloud security, cost, or posture management tool asks you to create a cross-account IAM role, you should understand what the External ID does before you connect production AWS accounts.
The basic setup: cross-account IAM role access
The safer way to connect a third-party AWS tool is usually through a cross-account IAM role.
Instead of creating an IAM user, generating access keys, and pasting those keys into a vendor product, you create an IAM role inside your AWS account. That role has a trust policy that allows a specific AWS principal from the vendor to assume it.
When the tool needs to scan your account, it calls AWS STS AssumeRole.
If AWS accepts the request, STS returns temporary credentials. Those credentials expire automatically.
This is much better than handing out long-lived access keys because the customer keeps control of the role, the permissions, and the trust relationship.
If you want to revoke access, you update or delete the role. You do not need to hunt down an access key that may have been copied into logs, scripts, CI variables, or a vendor database.
For AWS security tools, this matters. A product that is supposed to reduce cloud risk should not ask you to create a permanent secret as the first step.
Where External ID fits
AssumeRole is the access mechanism.
External ID is an additional condition that helps make sure the AssumeRole request is meant for the right customer.
A typical third-party SaaS provider serves many customers. Many of those customers create IAM roles that trust the same AWS principal owned by that provider.
From AWS’s point of view, the vendor principal may be allowed to assume many customer roles. That is expected.
But the trust policy still needs a way to say:
“This vendor principal can assume this role only when it provides the External ID that belongs to this customer.”
That is the job of External ID.
It is a value included in the AssumeRole request. The IAM role trust policy can require that exact value through a condition. If the value does not match, AWS denies the request.
The confused deputy problem
External ID exists to help prevent the confused deputy problem.
The idea is not specific to AWS. It is an old security problem where a trusted system is tricked into using its authority on behalf of the wrong party.
In AWS cross-account access, the pattern looks like this:
Customer A uses a SaaS platform.
Customer B also uses the same SaaS platform.
Both customers create IAM roles that trust the SaaS provider’s AWS principal.
Now imagine Customer A tries to cause the SaaS provider to assume Customer B’s role. The provider is trusted by Customer B, so AWS needs another way to know whether the request is actually meant for Customer B.
External ID gives AWS that additional check.
Customer B’s role trust policy requires Customer B’s External ID. If the SaaS provider sends the wrong External ID, the AssumeRole request fails.
This does not solve every security problem. It solves a specific cross-account authorization problem. But that problem is important enough that any serious AWS SaaS integration should handle it cleanly.
A simple trust policy example
A simplified trust policy might look like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "example-external-id"
}
}
}
]
}There are three important pieces here.
First, the Principal identifies the AWS account or role that is allowed to request access.
Second, the Action allows sts:AssumeRole.
Third, the Condition requires the expected sts:ExternalId.
Without the condition, the trusted principal alone may be enough to assume the role. With the condition, the trusted principal also has to provide the correct customer-specific value.
That is the practical security improvement.
External ID is not a password
It is tempting to think of External ID as a password.
That is not quite right.
A password is usually selected by a user and used to authenticate that user. External ID is a value used inside an AWS trust relationship to help a third-party service prove that an AssumeRole request belongs to the correct customer context.
The customer should not need to invent it.
A well-designed SaaS platform should generate it, bind it to the correct customer or workspace, and show it during setup. The customer then places it into the IAM role trust policy.
The customer still controls the AWS role. The SaaS controls the mapping between customer workspace and External ID.
That division is useful.
The customer should not be able to accidentally choose a weak or duplicate value. The service should not rely on user-selected text as the trust boundary.
External ID should be generated by the SaaS
When evaluating an AWS SaaS product, pay attention to how it handles External ID.
A stronger pattern looks like this:
- The SaaS generates the External ID server-side.
- The value is unique to the customer workspace or account connection.
- The browser cannot override it.
- The IAM role setup instructions include the generated value.
- The product verifies the role by calling STS with that value.
- The product stores only what it needs to identify and verify the connection.
This removes a surprising amount of ambiguity.
It also avoids a common setup smell: asking the customer to type any External ID they want.
If the customer can choose any value, the product now has to trust that customers will choose something unique and hard to guess. That is not a good assumption for a security-sensitive integration.
External ID does not replace least privilege
External ID is necessary, but it is not sufficient.
A role can have a perfect External ID condition and still be overprivileged.
That is why External ID should sit beside least privilege, not replace it.
For a cloud security scanner, the IAM permissions should usually be read-only. The scanner may need broad visibility, but broad visibility is not the same as broad control.
A scanner might need to call APIs that list resources, describe configurations, inspect IAM structure, read security service status, or query cost metadata.
That does not mean it needs permission to modify infrastructure.
A safer policy shape is built around actions like:
List*
Describe*
Get*For configuration metadata, that is usually enough to answer the important posture questions:
- Which resources exist?
- Which ports are exposed?
- Which buckets are public?
- Which roles look risky?
- Which access keys are stale?
- Which services lack logging, backup, or encryption?
- Which resources look idle or wasteful?
External ID protects the cross-account trust path. Least privilege limits what can happen after access is granted.
You need both.
External ID does not mean the scanner should read your data
Another common mistake is treating “read-only” as one big category.
It is not.
There is a major difference between reading configuration metadata and reading customer data.
A cloud posture tool may need to know that an S3 bucket is public. It does not need to read the objects inside that bucket.
It may need to know that a DynamoDB table exists and whether encryption is configured. It does not need to read table items.
It may need to know that a Lambda function uses an outdated runtime. It does not need to inspect application payloads.
For a metadata-only scanner, the IAM policy should avoid data-plane reads such as:
s3:GetObject
dynamodb:GetItem
dynamodb:Query
dynamodb:Scan
logs:GetLogEvents
states:GetExecutionHistory
athena:GetQueryResultsA vendor may have a valid reason for some of these in a specific product category. But for a normal AWS security and cost posture scanner, data-plane access should not be the default.
If a tool asks for it, ask why.
What can go wrong without External ID
Without External ID, the trust policy may depend only on the vendor’s AWS principal.
That means the role trusts the vendor, but it may not strongly bind the AssumeRole request to the correct customer context.
In small internal setups, that may not seem like a big deal. In a third-party SaaS environment, it is different.
A vendor might have thousands of customers. Many customers may trust the same vendor AWS account. The vendor’s application layer must map customers to role ARNs, account IDs, and scans correctly.
External ID gives AWS a policy-level guardrail. Even if the wrong role ARN is used in the wrong customer context, the trust policy can reject the request because the External ID does not match.
That is valuable because it moves part of the protection into AWS IAM, not just the vendor application.
Application checks are still necessary. But when the AWS trust policy can enforce the customer binding too, the overall design is stronger.
What good onboarding should show
A good AWS onboarding flow should not hide the trust model.
It should make it obvious.
Before connecting a production account, you should be able to see:
- The IAM role ARN you are creating.
- The trusted AWS principal.
- The External ID value.
- The policy permissions.
- Whether the policy is read-only.
- Whether the scanner reads metadata only.
- How to revoke access.
- What AWS services are covered.
- Whether the product supports CloudFormation or Terraform setup.
That level of clarity matters because connecting a cloud account is not the same as signing into a normal web app. You are creating a trust relationship between your infrastructure and a third-party system.
The setup screen should respect that.
How trueno handles External ID
trueno uses the AWS cross-account role model for connected AWS accounts.
The customer creates a read-only IAM role in their AWS account. trueno assumes that role server-side through AWS STS. The role trust policy is gated with an External ID tied to the customer workspace, and the client cannot choose or override that value.
The scanner is designed around configuration metadata. It uses AWS metadata to find public exposure, identity risk, compliance gaps, operational drift, and cost waste. It does not require long-lived AWS access keys for routine scanning, and it does not require broad infrastructure write permissions.
That is the important part.
The product can inspect enough of the AWS account to produce useful findings, but the access model keeps the customer in control:
- Temporary credentials.
- Read-only role.
- External ID protection.
- Metadata-only scanning.
- One IAM role that can be revoked from AWS.
This is the kind of access model a cloud security product should start with.
How to review a vendor’s AWS access model
Before you connect any AWS SaaS product, ask these questions:
- Do you use STS
AssumeRole? - Do you require long-lived AWS access keys?
- Is an External ID required in the trust policy?
- Who generates the External ID?
- Can the browser or customer override it?
- Is the IAM role read-only?
- Which exact AWS actions are included?
- Do you call any data-plane APIs?
- Can access be revoked by deleting one IAM role?
- What happens if
AssumeRolefails? - Can I inspect the policy before deployment?
- Do you support CloudFormation or Terraform setup?
You do not need a perfect answer to every question, but you do need clear answers.
Vague answers are a warning sign.
A practical rule for buyers
When a security tool asks for AWS access, evaluate the access model before the dashboard.
A beautiful dashboard does not compensate for a risky connection model.
A strong AWS SaaS integration should have these properties:
- Temporary credentials through STS
- External ID protection
- Customer-controlled IAM role
- Read-only permissions by default
- Metadata-only scanning where possible
- No long-lived AWS access keys
- Clear revocation path
- Clear documentation of required permissions
That is the baseline.
Everything else comes after.
Final thought
External ID is a small field in an IAM trust policy, but it carries a lot of weight.
It helps prevent a trusted service from becoming a confused deputy. It binds cross-account access to the right customer context. It makes the trust relationship more explicit.
For any AWS SaaS product, that matters.
If the product is supposed to help you manage cloud security, cost, and operational risk, its own access model should be secure by design.
Start there.