Connecting AI agents to S3 without exposing your bucket

S3 is where a lot of real company data lives: documents, exports, logs, training data, customer uploads. It's often the first data source teams try to connect their AI agents to — and the first place they run into serious security tradeoffs.

This article walks through the available approaches for giving AI agents S3 access, from the dangerously simple to the properly secure, and explains when each is appropriate.

Approach 1: Static IAM access keys in agent config (don't do this)

The most common approach because it's the fastest: create an IAM user, generate access keys, put them in the agent's environment variables or system prompt.

AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=abc123...
AWS_DEFAULT_REGION=us-east-1

The problems are significant. IAM access keys are long-lived credentials — by default, they don't expire. Once generated, they grant access until explicitly revoked. If they appear in a log, a model output, or a leaked context window, they're valid until someone notices and rotates them.

Static keys also can't be scoped below the IAM policy level. If the agent needs to read from one bucket but your IAM user has broader permissions, the key grants all of that access.

When acceptable: Never in production. Possibly acceptable for a disposable development environment with read-only access to non-sensitive data.

Approach 2: IAM roles with instance profiles (better, but limited)

If your agent runs on EC2, ECS, Lambda, or another AWS compute service, you can attach an IAM role directly to the compute resource. The agent inherits credentials from the role via the instance metadata service — no static keys to manage.

This is a significant improvement. Credentials rotate automatically. They're not stored in your application configuration. An IAM role can be scoped to specific buckets and operations via policy.

The limitations are real, though. This only works if your agent runs on AWS infrastructure. If it runs on your laptop, in a container somewhere else, or on a third-party agent platform, instance profiles aren't available. And a compromised agent process can still exfiltrate data within its role's permissions — there's still no per-agent scoping or audit trail beyond CloudTrail.

When appropriate: Agents deployed on AWS infrastructure, when you have good IAM policy hygiene and CloudTrail enabled.

Approach 3: Pre-signed URLs (good for specific use cases)

Pre-signed URLs are time-limited URLs that grant access to a specific S3 object. A backend service generates a pre-signed URL for a specific file, passes it to the agent, and the agent downloads the file directly. The agent never touches AWS credentials.

import boto3

s3 = boto3.client('s3')
url = s3.generate_presigned_url(
    'get_object',
    Params={'Bucket': 'my-bucket', 'Key': 'path/to/file.pdf'},
    ExpiresIn=300  # 5 minutes
)

This is elegant for read-only access to known files. The agent gets a URL, downloads the content, does its work. No credentials in agent context. URL expires after use.

The constraints are significant for agentic use cases. Pre-signed URLs are file-specific — you can't give an agent a pre-signed URL that lets it list or search a bucket. For agents that need to discover and process multiple files, this requires a separate orchestration layer to generate URLs on demand. It also provides no audit trail of what the agent accessed — just that the URL was generated.

When appropriate: Agents that receive specific file references from a trusted orchestration layer and only need to read those specific files.

Approach 4: Mount tokens with a proxy layer (the right answer)

The secure pattern for agents that need real S3 access — the ability to list, search, read, and potentially write — is to put a proxy layer between the agent and S3. The agent authenticates with a mount token, the proxy validates the token and enforces the permission scope, and the proxy handles the actual S3 API calls.

This is what Agent Mounts provides for S3. The agent calls the mount API:

curl -H "Authorization: Bearer mount_tok_..." \
  "https://mount.agentmounts.com/s3/my-bucket/list?prefix=reports/2025/"

The proxy validates the token, confirms the agent is authorized to list that prefix, makes the S3 API call using the real AWS credentials it holds in its vault, and returns the result. The agent never sees AWS credentials. Every operation is logged.

The advantages compound:

Pre-signed URLs solve a specific narrow problem. Mount tokens solve the general problem of giving agents safe, audited, revocable access to S3 at whatever scope they need.

Choosing the right approach

Use static IAM keys: never in production.

Use IAM role instance profiles: when your agent is deployed on AWS and you're comfortable with CloudTrail as your audit trail. Good baseline, not sufficient for sensitive data.

Use pre-signed URLs: when your orchestration layer knows exactly which files the agent needs and can generate URLs on demand. Works well for document processing pipelines.

Use mount tokens: when agents need to search, discover, or operate on multiple files; when you need per-agent permission scoping; when compliance requires a detailed audit trail; when agents run outside AWS infrastructure.

For most serious agent deployments with S3, the mount token pattern is the right answer. The additional infrastructure is minimal; the security properties are significantly better.

Connect your agents to S3 securely

Agent Mounts handles S3 and 7 other data sources with scoped mount tokens, full audit logging, and zero credential exposure.

Get early access