Enforcing CMK encryption, isolating memory by namespace and actor, choosing a store topology for multi-tenancy, and mitigating memory poisoning.
Agent memory persists potentially sensitive context. It's always encrypted — but by default with a service-managed key. Moving to a customer-managed key (CMK) is what gives you control over the key lifecycle, and it's what Security Hub checks for.
Memory is encrypted both at rest and in transit, with the CMK under your control and auditability.
A CMK means you control rotation, grants, and revocation — and you can cut access by disabling the key.
Pair with SCP 2 (M3): deny memory creation without a KmsKeyArn condition, org-wide.
Enforce via IAM condition — require a CMK on create
Encryption protects memory from outsiders. Namespace and actor scoping protect it from cross-tenant leakage — one user's memory bleeding into another's.
Memory is logically isolated by tenant, user, or agent. Namespaces are the partition boundary.
Each user's memory is isolated even within the same agent, keyed by actorId.
Policies restrict which principals can read/write which namespaces — least privilege, applied to memory.
actorId, always.
This is the memory-side of M2's identity work: the same actorId and namespace condition keys that scope access also enforce tenant isolation in memory. The Security Lab (capstone) demonstrates this live — sign in as one customer and watch a cross-customer memory read get denied by IAM.
Once you know memory is partitioned by actorId and namespace, the natural next question is whether each customer should get their own memory store instead. It's the right instinct — a smaller blast radius is usually a better design — but here it's mostly the wrong lever, and the reason why is the most useful thing in this module.
Separation is not isolation. A role granted Resource: memory/* reads across a hundred separate stores just as easily as it reads across one. A role constrained by the actorId condition can't cross tenants even inside a single shared store. The control is the policy, not the topology.
Amazon Bedrock AgentCore Memory puts the tenant boundary inside the store deliberately. Short-term events are keyed by actorId and sessionId; long-term records live in namespaces whose templates take {actorId} directly. AWS describes a namespace as a path that aids "retrieval, filtering, and access control" — access control is a stated purpose, not a side effect.
Namespace templates put the actor in the path at extraction time
The service quotas then make a store-per-user impractical at consumer scale:
| Quota | Value | Adjustable |
|---|---|---|
| Memory resources per Region, per account | 150 | Yes |
| Memory strategies per memory resource | 6 | No |
| Memory strategies per account | 900 | Yes |
CreateMemory requests per second | 3 | Yes |
A retail bank has millions of customers against a default ceiling of 150 stores. Even with the limit raised, creating stores at three per second puts provisioning on your sign-up path — new latency, and a new way for sign-up to fail. Then multiply every CMK grant, retention setting and IAM policy by your customer count.
Split when the thing that differs is a property of the store itself — because those are exactly the things actorId cannot express.
| Boundary | Separate store? | Reason |
|---|---|---|
Per end user (actorId) | No | This is what actorId, namespaces and IAM conditions are for. |
| Per environment (dev / staging / prod) | Always | Few in number, and test writes must never reach production memory. |
| Tenant needs its own KMS key | Yes | Encryption is configured per memory resource. Per-tenant BYOK, or revoking one tenant by disabling a key, requires its own store. |
| Tenant needs different retention | Yes | eventExpiryDuration is a property of the memory, applied per event at write time. |
| Data residency | Forced | A memory resource lives in exactly one Region. |
| Tenant needs >6 strategies or different extraction logic | Sometimes | Six strategies per memory is a hard limit. |
| Business unit / acquired entity | Often | Independent lifecycle and blast radius; counts are usually tens. |
The pattern: separate per tenant organisation when a store-level property differs — never per end user. A B2B platform with 40 enterprise customers can give each its own store and its own CMK. A consumer bank cannot, and shouldn't try.
Only where key, retention or Region differ.
actorId per userDerived from the validated token, never from the prompt.
/users/{actorId}/… — actor built into the path.
actorId pinned to the caller's identity. The control.
Amazon Bedrock AgentCore Memory supports cross-account access: the store lives in one account, principals in another reach it through a resource-based policy on the memory. That's real separation — per tenant account, not per user.
Because the key is per store, a per-tenant CMK gives you a clean revocation story: disable the key and that tenant's memory becomes unreadable.
Many stores plus one over-broad role. It looks segregated on an architecture diagram and leaks exactly like a single shared store.
The Security Lab demonstrates precisely this. It runs a single shared memory store on purpose, so the only variable is the IAM policy — and the same request leaks or is denied depending solely on whether the caller's credentials carry the actorId condition.
Memory poisoning is the durable cousin of prompt injection: a malicious input persists in memory and quietly steers the agent's future behavior. AWS documentation calls this out directly.
Check memory content for integrity and policy compliance before it's persisted.
Periodically audit memory and watch for anomalous writes — surfaced through observability (M6).
Keep reference data read-only; allow writes only for genuine session context.
Expire memory to limit the exposure window — poisoned data can't influence forever.
Mental model: treat memory writes like untrusted user input, because that's often exactly what they are. Validate on the way in, expire on a schedule, and trace every write.
actorId/sessionId, event expiry (up to 365 days), strategies ignore PII by defaultnamespace, strategyId, actorId, KmsKeyArn condition keysCreateMemory 3/seceventExpiryDuration; namespace templates such as /users/{actorId}/preferences/