Security Risks of Cross-Account Amazon S3 Access

Galaxy Glossary

What are the security risks of cross-account Amazon S3 access?

Cross-account S3 access lets principals in one AWS account read or write buckets in another, but misconfiguration can expose data, enable privilege escalation, or violate compliance.

Sign up for the latest in SQL knowledge from the Galaxy Team!
Welcome to the Galaxy, Guardian!
Oops! Something went wrong while submitting the form.

Description

Granting cross-account access to Amazon S3 is a common pattern for data sharing and multi-tenant architectures, but every policy you attach to a bucket or IAM role expands the attack surface. Understanding the risks, mitigation techniques, and monitoring strategies is essential for anyone responsible for securing data in S3.

Why Cross-Account S3 Access Exists

Organizations use multiple AWS accounts for isolation, billing, or SDLC environments. Sooner or later those accounts must exchange data: analytics teams pull raw logs from a production account, external vendors drop CSV exports for finance, or an acquired company migrates legacy datasets. Amazon S3 makes this easy with bucket policies, IAM roles, and AWS Resource Access Manager (RAM). Unfortunately, a single overly permissive statement may expose petabytes of sensitive data to unintended principals.

Core Security Risks

1. Accidental Public Exposure

The most reported S3 incident is still the “world-readable bucket.” When Account B is granted s3:GetObject using the wildcard principal "*" or an AWS account ID that was typed incorrectly, the data can be publicly listed and downloaded. Attackers continuously scan for such misconfigured buckets.

2. Excessive Privileges (Write or Delete)

Cross-account write access (s3:PutObject, s3:DeleteObject) enables data poisoning. A compromised developer account could overwrite trusted Parquet files with malicious payloads that downstream jobs automatically load. Similarly, s3:DeleteBucket permissions can wipe critical data.

3. Cross-Account Replication Loops

Using S3 Replication without strict scoping can create circular replication rules. Attackers who obtain permissions in Account B can push versioned objects back to Account A, polluting or overwriting original data.

4. Privilege Escalation via IAM Role Assumption

It’s common to let an external account assume an IAM role that owns a bucket. If sts:AssumeRole is too permissive (e.g., wildcard external ID), an attacker could pivot from S3 to other services like DynamoDB or even create new IAM users.

5. Lateral Movement to VPC Endpoints

A misconfigured VPC endpoint policy can allow principals from Account B to access private buckets in Account A’s VPC, bypassing network security controls.

6. Compliance & Data Residency Violations

Sharing data with another account may violate PCI-DSS segmentation or GDPR residency if that account is outside a defined compliance boundary. Without proper tagging and logging, auditors cannot prove who accessed which dataset.

Attack Surface Explained

Buckets and Objects

The bucket policy is the main enforcement point. Every Principal, Action, and Condition triple must be evaluated for least privilege. Object ACLs and S3 Access Points add additional layers that must align.

IAM Roles and Policies

Roles that the external account assumes should include trust policies with specific ExternalId conditions, restricting who can call sts:AssumeRole. Inline or attached policies on those roles should allow only S3 actions that are required.

Network Controls

When S3 PrivateLink endpoints (Interface VPC Endpoints) are involved, both the endpoint policy and the bucket policy must be correct. Otherwise, data can be exfiltrated privately, making detection harder.

Best Practices for Secure Cross-Account Access

Principle of Least Privilege

  • Grant only needed actions (s3:GetObject, s3:ListBucket) and only on specific ARNs.
  • Avoid "*" in Resource and Principal.

Use IAM Roles with External IDs

Require a unique External ID that the third-party must supply when calling AssumeRole. This mitigates the confused deputy problem.

Enforce SSL and MFA

Add bucket policy conditions: "aws:SecureTransport": "true" and "aws:MultiFactorAuthPresent": "true" where feasible.

Block Public Access Settings

S3 Block Public Access should be enabled at both the account and bucket level unless you are intentionally hosting public content. Cross-account access can coexist with blocked public access when using IAM roles.

Use AWS Resource Access Manager (RAM)

For intra-organization sharing, RAM provides a higher-level abstraction with automated principal management. RAM shares respect SCPs, making them easier to audit.

Tag and Encrypt Everything

  • Use KMS keys with key policies that restrict principals.
  • Apply data classification tags (Confidentiality=High) and require IAM condition keys "s3:RequestObjectTag/Confidentiality": "High" for writes.

Continuous Monitoring

Enable AWS CloudTrail, S3 Server Access Logging, and Amazon GuardDuty. Write Detective controls in AWS Config to flag policies that include wildcards.

Practical Example

Suppose Account A owns bucket log-archive-123 and wants Account B’s Snowflake ingestion role to read only yesterday’s logs.

{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::222222222222:role/snowflake-reader"
},
"Action": ["s3:GetObject"],
"Resource": [
"arn:aws:s3:::log-archive-123/2023-*/parquet/*"
],
"Condition": {
"StringEquals": {
"s3:DataAccessPointAccount": "111111111111"
}
}
}]
}

Account B must then assume snowflake-reader with an external ID like sf-prod-ingest.

Common Misconceptions

  • “Block Public Access prevents all cross-account sharing.” False. BPA stops world access but not explicit cross-account principals.
  • “Encrypting with KMS is enough.” If the key policy is lax, anyone with ciphertext and kms:Decrypt permission can read the data.
  • “Replication auto-handles permissions.” The destination bucket needs additional role permissions; otherwise, replication fails silently.

Common Mistakes and How to Fix Them

1. Using Wildcard Principals

Why it’s wrong: "Principal": "*" or "AWS": "*" means every AWS account can access the resource.

Fix: Always specify the exact account or IAM role ARN. If multiple accounts require access, enumerate them explicitly.

2. Forgetting to Restrict Object ACLs

Why it’s wrong: Even if the bucket policy is strict, individual objects can be made public by a writer.

Fix: Add a bucket policy denying PutObject unless the ACL is private and the request is encrypted.

3. Skipping Logging and Alerting

Why it’s wrong: Without CloudTrail or GuardDuty, data theft can go unnoticed.

Fix: Enable logging in all regions and set up automated alerts for anomalous access patterns, such as a new external IP reading large volumes.

Working Code Example

The following Terraform snippet creates an IAM role in Account A that Account B can assume, the corresponding bucket policy, and a Config rule to detect wildcard principals.

```hcl# IAM role in Account Aresource "aws_iam_role" "shared_logs_reader" { name = "shared-logs-reader" assume_role_policy = jsonencode({ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::222222222222:root" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": {"sts:ExternalId": "sf-prod-ingest"} } }] })}resource "aws_iam_role_policy" "reader_policy" { role = aws_iam_role.shared_logs_reader.id policy = jsonencode({ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::log-archive-123/*" }] })}# S3 bucket policy granting access via roleresource "aws_s3_bucket_policy" "log_archive_policy" { bucket = "log-archive-123" policy = jsonencode({ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "AWS": aws_iam_role.shared_logs_reader.arn }, "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::log-archive-123/*" }] })}# AWS Config rule to detect wildcard principals in bucket policiesresource "aws_config_config_rule" "s3_bucket_policy_no_wildcards" { name = "s3-bucket-policy-no-wildcards" source { owner = "AWS" source_identifier = "S3_BUCKET_PUBLIC_READ_PROHIBITED" }}```

Key Takeaways

  • Always apply least-privilege and avoid wildcards.
  • Use roles with external IDs instead of static access keys.
  • Complement bucket policies with KMS encryption, logging, and Config rules.
  • Regularly audit cross-account permissions with IAM Access Analyzer.

Further Reading

Why Security Risks of Cross-Account Amazon S3 Access is important

S3 stores critical business data. Granting access to other AWS accounts is necessary for data sharing but introduces risks like public exposure, data poisoning, privilege escalation, and compliance violations. Misconfigurations can be exploited within minutes. Understanding these risks enables teams to design least-privilege policies, use encryption, and monitor for threats—essential skills for any data engineer or security professional.

Security Risks of Cross-Account Amazon S3 Access Example Usage



Security Risks of Cross-Account Amazon S3 Access Syntax



Common Mistakes

Frequently Asked Questions (FAQs)

How do I safely grant read-only access to an external vendor?

Create an IAM role in your account with s3:GetObject on the specific bucket prefix. Require an External ID and enable Server-Side Encryption. Provide the role ARN, not access keys, to the vendor.

Is cross-account access possible when Block Public Access is on?

Yes. BPA blocks public principals but explicit IAM roles from other accounts remain valid, as long as the bucket policy allows them.

Can IAM Access Analyzer detect risky cross-account policies?

Absolutely. Access Analyzer reviews bucket and IAM policies, identifying resources shared outside your organization or publicly accessible.

Do I need to worry about Galaxy when configuring S3 cross-account access?

Galaxy is a SQL editor and doesn’t manage S3 policies directly. However, if you use S3 as external tables in a data warehouse queried via Galaxy, you must secure S3 just as rigorously to prevent unauthorized SQL reads.

Want to learn about other SQL terms?

Trusted by top engineers on high-velocity teams
Aryeo Logo
Assort Health
Curri
Rubie
BauHealth Logo
Truvideo Logo
Welcome to the Galaxy, Guardian!
Oops! Something went wrong while submitting the form.