Original Japanese article: SnowflakeのExternal Volumeで設定するExternal IDの意味を整理してみる
Introduction
I'm Aki, an AWS Community Builder (@jitepengin).
In previous articles, I introduced how to connect Iceberg tables on S3 with Snowflake.
AWS Snowflake Lakehouse: 2 Practical Apache Iceberg Integration Patterns
Connecting Amazon S3 Tables with Snowflake
As covered in those articles, depending on the configuration, working with Iceberg tables on S3 from Snowflake starts with creating an External Volume and then setting sts:ExternalId in the trust policy of the IAM role on the AWS side.
I set this up by the book every time, but recently someone asked me, "What is this External ID actually for?"
It shows up in every setup guide, yet I think it's one of those items people rarely stop to think about.
In this article, I'll go through the meaning of the External ID and some practical points to watch out for, checking against the official AWS and Snowflake documentation.
What Is an External ID?
Let's start with how it works on the AWS side.
An External ID is an optional identifier used in an IAM role's trust policy to specify who is allowed to assume that role.
The official AWS documentation explains that its main purpose is to prevent the confused deputy problem.
https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html
The confused deputy problem is a security issue where an entity without permission gets a more privileged entity to perform an action on its behalf.
The documentation explains it with an example along these lines:
- You let a third party (Example Corp) assume a role in your AWS account.
- Example Corp also accesses the AWS accounts of its other customers.
- If another customer gives Example Corp your role ARN, Example Corp may end up accessing your resources without realizing it.
If you add the External ID that Example Corp issued for you, as a customer, as a condition in the trust policy, then knowing the ARN alone is no longer enough to assume the role.
By the way, the official documentation also states that the External ID is something you receive from the third party, not something you come up with yourself.
In the trust policy, it is written as a condition like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "<snowflake_user_arn>" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "sts:ExternalId": "<snowflake_external_id>" }
}
}
]
}
How the External ID Relates to Snowflake
Next, let's map this onto Snowflake.
From AWS's point of view, Snowflake is a third party that comes to assume an IAM role in your account.
Lining it up against the official AWS example looks like this:
| Item | Official AWS example | Snowflake |
|---|---|---|
| Entity assuming the role | Example Corp | The IAM user for your Snowflake account (STORAGE_AWS_IAM_USER_ARN) |
| Issuer of the External ID | Example Corp | Snowflake (generated when the external volume is created, or specified by the user) |
| Resource being accessed | Your AWS resources | The S3 bucket referenced by the external volume |
The key thing to understand here is the scope of the IAM user.
According to the Snowflake documentation, Snowflake provisions a single IAM user for the entire Snowflake account, and every S3 external volume in that account uses that same IAM user.
https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-external-volume-s3
You can check these values with DESC EXTERNAL VOLUME.
| Property | Description |
|---|---|
STORAGE_AWS_IAM_USER_ARN |
The ARN of the IAM user automatically created for your Snowflake account. Set this as the Principal in the trust policy. |
STORAGE_AWS_EXTERNAL_ID |
The external ID Snowflake uses to establish the trust relationship. Set this as sts:ExternalId in the trust policy. |
In other words, if you only put the IAM user in the trust policy's Principal, there's no narrowing by External ID, so the trust policy can't exclude requests coming from other external volumes that use the same IAM user.
Adding the External ID as a condition lets the trust policy verify the External ID that Snowflake passes when it assumes the role.
If you give each external volume a different External ID, the trust policy condition narrows access down to requests that use the expected External ID.
That said, AWS isn't identifying the external volume itself, so external volumes that share the same External ID can't be told apart.
In fact, the same documentation states that, for security reasons, a newly created or recreated external volume has a different external ID, and the trust relationship can't be resolved until you update the trust policy.
Things to Watch Out For
Now for the points that matter in practice.
STORAGE_AWS_EXTERNAL_ID on an external volume is optional.
According to the CREATE EXTERNAL VOLUME reference, if you omit it, Snowflake generates an external ID automatically.
https://docs.snowflake.com/en/sql-reference/sql/create-external-volume
The case to be careful about is recreating an external volume.
The same reference states that if you recreate it with CREATE OR REPLACE EXTERNAL VOLUME without specifying an external ID, you need to redo the steps for granting access to S3.
This is because the recreation generates a new external ID, which no longer matches the value in the trust policy.
If you forget to update the trust policy after recreating the volume, access to S3 can fail.
Note: if a different team manages IAM on the AWS side, you'll have to ask them to update the trust policy, and recovery can take a while. (I still slip up on this now and then...)
One way to avoid this is to specify the external ID explicitly.
CREATE OR REPLACE EXTERNAL VOLUME exvol
STORAGE_LOCATIONS = (
(
NAME = 'my-s3-location'
STORAGE_PROVIDER = 'S3'
STORAGE_BASE_URL = 's3://<bucket>/'
STORAGE_AWS_ROLE_ARN = 'arn:aws:iam::<account_id>:role/<role_name>'
STORAGE_AWS_EXTERNAL_ID = '<external_id>'
)
);
The external volume configuration guide also explains that by specifying an external ID, you can reuse the same IAM role and external ID across multiple external volumes.
https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-external-volume-s3
The official AWS documentation describes the External ID as something you receive from the third party.
Snowflake, on the other hand, also lets you specify the external ID explicitly, so you can choose the approach that fits your operational requirements.
Note
Specifying and reusing an external ID saves you the hassle when recreating volumes, but it weakens the separation of trust relationships between external volumes.
Key Points
Here's how I'd suggest handling the external ID:
- If you frequently recreate external volumes, for example in a development environment: specify the external ID explicitly to avoid access errors caused by forgetting to update the trust policy.
- If you want to strictly separate the S3 access scope per external volume: use a separate IAM role for each external volume and give each role only the S3 permissions it needs. Separate the External IDs as well when needed, to isolate the trust relationships.
On the other hand, if you reuse an external ID, keep in mind that it widens the set of external volumes that can assume that IAM role.
Also note that the External ID only controls who can assume the IAM role.
Which S3 buckets and paths can actually be accessed is determined by the permission policy attached to the IAM role.
Conclusion
In this article, I went through what the External ID set in a Snowflake External Volume actually means.
To summarize:
- The External ID is an identifier set as a condition in an IAM role's trust policy to prevent the confused deputy problem.
- Snowflake provisions one IAM user per Snowflake account, shared by all S3 external volumes.
- Using a different External ID for each external volume narrows down which requests can assume the IAM role.
- If you omit the external ID and run
CREATE OR REPLACE, the external ID changes and the trust policy must be updated. - Specifying the external ID explicitly lets you reuse it, but weakens the separation of trust relationships between external volumes.
- What determines the S3 access scope is not the External ID but the IAM role's permission policy.
Even for settings you normally just fill in by following the steps, understanding what they mean makes it easier to make the right call when recreating resources or designing permissions.
I hope this article helps anyone trying to make sense of the External ID.
Top comments (0)