AWS Builder Center

How to Give an AI Agent AWS Tools Without Giving It Full Access

AI agents become much more useful when they can interact with cloud resources. But giving an agent broad AWS permissions creates a dangerous security boundary. This article shows how to design an agent that can use specific AWS tools while keeping permissions tightly controlled.

An AI agent that can only answer questions is useful.
An AI agent that can actually interact with your infrastructure is much more powerful.
For example, imagine asking:
“Check whether my application is running.”
The agent could inspect an AWS resource and return the result.
Now imagine asking:
“Delete the production database.”
This is where things become interesting.
The problem is not whether an AI model is capable of understanding the request.
The problem is what permissions the agent has after it understands the request.
Giving an agent administrator-level access to AWS is one of the easiest ways to turn a useful AI application into a serious security risk.
The better approach is simple:
Give the agent tools, not unrestricted AWS access.

The Core Idea

Instead of allowing an AI agent to interact directly with everything in an AWS account, put a controlled tool layer between the agent and the AWS resources.
A simple architecture looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
User
|
v
AI Agent
|
v
AgentCore Gateway / Tool Layer
|
+--------+--------+
| |
v v
Tool: EC2 Tool: S3
| |
v v
Lambda Lambda
| |
+--------+--------+
|
v
AWS Resources
The important part is that the agent does not receive a general-purpose AWS identity.
Instead, it receives access to a small set of predefined tools.
Amazon Bedrock AgentCore Gateway is designed to provide a unified connectivity layer between agents and tools. Gateway targets can include Lambda functions, API Gateway endpoints, OpenAPI-based tools, and MCP servers.

Why Full AWS Access Is a Bad Idea

A common shortcut is to attach a broad AWS managed policy to the role used by an AI application.
That may make development easier, but it creates a much larger blast radius.
Consider an agent with permissions like:
1
2
3
4
5
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
Now the agent potentially has access to far more than it actually needs.
Even if the model is instructed:
“Never delete resources.”
IAM does not understand the instruction.
IAM understands permissions.
This leads to an important security principle:
Prompt instructions are not a replacement for authorization.
The model can decide what tool it wants to use, but AWS IAM should decide whether that action is actually allowed.

Step 1: Decide What the Agent Actually Needs

Before creating IAM policies, define the agent's capabilities.
Suppose we are building a cloud monitoring agent.
We only want it to:
1
2
3
4
5
6
7
8
9
✓ Read EC2 instance status
✓ Read selected S3 objects
✓ Read CloudWatch metrics

✗ Start instances
✗ Stop instances
✗ Terminate instances
✗ Delete S3 objects
✗ Modify IAM policies
That list becomes our security boundary.
The agent does not need permission to perform every action supported by the AWS service.
It only needs the specific actions required by the application.

Step 2: Turn AWS Operations Into Tools

Instead of exposing raw AWS APIs to the model, create explicit tools.
For example:
1
2
3
get_ec2_status()
read_application_logs()
get_cloudwatch_metric()
The agent can choose between these tools based on the user's request.
A tool might conceptually look like:
1
2
3
4
5
6
7
{
"name": "get_ec2_status",
"description": "Returns the current status of an approved EC2 instance",
"input": {
"instance_id": "string"
}
}
The model decides:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
User:
"Is the application server running?"

↓

Agent:

I should use get_ec2_status()

↓

Tool Layer:

Validate request

↓

AWS API:

DescribeInstances

↓

Response:

running
The agent never needs a general-purpose AWS administrator credential.

Step 3: Put the Tool Behind Lambda

A useful pattern is to implement the actual AWS operation inside a Lambda function.
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import boto3

ec2 = boto3.client("ec2")

def lambda_handler(event, context):
instance_id = event["instance_id"]

response = ec2.describe_instances(
InstanceIds=[instance_id]
)

state = response["Reservations"][0]["Instances"][0]["State"]["Name"]

return {
"instance_id": instance_id,
"state": state
}
The Lambda function performs the AWS operation.
The Lambda execution role determines what the function is allowed to do.
This creates a useful separation:
1
2
3
4
5
6
7
8
9
10
11
12
13
AI decision
|
v
Tool invocation
|
v
Lambda
|
v
IAM authorization
|
v
AWS resource
Amazon Bedrock documentation also supports this tool-oriented architecture through Lambda-backed action groups and AgentCore Gateway targets.

Step 4: Give Lambda Only the Permission It Needs

Now comes the most important part.
The Lambda function should receive a narrowly scoped IAM role.
For our monitoring example, suppose the only required operation is reading EC2 instance information.
The role can be limited to the required API action:
1
2
3
4
5
6
7
8
9
10
11
12
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances"
],
"Resource": "*"
}
]
}
This is already much better than:
1
"Action": "*"
But we can go further.
The goal should always be to reduce permissions to the smallest practical set.
AWS recommends applying least privilege to AgentCore Runtime permissions, avoiding unnecessary wildcard resources, and creating custom policies for production rather than relying on broad development policies.

Step 5: Restrict the Resource

Resource-level restrictions are even more useful for services that support them.
Imagine an agent that needs to read application logs from S3.
Instead of:
1
2
3
4
5
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "*"
}
restrict it to the application bucket and prefix:
1
2
3
4
5
6
7
8
9
10
11
12
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-application-logs/agent-readable/*"
}
]
}
Now the Lambda function cannot use that permission to read arbitrary objects across the account.
The permission has become:
1
2
3
4
5
6
7
8
9
AWS Account
|
+-- Other buckets ✗
|
+-- Production secrets ✗
|
+-- Application logs ✓
|
+-- agent-readable/*
This is what least privilege looks like in practice.

Step 6: Restrict Which Tools the Agent Can Reach

IAM controls AWS actions, but there is another important layer:
Which tools can the agent invoke in the first place?
AgentCore Gateway provides a centralized way to expose tools to agents and supports authorization controls for gateway access. AWS also documents fine-grained controls at the operation and parameter level.
This gives us two separate security questions:
1
2
3
4
5
6
7
8
9
10
11
12
13
Question 1:
Can the agent invoke this tool?

↓

Gateway / authorization policy

Question 2:
Can the tool perform this AWS action?

↓

IAM policy
Using both layers gives us defense in depth.

A Better Architecture

Putting everything together:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
USER
|
v
AI AGENT
|
v
AgentCore Gateway
|
Authorization Layer
|
+------------+------------+
| |
v v
get_ec2_status() read_logs()
| |
v v
Lambda Lambda
| |
v v
IAM Role #1 IAM Role #2
| |
v v
EC2 Read S3 Read-Only
Notice something important.
There is not one giant role for the whole agent.
Different tools can have different execution boundaries.
That means compromising one tool does not automatically give the attacker every permission in the application.

What Happens When the User Asks for Something Dangerous?

Imagine the user says:
“Stop the production EC2 instance.”
The model might understand the request correctly.
But understanding the request does not mean the action should be possible.
Suppose our toolset only contains:
1
2
3
get_ec2_status
read_logs
get_metrics
There is no:
1
stop_ec2_instance
The agent cannot invoke a tool that was never exposed.
Even if someone later adds a stop-instance tool, IAM can still deny the operation.
This gives us multiple security boundaries:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
User Request
|
v
Model Decision
|
v
Available Tools
|
v
Authorization Policy
|
v
IAM Policy
|
v
AWS Resource
A failure at any authorization layer should stop the operation.

The "Read vs Write" Rule

A useful design rule for cloud agents is:
Start with read-only capabilities.
For example:
1
2
3
4
5
6
7
READ

✓ describe instances
✓ read logs
✓ inspect metrics
✓ retrieve configuration
✓ check deployment status
Only introduce write operations when there is a strong reason:
1
2
3
4
5
6
7
WRITE

⚠ restart service
⚠ deploy application
⚠ modify configuration
⚠ create resources
⚠ delete resources
For high-impact operations, adding human approval can provide another control.
The architecture can become:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Agent
|
v
Request dangerous action
|
v
Authorization
|
v
Human approval
|
v
Tool
|
v
AWS
This is especially useful for destructive or expensive operations.

Don't Put AWS Credentials in the Prompt

An obvious but important rule:
Never put AWS access keys in:
1
2
3
4
5
System prompts
User prompts
Tool descriptions
Source code
Environment variables committed to Git
The agent should not need to know the secret credentials used by the infrastructure.
AWS permissions should be handled through IAM roles and temporary credentials where appropriate.
The model should see something like:
1
get_ec2_status
not:
1
2
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...

Add Guardrails, But Don't Confuse Them With IAM

Amazon Bedrock Guardrails can help filter unwanted inputs and outputs, and AWS supports associating guardrails with agents.
But guardrails and IAM solve different problems.
1
2
3
4
5
6
7
Guardrails
|
+-- What content should be allowed?

IAM
|
+-- What AWS actions should be allowed?
You should not rely on a guardrail to replace IAM authorization.
A good architecture uses both:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
User
|
v
Guardrails
|
v
AI Agent
|
v
Tool Authorization
|
v
IAM
|
v
AWS
AWS also provides mechanisms for enforcing the use of specific guardrails through IAM condition keys in supported inference APIs.

Test the Policy Before Trusting It

Another useful practice is to test IAM policies before deploying them.
AWS IAM Policy Simulator can evaluate identity-based policies, permissions boundaries, SCPs, and resource-based policies without sending a real request to an AWS service.
For example, test:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Can the agent read EC2 status?

YES

Can the agent stop an instance?

NO

Can the agent delete an S3 object?

NO

Can the agent read an unrelated bucket?

NO
The goal is not:
“Does the agent work?”
The goal is:
“Does the agent work while everything it doesn't need remains inaccessible?”

A Practical Security Checklist

Before putting an AWS-powered AI agent into production, I would verify:
1
2
3
4
5
6
7
8
9
10
11
[ ] No administrator-level role
[ ] No hardcoded AWS credentials
[ ] Tools are explicitly defined
[ ] Tool access is restricted
[ ] IAM policies use least privilege
[ ] Resources are scoped where possible
[ ] Write operations are minimized
[ ] Destructive actions require stronger controls
[ ] Guardrails are configured where appropriate
[ ] IAM policies are tested
[ ] Cloud activity is logged and monitored
AWS's current AgentCore security guidance also recommends least privilege, resource scoping, IAM conditions where applicable, and IAM Access Analyzer for validating policies.

The Bigger Lesson

The most important architectural shift is this:
1
2
3
4
5
6
7
8
9
BAD

AI Agent
|
v
AWS Admin Credentials
|
v
Everything
versus:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BETTER

AI Agent
|
v
Approved Tools
|
v
Authorization
|
v
Least-Privilege IAM
|
v
Specific AWS Resources
An AI agent does not need unlimited access to be useful.
It needs well-designed capabilities.
That is the difference between an AI agent that merely has access to your cloud and an AI agent that can operate inside your cloud safely.

Conclusion

Giving an AI agent AWS capabilities is not inherently dangerous.
Giving it unnecessary authority is.
The safest architecture is to treat every tool as a controlled boundary:
1
2
3
4
5
6
7
8
9
Agent
↓
Tool
↓
Authorization
↓
IAM Role
↓
Specific Resource
Start with read-only tools.
Restrict the resources.
Separate tool permissions where practical.
Add stronger approval mechanisms around dangerous actions.
And remember:
The model decides what it wants to do. IAM decides what it is allowed to do.
That distinction is what makes an AI agent manageable in a real cloud environment.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article