The situation
A regional insurer with around 400 staff has been running a customer-service assistant on Amazon Bedrock since March. Contact-centre agents ask it questions in plain English, and it answers from a knowledge base built over the underwriting manuals and the current policy wordings. Retrieval over the company’s own documents is doing the work; there is no custom model anywhere in it.
It has been useful enough that the operations director wants to widen it to the claims team. Widening it triggers a security review, and the review has come back with a list. Six items, written by four different people, in no particular order.
- Anyone with a console login appears able to call the model. Nobody can say which roles are allowed to do what.
- The application runs in a private subnet and reaches Bedrock through a NAT gateway, so every request goes out over the public internet.
- There is an S3 bucket of exported claims text that somebody used while drafting prompts last year. Nobody has looked at what is in it. It very likely holds policyholder names, addresses, and medical notes.
- The compliance officer wants a written answer to “is the data encrypted?” and will not accept “yes, by default” without knowing who holds the key.
- Twice last month the assistant answered a question about a competitor’s product, at length, and confidently.
- The next version is supposed to file small refunds itself by calling the payments team’s refunds API, instead of telling the agent to go and do it.
Nobody in the room disputes that all six are real. The argument is about which AWS control answers which, and it keeps going in circles because several of the controls sound like they might answer several of the worries.
What actually matters
The frame that sorts this out is the AWS shared responsibility model, and it applies to Amazon Bedrock exactly as it applies to Amazon EC2. AWS operates the data centres, the network, the hardware, and the hosting of the foundation models themselves, and publishes the assurance evidence for all of that. You own your data, your prompts and completions, your IAM configuration, your network design, and whether your use of the service meets the rules your industry puts on you. A fully managed service moves the boundary up, so there is less on your side than there would be with a model you ran yourself, but it does not empty your side. Every one of the six worries above sits below the line marked “yours”.
The next thing to settle is what each worry is actually about, because a control protects one kind of object and is useless against the others. There are five objects in this list. An identity (who is calling). A network path (how the request travels). Data at rest (what is sitting in a bucket). Data in transit (what is on the wire). And model behaviour (what goes into the model and what comes back out). Worry six adds a sixth object that only shows up once software starts acting on its own: an action taken against another system, with no human in the moment to approve it.
Where a control sits in the request path decides when it can help. Some controls act before the call is made, deciding whether it happens at all. Some act on the wire. Some act at the moment of invocation, inspecting the text going in and the text coming out. Some act on data that was written weeks ago and has been sitting there since. A control that runs at invocation time cannot tell you what is in last year’s bucket, and a scan of that bucket cannot stop a model saying something today.
Then the part that is easy to skip: what each control explicitly does not do. Most of the wrong answers here are a real control aimed at the wrong object. Naming the gap out loud, for each control, is what stops that.
What we’ll filter on
- Object. What is being protected: an identity, a network path, data at rest, data in transit, model behaviour, or an action against another system?
- Position in the path. Does it act before the call, on the wire, at invocation, or over stored data long after the fact?
- Side of the line. Under the AWS shared responsibility model, is this AWS’s to run, yours to configure, or both?
- Time of effect. Is it a configuration decision made once, or something that runs on every request?
- The gap. What does this control explicitly not cover, so it does not get credited with a job it cannot do?
The landscape
Seven controls cover the whole list, and each one has a single sentence that says what it is for.
IAM roles, policies, and permissions
AWS Identity and Access Management decides which principal may perform which action on which resource. For a Bedrock application this means an IAM role, assumed by the application, holding a policy that allows invoking one named model and retrieving from one named knowledge base, and nothing else. The resource is the model’s own ARN, so “may call our assistant’s model” and “may call every model in the catalogue” are different policies, and only one of them belongs in production.
Two shapes of policy exist. An identity-based policy is attached to the role and says what that role may do. A resource-based policy is attached to the thing being reached, such as an S3 bucket, and says who may reach it. Both grants have to line up for access to work, and both are yours to write.
Roles matter more than the policy text at this stage. A role is assumed and hands out credentials that expire in hours; an IAM user with a long-lived access key hands out credentials that expire when somebody remembers. For the insurer’s worry about who can call the model, this is the whole answer: give the application a role, scope the policy to the one model, and stop issuing access keys.
Encryption: AWS KMS and TLS
Encryption comes in two halves, and the compliance officer’s question needs both answered.
Data at rest is what is written to storage: the S3 bucket, the knowledge base and its vector index, the invocation logs. AWS encrypts this by default using AWS Key Management Service, so the honest answer to “is it encrypted?” is yes before anyone does anything. What is left to decide is the key. An AWS-managed key is created and rotated by AWS, costs nothing, and you cannot write a policy against it or delete it. A customer-managed key is created by you in AWS KMS, carries a key policy you control, appears in CloudTrail every time it is used, and can be disabled, which stops decryption of everything it protects. That last property is why a regulator-facing workload usually asks for one.
Data in transit is what is on the wire between the application and the Bedrock endpoint, and that is protected by TLS on every call, whether the traffic goes over the internet or stays inside AWS. The insurer already has this and nobody had told the compliance officer. Working out which artefacts deserve a customer-managed key is the follow-on decision once the default position is understood.
Amazon Macie
Amazon Macie inspects data already sitting in Amazon S3 and reports what sensitive material it finds: names, addresses, card numbers, health identifiers, credentials. It samples and classifies objects, produces findings, and tells you which bucket and which prefix the sensitive data lives in.
It is a discovery tool for stored data, and its whole value at this insurer is worry three. Nobody knows what is in that claims-export bucket, and Macie is how they find out without a person reading a hundred thousand files. It does not stop anything. It does not read prompts, it does not inspect model output, and it does not act on data outside S3. It finds, and then a human decides whether to delete, redact, or move what was found.
AWS PrivateLink
By default an SDK call to Amazon Bedrock resolves to a public service endpoint. From a private subnet that means a NAT gateway and a trip across the public internet. AWS PrivateLink changes that: an interface VPC endpoint puts a private IP address for the Bedrock APIs inside your own subnets, and the traffic stays on the AWS network without ever touching the internet.
The endpoint also carries a policy of its own, so it can narrow which principals and which actions are allowed to pass through this particular door, on top of whatever the calling role’s IAM policy already says. The professional-level treatment of how identity, network, and key controls stack on a Bedrock application goes into how those two policies interact; at this level, the sentence to hold is that PrivateLink changes the route.
Here is the trap. A VPC endpoint does not encrypt anything. The call was already encrypted by TLS before the endpoint existed, and it is still encrypted by TLS afterwards. What changes is which networks the packets cross. Answering “is it encrypted?” with “we added a VPC endpoint” is answering a different question.
Amazon Bedrock Guardrails
Amazon Bedrock Guardrails sits at invocation time, between the application and the model, and inspects both directions. It can deny whole topics, so a request about a competitor is refused with a message you write instead of answered. It can filter categories of harmful content at a strength you choose. It can detect and either block or mask personally identifiable information in what goes in and what comes back. It can check a response against the retrieved source documents and flag output the sources do not support, which is how a grounding check gets enforced rather than hoped for.
A guardrail is attached to the invocation, so it applies however the model is called, and it applies to models, knowledge bases, and agents alike. It is the only control on this list that inspects meaning rather than identity, route, or storage. Configuring the denied topics, filters, and grounding thresholds is a separate exercise; recognising that worry five is a guardrail worry is the step that matters first.
AWS Secrets Manager
The application holds credentials for things that are not AWS: in this case an API token for the payments team’s refunds service. AWS Secrets Manager stores that token encrypted, hands it to the application at runtime through an IAM-gated call, rotates it on a schedule, and records every retrieval in CloudTrail. The alternative, which is what most teams find when they look, is the token in an environment variable, a config file, or the repository.
It protects a credential. It has nothing to say about who may call the model, what the model says, or what is in an S3 bucket.
Amazon Bedrock AgentCore Identity and Policy in AgentCore
Worry six is different in kind from the other five, because the software is about to take an action against a real system with money attached, and an agent decides its own steps at run time rather than following a path somebody wrote down. The question “who is calling the refunds API?” no longer has an obvious answer, because the caller is a workload acting on a user’s behalf, and the two identities are not the same thing.
Amazon Bedrock AgentCore Identity is what establishes that identity. It gives the agent a workload identity of its own, and it handles obtaining and holding the tokens the agent needs to reach other systems, both AWS services and third-party APIs, on behalf of a particular user. It answers “which agent is this, and whose authority is it acting under?”
Policy in AgentCore answers the next question, which is what the agent is permitted to do once it has been identified. Permissions are declared for the agent’s actions, and they are evaluated when the agent tries to act, so a plan that involves refunding more than the agent is allowed to refund is stopped at the moment of the call rather than at code review. Identity and policy are two halves of one control: identity without policy tells you who overspent, and policy without identity has nobody to apply to. Wiring a model up to actions with side effects covers the mechanics.
Evaluation
Side by side
| Control | What it protects | Where it sits | Under shared responsibility | What it does not do |
|---|---|---|---|---|
| IAM roles, policies, and permissions | An identity and what it may reach | Before the call is made | Yours entirely; AWS enforces it | Nothing about content, route, or stored data |
| Encryption: AWS KMS and TLS | Data at rest and data in transit | Storage layer and the wire | AWS encrypts by default; the key choice is yours | Nothing about who is allowed to decrypt beyond the key policy |
| Amazon Macie | Sensitive data already in Amazon S3 | Over stored data, after the fact | Yours to enable; AWS runs the scanner | Does not block, redact, or read model traffic |
| AWS PrivateLink | The network path to the service | On the wire, between VPC and endpoint | Yours to configure; AWS provides the endpoint | Does not encrypt; TLS was already doing that |
| Amazon Bedrock Guardrails | What goes into and comes out of the model | At invocation, both directions | Yours to define; AWS enforces per request | Does not authenticate, and does not see stored data |
| AWS Secrets Manager | Credentials the application holds | Before the call to a third-party API | Yours to adopt; AWS stores and rotates | Does not govern Bedrock access itself |
| Amazon Bedrock AgentCore Identity and Policy in AgentCore | Which workload is acting, and what it may do | At the moment an agent takes an action | Yours to declare; AWS evaluates per action | Does not inspect the words in the prompt or reply |
Read the fourth column downwards. Every row lands on the customer’s side, in one form or another. AWS runs the mechanism in all seven cases and secures the infrastructure underneath, and in exactly none of them does it decide the configuration for you. That is the AWS shared responsibility model applied to a managed AI service: a shorter list than you would have running your own models, and still a list.
Which worry lands where
The solution
Six worries, six assignments, and none of them needs a control borrowed from another row.
The identity worry gets IAM roles, policies, and permissions. The application assumes a role whose identity-based policy allows invoking the one model the assistant uses and retrieving from the one knowledge base it reads, on those specific resource ARNs. Nobody’s console login carries model-invocation permissions after this, because the permission lives on the application’s role rather than on people. The claims team gets access by being federated into a role, not by being handed a key.
The network worry gets AWS PrivateLink. An interface VPC endpoint for the Bedrock runtime goes into the same private subnets as the application, the NAT gateway route for that traffic goes away, and requests to the model stay on the AWS network. Write down what this has and has not changed, because the review will ask: the route is now private, and the encryption is exactly what it was before.
The uncatalogued bucket gets Amazon Macie. Enable it, point a discovery job at the bucket, and read the findings. What comes back is a list of prefixes with policyholder names and medical information in them, and then the decision is a human one: delete what should never have been exported, and if any of it is needed, move it to a bucket with an access policy and a customer-managed key. Macie tells the insurer what it has; it does not decide what to do about it.
The compliance officer’s question gets a two-part answer about encryption. In transit, TLS, already on, for every call to Bedrock and every call to S3. At rest, AWS KMS, already on by default. The change worth making is moving the knowledge-base data, the claims bucket, and the model invocation logs onto a customer-managed key, so the insurer holds a key policy it can audit and disable, and so key usage shows up in CloudTrail with a name attached. That converts “AWS encrypts it” into “we encrypt it and we can prove who used the key”.
The competitor answers get Amazon Bedrock Guardrails, with a denied topic covering competitor products and a refusal message the marketing team is happy with. While the guardrail is being written, add the PII filter as well, because a contact-centre agent will eventually paste a claim record into the box, and what a user types is not a channel you control. Guardrails are attached to the invocation, so they hold whether the call comes from the current application or from anything built next.
The refunds API gets three things, in order. AWS Secrets Manager for the payments API token, so the credential stops living in an environment variable. Amazon Bedrock AgentCore Identity so the agent has a workload identity of its own and obtains its tokens through a managed flow rather than holding a shared secret. Policy in AgentCore to declare what the agent may actually do, evaluated at the moment it tries to act, so an instruction that talks the model into a larger refund than the policy allows fails at the call. None of that is a substitute for a guardrail on the conversation, and a guardrail is no substitute for any of it.
Two mistakes are worth naming because they come up every time. The first is treating a VPC endpoint as an encryption control. AWS PrivateLink changes which networks the traffic crosses, and TLS does the encrypting, before and after. The second is reaching for Amazon Macie when the worry is about model output. Macie reads objects in S3, which covers a bucket nobody has catalogued and does nothing for an assistant that says something it should not. Model output is guardrail territory; stored data is Macie territory. Once the object of the worry is named, the control usually names itself, and a general map of which AWS service does which job in a generative AI application covers the rest of the stack the same way.
What’s worth remembering
- Name the object of the worry first, because a control protects an identity, a network path, data at rest, data in transit, model behaviour, or an autonomous action, and it is useless against the other five.
- AWS PrivateLink changes the route a request takes and encrypts nothing; TLS was already encrypting the call, and AWS KMS handles the data at rest.
- Amazon Macie discovers sensitive data already sitting in Amazon S3 and takes no action on it; anything about what the model says is Amazon Bedrock Guardrails instead.
- An AWS-managed key encrypts your data with no work and no control; a customer-managed key gives you a key policy, a CloudTrail record of key use, and the ability to disable decryption.
- Amazon Bedrock AgentCore Identity establishes which workload is acting and on whose authority, and Policy in AgentCore constrains what that workload is permitted to do when it tries to act.
- The AWS shared responsibility model puts all of these on your side of the line: AWS runs the infrastructure and hosts the models, and a fully managed service still leaves your data, prompts, IAM configuration, and usage compliance to you.