⚠️ Disclaimer: All code examples in this post are provided for illustrative and educational purposes only. They are not intended for direct use in production environments without thorough review, testing, and validation against your specific security, compliance, and operational requirements. API parameter names and structures shown may differ from the actual service API—always consult the Amazon Bedrock AgentCore API Reference for the latest specifications. Always conduct your own testing before deploying to production.

Memory Isolation in Amazon Bedrock AgentCore

📅 2026-02-28📖 ~18 min readAgentCoreMemoryArchitecture
When you deploy agentic AI systems to production, one of the most critical—and often overlooked—challenges is memory isolation. How do you ensure that User A’s conversation history, preferences, and semantic memories don’t leak into User B’s agent interactions? Amazon Bedrock AgentCore provides a comprehensive memory isolation system that solves these challenges out of the box.

The Multi-Tenant Memory Challenge: Why Isolation Is Non-Negotiable

Imagine you’re building an enterprise agentic AI platform that serves your entire organization. You deploy three specialized agents: an HR assistant for employee benefits and leave management, an IT support agent for helpdesk tickets, and a sales agent for CRM interactions. All three agents use Amazon Bedrock AgentCore Memory to remember conversation history, extract user preferences, and maintain context across sessions. This shared memory capability transforms these agents from stateless question-answering systems into intelligent assistants that learn and adapt over time.

But here’s the challenge: How do you ensure that the HR agent, which processes sensitive salary discussions, cannot access the IT support agent’s helpdesk conversations? And within the HR agent itself, how do you guarantee that Employee X never sees Employee Y’s leave requests or benefits inquiries?

This is the multi-tenant memory isolation problem, and getting it wrong has serious consequences:

  • Compliance Violations: If an HR agent’s memory inadvertently contains IT support conversations, you’ve violated the principle of least privilege. In regulated industries, this data leakage could breach GDPR (unauthorized processing of personal data), HIPAA (exposure of protected health information), or SOC 2 requirements (inadequate access controls). The financial and reputational costs can be devastating.
  • Data Poisoning Across Tenants: In a shared memory system without proper isolation, one user’s interactions could influence another user’s responses. For example, if User A deliberately feeds malicious information to the sales agent (“our competitor’s pricing is X”), this could be stored in long-term memory and affect User B’s experience. This is memory poisoning, and it undermines trust in your entire platform.
  • Loss of Customer Trust: Nothing erodes trust faster than users discovering their private conversations aren’t actually private. If Employee X asks the HR agent about their disability accommodations, and Employee Y somehow sees this in a shared context, the damage goes beyond technical—it’s a fundamental breach of confidentiality.

For production multi-agent platforms, isolation isn’t a nice-to-have feature—it’s a non-negotiable architectural requirement. The good news? Amazon Bedrock AgentCore Memory provides built-in primitives for both app-level and user-level isolation. This post shows you how to architect these protections correctly, with working CDK code and IAM policies to illustrate the concepts.


AgentCore Memory Organization: How Isolation Is Built In

Before we dive into isolation patterns, let’s understand how AgentCore Memory organizes data. The service uses a three-level hierarchy that forms the foundation for all isolation strategies:

The Core Concepts

Actor – Refers to entities such as end users or agent/user combinations. In our HR agent example, the actor is typically the employee asking questions. Using the actor ID helps the system know which user the memory belongs to, keeping each user’s data separate and organized. For example: actor-employee-12345 or cognito-user-a1b2c3d4.

Session – A single conversation or interaction period between the user and the AI agent. It groups all related messages and events that happen during that conversation. For example: session-2026-02-27-abc123. When a user starts a new conversation, you create a new session ID.

Strategy (Long-term memory only) – Shows which long-term memory strategy is being used. AgentCore Memory supports multiple strategies like semantic memory (extracting key facts), summary memory (conversation summaries), and user preference memory (storing likes/dislikes). This identifier is auto-generated when you create an AgentCore Memory resource. For example: semantic-93483043 or summary-abc12345.

Source: Memory organization in AgentCore Memory

Namespace: The Key to Isolation

For long-term memory, AgentCore Memory uses namespaces to organize extracted memories. A namespace is a hierarchical path that determines where memories are stored and retrieved. Think of it like a file system path, but for memory records.

Source: Specify long-term memory organization with namespaces

When you create a memory strategy, you specify a namespace template using these pre-defined variables (AWS Docs: Memory strategies):

Template
/strategy/{memoryStrategyId}/actor/{actorId}/session/{sessionId}/

After memory creation, AgentCore replaces these placeholders with actual values:

Example
/strategy/summarization-93483043/actor/employee-12345/session/session-2026-02-27-abc/

CRITICAL: The Trailing Slash Rule

According to AWS documentation, you should use a hierarchical format separated by forward slashes /, ending with a trailing slash. The trailing slash prevents prefix collisions in multi-tenant applications. (AWS Docs: Specify long-term memory organization)

Why does this matter? Consider these two namespace patterns:

Without trailing slash (BAD)
❌ BAD:  /actors/Alice
❌ BAD:  /actors/AliceSmith

Without the trailing slash, a query for /actors/Alice would match BOTH namespaces due to prefix matching. The user “Alice” would inadvertently see “AliceSmith’s” memories. With trailing slashes, the isolation is enforced:

With trailing slash (GOOD)
✅ GOOD: /actors/Alice/
✅ GOOD: /actors/AliceSmith/

Now a query for /actors/Alice/ matches only Alice’s namespace, not AliceSmith’s.

Granularity Levels

AgentCore Memory supports different levels of namespace granularity depending on your use case:

Granularity Level Namespace Pattern Use Case
Most granular /strategy/{strategyId}/actor/{actorId}/session/{sessionId}/ Isolate memories per conversation; useful for temporary workflows
Actor-level /strategy/{strategyId}/actor/{actorId}/ Isolate memories per user across all sessions; most common pattern
Strategy-level /strategy/{strategyId}/ Share memories across all actors for a strategy; use cautiously
Global / No isolation; use only for truly global knowledge

For multi-tenant applications, you’ll almost always use actor-level granularity (/strategy/{strategyId}/actor/{actorId}/) as your baseline, combined with additional prefixes for app-level isolation.

Source: Specify long-term memory organization with namespaces

Short-Term vs Long-Term Memory Organization

Short-term memory (conversation history) is organized differently. When you call the CreateEvent API, you specify both a sessionId and an actorId. These parameters directly identify who the memory belongs to, without using namespaces (AWS Docs: Memory organization):

python
# Short-term memory: Direct actor and session IDs
client.create_event(
    memoryId='memory-abc123',
    actorId='employee-12345',
    sessionId='session-2026-02-27-abc',
    event={
        'type': 'message',
        'content': 'What is my remaining vacation balance?'
    }
)

Long-term memory (extracted facts, summaries, preferences) uses the namespace hierarchy. When AgentCore Memory automatically extracts insights from short-term events, it stores them under the namespace you configured in your memory strategy:

python
# Long-term memory: Namespace-based retrieval
response = client.retrieve_memory_records(
    memoryId='memory-abc123',
    namespace='/strategy/semantic-abc/actor/employee-12345/',
    searchCriteria={
        'searchQuery': 'vacation preferences'
    }
)

This dual organization model gives you flexibility: short-term memory is scoped to sessions (ephemeral context), while long-term memory is scoped to namespaces (persistent knowledge).

Source: Amazon Bedrock AgentCore Memory: Building context-aware agents (AWS ML Blog)


App-Level Isolation: Ensuring Agent A Cannot Access Agent B’s Memory

When building a multi-agent platform, you need to ensure that each agent application operates in its own isolated memory space. The HR agent should never be able to retrieve IT support conversations, and vice versa. Amazon Bedrock AgentCore Memory supports two architectural patterns for app-level isolation: Silo and Pool. Let’s examine both patterns.

Pattern 1: Silo Model (Maximum Isolation)

The Silo pattern creates a separate CfnMemory resource for each agent application. This provides the strongest isolation guarantee, with complete resource separation.

Key benefits:

  • Complete resource isolation: Each agent has its own Memory resource with a unique ARN
  • Separate KMS keys: Different agents can use different encryption keys based on data sensitivity (HR data requires stronger encryption than IT helpdesk logs). AgentCore Memory supports service-managed, AWS-managed, and customer-managed KMS keys (AWS Docs: Encrypt your AgentCore Memory)
  • Blast radius containment: A security issue in one agent’s memory doesn’t affect other agents
  • Simplified compliance: Easier to demonstrate per-application data residency and retention policies

Trade-offs:

  • Higher operational overhead (more resources to manage)
  • Higher cost (multiple Memory resources, multiple KMS keys)
  • More complex IAM (explicit DENY policies needed to prevent cross-resource access)

In this pattern, each agent application gets its own CfnMemory resource with a dedicated KMS key. The IAM role for each agent’s Lambda function is scoped to only that agent’s Memory resource ARN. For defense-in-depth, add explicit DENY statements for other agents’ memory resources.

Source: Enforcing tenant isolation (AWS Prescriptive Guidance)

Key IAM technique: Explicit DENY policies. Even though the HR agent role only has permissions for the HR Memory resource, we add explicit DENY statements for IT and Sales memory resources. This is defense-in-depth—if someone accidentally grants broader permissions elsewhere, the DENY will still block access.

Pattern 2: Pool Model (Shared Resource with Namespace Isolation)

The Pool pattern uses a single CfnMemory resource shared across all agents, with isolation enforced via namespace prefixes and IAM condition keys. This is more cost-efficient while still maintaining strong isolation.

Key benefits:

  • Cost efficiency: Single Memory resource, optionally shared KMS key
  • Centralized management: One resource to monitor, update, and configure
  • Still strongly isolated: IAM condition keys enforce namespace boundaries

Trade-offs:

  • Requires careful IAM policy management
  • All agents share the same eventExpiryDuration (though you can work around this with application logic)
  • Slightly more complex to demonstrate per-app data residency for compliance

In this pattern, a single CfnMemory resource is shared across all agents. Each agent gets a dedicated namespace prefix (e.g., /app/hr-agent/, /app/it-support/), and IAM condition keys on namespace scope (refer to AWS docs for exact key names) enforce that each agent can only access its designated namespace.

The critical line: The IAM condition key bedrock-agentcore:namespace enforces namespace-based access control. Even though all agents share the same Memory resource, IAM ensures they can only access their designated namespace. (AWS Docs: Memory organization – IAM access control)

Comparison: Silo vs Pool

Aspect Silo Pattern Pool Pattern
Isolation Strength Maximum (resource-level) Strong (namespace + IAM)
Cost Higher (N Memory resources, N KMS keys) Lower (1 Memory resource, 1 KMS key)
Operational Overhead Higher (manage N resources) Lower (manage 1 resource)
Best For High-security apps (finance, healthcare) Cost-sensitive platforms with many apps

Recommendation: Start with the Silo pattern for applications with high data sensitivity (HR, finance, healthcare). Use the Pool pattern for cost efficiency when you have many lower-sensitivity agents (IT support, sales, general chatbots). You can mix both patterns in the same platform—use Silo for sensitive apps and Pool for the rest.

Source: Enforcing tenant isolation in multi-tenant agentic AI (AWS Prescriptive Guidance)


User-Level Isolation: Keeping Each User’s Memory Private

App-level isolation ensures the HR agent doesn’t access IT support memory. But within the HR agent itself, how do you ensure Employee X never sees Employee Y’s conversations? This is user-level isolation, and it’s enforced through actorId scoping and namespace boundaries.

The Core Mechanism: actorId

Every interaction with AgentCore Memory requires an actorId parameter. This identifier represents the end user or entity whose memory is being accessed. According to AWS documentation, the actor “refers to entities such as end users or agent/user combinations.” (AWS Docs: Memory organization)

Best practices for actorId:

  • Use Cognito sub claim: cognito-user-a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6
  • Use internal user ID: employee-12345
  • NEVER use PII directly: ❌ [email protected] (enumerable, privacy risk)
  • Ensure uniqueness: Use UUIDs or globally unique identifiers

How User Isolation Works in Practice

When you create a short-term memory event, you specify both actorId and sessionId:

python
import boto3

client = boto3.client('bedrock-agentcore', region_name='us-east-1')

# User A creates an event
client.create_event(
    memoryId='memory-abc123',
    actorId='employee-alice',  # Alice's unique ID
    sessionId='session-2026-02-28-001',
    event={
        'type': 'message',
        'content': 'I need to request vacation leave for next month.',
        'timestamp': '2026-02-28T10:00:00Z'
    }
)

When you retrieve long-term memory records, the namespace parameter enforces isolation. The namespace MUST include the actorId to retrieve that user’s data:

python
# User A retrieves their own memory
response = client.retrieve_memory_records(
    memoryId='memory-abc123',
    namespace='/app/hr-agent/actor/employee-alice/',  # Alice's namespace
    searchCriteria={
        'searchQuery': 'vacation leave preferences',
        'topK': 10
    },
    maxResults=10
)

# Returns only Alice's memory records
print(f"Found {len(response['memoryRecordSummaries'])} records for Alice")

Proof of Isolation: User A Cannot Access User B’s Data

Here’s a complete demonstration showing that user isolation works:

python
"""
Demonstrates user-level memory isolation
User A cannot access User B's memory, even within the same agent app
"""

import boto3

client = boto3.client('bedrock-agentcore', region_name='us-east-1')
MEMORY_ID = 'memory-abc123xyz'

# Setup: Create events for two different users
print("Step 1: Creating events for User A and User B")
client.create_event(
    memoryId=MEMORY_ID,
    actorId='employee-alice',
    sessionId='session-alice-001',
    event={
        'type': 'message',
        'content': 'I need to request vacation leave for next month.',
        'timestamp': '2026-02-28T10:00:00Z'
    }
)
client.create_event(
    memoryId=MEMORY_ID,
    actorId='employee-bob',
    sessionId='session-bob-001',
    event={
        'type': 'message',
        'content': 'I need help with my disability accommodation request.',
        'timestamp': '2026-02-28T10:00:00Z'
    }
)

# Test: User A retrieves their own memory
print("\nStep 2: Alice retrieves her own memory")
alice_records = client.retrieve_memory_records(
    memoryId=MEMORY_ID,
    namespace='/app/hr-agent/actor/employee-alice/',
    searchCriteria={'searchQuery': 'vacation leave', 'topK': 10},
    maxResults=10
)
print(f"Alice's records: {len(alice_records.get('memoryRecordSummaries', []))} found")

# CRITICAL TEST: Alice attempts to query Bob's namespace
print("\nStep 3: Alice attempts to access Bob's namespace")
cross_user_records = client.retrieve_memory_records(
    memoryId=MEMORY_ID,
    namespace='/app/hr-agent/actor/employee-bob/',  # Bob's namespace
    searchCriteria={'searchQuery': 'accommodation', 'topK': 10},
    maxResults=10
)

if len(cross_user_records.get('memoryRecordSummaries', [])) == 0:
    print("✓ ISOLATION VERIFIED: Alice's query for Bob's namespace returned 0 records")
else:
    print("❌ ISOLATION BREACH: Alice can see Bob's records!")

What happens when Alice tries to access Bob’s namespace?

  1. Without IAM condition keys: The API call succeeds, but returns zero records. AgentCore Memory only returns records that match the specified namespace.
  2. With IAM condition keys (recommended): The API call is blocked by IAM with an AccessDeniedException. This is defense-in-depth—even if an attacker knows Bob’s actorId, they can’t enumerate his data. (AWS Docs: Memory organization – IAM access control)

Putting It Together: Sample Architecture for a Multi-Agent Platform

Now let’s combine app-level and user-level isolation into a complete, complete architecture. This stack includes Amazon Cognito for authentication, API Gateway with authorization, Lambda for agent logic, and AgentCore Memory with namespace-based isolation.

Architecture Diagram

🚀 Architecture
┌──────────────────────┐
│   User (Employee)    │
│  Alice (sub: a1b2c3) │
└──────────┬───────────┘
           │ 1. POST /chat with JWT
           │    {"message": "vacation leave", "sessionId": "..."}
           ▼
┌──────────────────────────────────────────────┐
│          Amazon Cognito User Pool            │
│  (Authenticates user, issues JWT)            │
│  JWT contains: sub=a1b2c3, email=alice@...   │
└──────────┬───────────────────────────────────┘
           │ 2. JWT validated
           ▼
┌──────────────────────────────────────────────┐
│         API Gateway (REST API)               │
│  - Cognito Authorizer validates JWT          │
│  - Extracts 'sub' claim from JWT             │
│  - Passes claims to Lambda via event context │
└──────────┬───────────────────────────────────┘
           │ 3. event.requestContext.authorizer.claims
           │    { sub: "a1b2c3", email: "alice@..." }
           ▼
┌──────────────────────────────────────────────┐
│       Lambda Function (HR Agent Logic)       │
│  1. Extract actorId from Cognito sub         │
│     actorId = "cognito-user-a1b2c3"          │
│  2. Build namespace with actorId             │
│     namespace = "/app/hr-agent/actor/        │
│                  cognito-user-a1b2c3/"       │
│  3. Call AgentCore Memory APIs               │
│     - CreateEvent(actorId, sessionId, ...)   │
│     - RetrieveMemoryRecords(namespace, ...)  │
└──────────┬───────────────────────────────────┘
           │ 4. Memory API calls with actorId and namespace
           ▼
┌──────────────────────────────────────────────┐
│  AgentCore Memory (CfnMemory Resource)       │
│                                              │
│  Namespace structure:                        │
│  /app/hr-agent/                              │
│    └─ actor/                                 │
│        ├─ cognito-user-a1b2c3/  ← Alice      │
│        │   └─ session-001/                   │
│        │   └─ session-002/                   │
│        ├─ cognito-user-d4e5f6/  ← Bob        │
│        │   └─ session-001/                   │
│                                              │
│  ✓ Alice can only access her namespace      │
│  ✓ Bob can only access his namespace        │
│  ✓ Enforced by namespace parameter + IAM    │
└──────────────────────────────────────────────┘

Key Security Properties

This architecture guarantees:

  1. Authenticated Identity: Users must authenticate with Cognito before accessing the API
  2. Verified Identity Propagation: The JWT sub claim is cryptographically verified by API Gateway
  3. Enforced Namespace Scoping: Lambda ALWAYS builds the namespace from the authenticated user’s sub, not from user input
  4. IAM Defense-in-Depth: The IAM policy’s namespace condition provides an additional security layer
  5. Audit Trail: All API calls to AgentCore Memory are logged in CloudTrail with the actorId visible

What if an attacker tries to forge a request?

  • If they modify the JWT → API Gateway rejects it (invalid signature)
  • If they pass a different actorId in the body → Lambda ignores it and uses the JWT sub
  • If they somehow bypass Lambda → IAM condition key blocks unauthorized namespace access

This architecture illustrates patterns suitable for regulated industries requiring strong isolation guarantees.

Source: Use isolated sessions for agents (AWS Docs)


Best Practices, Anti-Patterns, and Testing Isolation

With the architecture in place, let’s discuss operational best practices, common mistakes to avoid, and how to continuously verify that isolation is working.

Best Practices

1. Always Use Trailing Slash in Namespaces

According to AWS documentation, you should use a hierarchical format separated by forward slashes /, ending with a trailing slash. This prevents prefix collisions. (AWS Docs: Specify long-term memory organization)

Namespace conventions
✅ GOOD: namespace = '/app/hr-agent/actor/alice/'
❌ BAD:  namespace = '/app/hr-agent/actor/alice'

Why? Without the trailing slash, a namespace query for /app/hr-agent/actor/alice would match:

  • /app/hr-agent/actor/alice (intended)
  • /app/hr-agent/actor/alicesmith (unintended)
  • /app/hr-agent/actor/alice123 (unintended)

The trailing slash ensures exact boundary matching.

2. Use Meaningful, Non-Enumerable actorId Conventions

Actor ID patterns
✅ GOOD: actor_id = f"cognito-user-{uuid_from_cognito_sub}"
✅ GOOD: actor_id = f"employee-{random_employee_id}"
❌ BAD:  actor_id = "user-1", "user-2", "user-3"  # Sequential, enumerable
❌ BAD:  actor_id = "[email protected]"  # PII, privacy risk

Sequential or predictable actorIds allow enumeration attacks where an attacker can iterate through user-1, user-2, etc., attempting to access other users’ data. Use UUIDs or cryptographically secure random identifiers.

3. Defense-in-Depth: Combine Namespace + IAM + Application Logic

Don’t rely on a single isolation mechanism. Use all three layers, as recommended by the AWS Prescriptive Guidance on multi-tenant agentic AI:

Layer Mechanism Purpose
Application Layer Validate actorId matches authenticated user in Lambda Prevent logic bugs
IAM Layer IAM condition keys on namespace scope (refer to AWS docs for exact key names) Enforce at policy level
API Layer AgentCore Memory namespace parameter Enforce at service level

4. Monitor and Alert on Cross-Namespace Access Attempts

Use CloudWatch Logs Insights or CloudTrail to detect suspicious patterns:

CloudWatch Logs Insights query
fields @timestamp, requestParameters.actorId, requestParameters.namespace
| filter @message like /RetrieveMemoryRecords/
| stats count() by requestParameters.actorId as actor, requestParameters.namespace as namespace
| filter namespace not like concat("/app/hr-agent/actor/", actor, "/")

If you see results, it means a Lambda function is attempting to access a namespace that doesn’t match its actorId—this could indicate a bug or security issue.

Anti-Patterns

❌ Anti-Pattern 1: Omitting Trailing Slash

Bad practice
# BAD: Prefix collision risk
namespace = "/app/hr-agent/actor/alice"
# Matches: alice, alicesmith, alice123

Impact: User “alice” could see “alicesmith”‘s memory records.

Fix: Always append trailing slash: /app/hr-agent/actor/alice/

❌ Anti-Pattern 2: Using User Input for actorId

Bad practice
# BAD: Trusting user-provided actorId
body = json.loads(event['body'])
actor_id = body['actorId']  # User controls this!

Impact: A malicious user can set actorId: "victim-user" and access their data.

Fix: Always extract actorId from the authenticated JWT:

Good practice
# GOOD: Extract from JWT
claims = event['requestContext']['authorizer']['claims']
actor_id = f"cognito-user-{claims['sub']}"  # Server-controlled

Testing Isolation: Integration Tests

As part of your CI/CD pipeline, run integration tests that verify isolation is working. Here’s a sample test pattern:

python
"""
Integration test for user-level isolation
Run this in your CI/CD pipeline after deploying Memory resources
"""

import boto3
import pytest

client = boto3.client('bedrock-agentcore', region_name='us-east-1')
TEST_MEMORY_ID = 'memory-test-isolation-abc123'


def test_user_isolation_basic():
    """Verify User A cannot see User B's memory."""

    # Setup: Create distinct events for two users
    client.create_event(
        memoryId=TEST_MEMORY_ID,
        actorId='test-user-alice',
        sessionId='test-session-alice',
        event={
            'type': 'message',
            'content': 'Alice secret: Project Phoenix budget is $2M',
            'timestamp': '2026-02-28T10:00:00Z'
        }
    )

    client.create_event(
        memoryId=TEST_MEMORY_ID,
        actorId='test-user-bob',
        sessionId='test-session-bob',
        event={
            'type': 'message',
            'content': 'Bob secret: Requesting time off for surgery',
            'timestamp': '2026-02-28T10:01:00Z'
        }
    )

    # Test: Alice retrieves only her memory
    alice_response = client.retrieve_memory_records(
        memoryId=TEST_MEMORY_ID,
        namespace='/app/test/actor/test-user-alice/',
        searchCriteria={'searchQuery': 'secret', 'topK': 10},
        maxResults=10
    )

    alice_records = alice_response.get('memoryRecordSummaries', [])
    alice_content = ' '.join([str(r.get('content', '')) for r in alice_records])

    # Assertion: Alice should see her own secret but not Bob's
    assert 'Project Phoenix' in alice_content, \
        "Alice should see her own data"
    assert 'surgery' not in alice_content, \
        "Alice should NOT see Bob's data (ISOLATION BREACH)"

    print("✅ User isolation test passed")


if __name__ == '__main__':
    pytest.main([__file__, '-v'])

Run these tests in your CI/CD pipeline:

bash
# In your buildspec.yml or GitHub Actions workflow
pytest tests/test_memory_isolation.py --region us-east-1

If any test fails, the pipeline should halt and alert your security team.


Conclusion

Building production multi-agent platforms requires more than just connecting an LLM to a memory service. It demands rigorous isolation guarantees to protect sensitive data, maintain user privacy, and meet compliance requirements. As we’ve seen, Amazon Bedrock AgentCore Memory provides the primitives you need to build these guarantees correctly.

Key Takeaways:

  1. AgentCore Memory has isolation built-in: The namespace hierarchy (/app/{appId}/actor/{actorId}/session/{sessionId}/), actorId scoping, and IAM condition keys on namespace scope (bedrock-agentcore:namespace) provide multiple layers of isolation. (AWS Docs)
  2. Two patterns for app-level isolation: Use the Silo pattern (separate CfnMemory per app) for maximum isolation and data sensitivity, or the Pool pattern (shared CfnMemory with namespace isolation) for cost efficiency. Choose based on your security and cost requirements.
  3. User-level isolation requires end-to-end identity propagation: The flow from Cognito JWT → API Gateway → Lambda → AgentCore Memory must preserve the authenticated user’s identity at every step. Extract the sub claim from the JWT and use it as the actorId—never trust user-provided values.
  4. Defense-in-depth is essential: Combine namespace scoping (API layer), IAM condition keys (policy layer), and application validation (Lambda layer). Any single mechanism might have bugs; three layers ensure robustness.
  5. Testing isolation is not optional: Integration tests that verify User A cannot see User B’s data should run in your CI/CD pipeline before every production deployment.
  6. The trailing slash matters: This small detail (/actor/alice/ not /actor/alice) prevents prefix collision attacks. It’s easy to forget and critical to get right.

Next Steps

Ready to implement this in your AWS account? Here’s what to do:

  1. Choose the Silo or Pool pattern based on your isolation and cost requirements. Start by building the IAM policies and namespace conventions in a non-production environment, adapting the concepts from this post to your specific needs.
  2. Review the AWS Prescriptive Guidance on multi-tenant agentic AI for broader architectural patterns beyond memory isolation.
  3. Add integration tests to your CI/CD pipeline using the test patterns from the Best Practices section. Fail the build if isolation is violated.
  4. Monitor and alert on cross-namespace access attempts using CloudWatch Logs Insights. Set up alerts for suspicious patterns.
  5. Document your isolation model for compliance audits. Show how app-level and user-level isolation are enforced at multiple layers (architecture diagram + IAM policies + code).
📝 Note: This blog post represents my personal views and experiences and does not represent the views of my employer. Any recommendations or architectural patterns discussed are based on publicly available documentation and my own analysis.

References

Related Posts

💬 Comments

Comments are reviewed before appearing
No comments yet. Be the first to share your thoughts!