TL;DR β Secure generative AI on AWS is mostly secure cloud, applied to a new kind of workload. Three building blocks do most of the heavy lifting: Amazon Bedrock (the managed model service), Guardrails for Amazon Bedrock (the configurable safety net), and IAM (the identity boundary). This post walksthrough each, assembles them into a reference architecture, and gives you a reproducible demo. Slides, demo guide, and code are linked at the end.
Adapted from my AWS Cloud Security User Group - West Africa Study Series on "Secure Generative AI Applications withAmazon Bedrock, Guardrails, and IAM."
Keywords: Amazon Bedrock, Generative AI Security, AWS Guardrails, IAM BestPractices, Secure AI Applications, Responsible AI, Least-Privilege Access,Prompt Injection, Foundation Models, AWS Well-Architected.
1. Introduction
Every team I talk to is shipping something with a large language model in it, a chatbot, a summarizer, a "talk to your docs" feature. The model is the easy part. Bedrock hands you a state-of-the-art foundation model behind one API call. The hard part is everything around the model: who is allowed to call it, what it is allowed to say, what data it can touch, and how you prove, after the fact, what actually happened.
This post is about that surrounding 90%. It is deliberately practical. By the end you should be able to understand the topic, follow the talk, reproduce the demo, and deploy a small version of this yourself.
Figure 1: The secure GenAI blueprint. Three core controls (Bedrock, Guardrails, IAM)
2. Problem Statement: the chatbot that wasn't ready for production
A team built an internal LLM chatbot, call it PolicyBot. It was wired to a knowledge base of policies, claim notes, and customer correspondence. It worked beautifully in the demo⦠and then, within a week of going live, a misconfigured prompt returned another customer's record to a user.
The root cause was not the model. It was everything around the model:
- The Lambda calling the model ran with a wide IAM role (
bedrock:*, and more). - There was no guardrail β no PII filter, no denied-topics policy, no prompt-injection screen.
- There was no audit trail β no easy way to ask "which prompt produced which response, for which user?"
- Sensitive and public data were mixed in one knowledge base.
- The team had only tested the happy path.
Sound familiar? None of these are exotic AI problems. They are ordinary cloud security problems wearing an AI costume.
3. Why Secure GenAI Matters
Generative AI changes the security conversation in three concrete ways:
- The inputs and outputs are the data plane: With S3 you secure objects. With an LLM, the prompt and the completion are the sensitive payload and they are generated dynamically, so you cannot enumerate them in advance.
- Natural language is an attack surface: Prompt injection and jailbreaks let an attacker reprogram behaviour using nothing but text, no CVE required.
- Agency amplifies blast radius: The moment a model can call tools, query a knowledge base, or trigger an action, its permissions become its permissions.
The community has converged on shared threat models for exactly this. The
OWASP Top 10 for LLM Applications and the NIST AI Risk Management Framework are both worth reading. The good news: nearly every item maps to an AWS control you can configure today.
Figure 2: OWASP-style GenAI risks (left) mapped to the AWS control that addresses each one (right). No single layer is sufficient; the controls compose.
4. Amazon Bedrock Overview
Amazon Bedrock is a fully managed service that gives you access to a curated catalogue of foundation models, Claude (Anthropic), Nova/Titan (Amazon), Llama (Meta), Mistral, Cohere, AI21, through one consistent API. You don't host any model yourself. You call InvokeModel, or their streaming variants. Around that, Bedrock offers Knowledge Bases (managed RAG), Agents (tool-using assistants), Prompt Management, and Guardrails.
Three security-relevant facts that shape every design decision below:
- Access is governed by IAM, not a console toggle: AWS retired the old Model access page in 2025 β serverless models now auto-enable on first invocation, and who can call which model is controlled entirely through IAM policies and SCPs (First-time Anthropic use may require a short use case form.)
- All requests stay on AWS: Use VPC interface endpoints (PrivateLink) for Bedrock to keep traffic off the public internet entirely.
- Every call is auditable: Model invocation logging captures prompt, response, and metadata to CloudWatch Logs and/or S3.
That last point matters in a way it didn't for, say, S3: because the inputs and outputs are the data plane, you can't reason about safety without seeing them.
5. Guardrails β moving safety out of the prompt
You can write a beautiful system prompt that says "never reveal PII, never give legal advice, never produce harmful content." It will work most of the time. The problem is that a prompt isn't:
- Testable β there's no clean way to assert it's enforced for every variation.
- Versionable β prompt drift across PR reviews is invisible.
- Auditable β a prompt instruction leaves no record of which request triggered which clause.
Guardrails for Amazon Bedrock solve this by moving safety policy out of the prompt and into a versioned, named resource that lives next to your IAM resources. You attach a guardrail to a model invocation, or call it standalone via the ApplyGuardrail API. A guardrail evaluates policy on input (before themodel sees it) and output (before the caller sees it).
The six policy types:
| Policy | What it does |
|---|---|
| Content filters | Categories β Hate, Insults, Sexual, Violence, Misconduct β with low/medium/high thresholds. |
| Denied topics | Domain-specific bans ("legal advice", "medical diagnosis") defined by name, definition, and example phrases. |
| Word filters | Profanity list plus your custom words. |
| Sensitive information | PII patterns (email, phone, name, address, SSN, credit card) with block or mask/anonymize actions. |
| Prompt attacks | Detector for prompt injection / jailbreak attempts in user input. |
| Contextual grounding | For RAG β blocks answers not grounded in retrieved sources. |

Figure 3 β A guardrail applies policy on the way in and on the way out.
6. IAM Controls β half the talk
Here's the line that belongs on a sticker:
The blast radius of an LLM is the IAM role attached to it.
Everything else β guardrails, content filters, prompt techniques β is a
defence-in-depth layer inside that blast radius. Get the role wrong and the layers don't matter.
The good news: this is regular AWS. The least-privilege patterns you already know apply directly. The Bedrock-specific actions you'll touch most are:
-
bedrock:InvokeModel/bedrock:InvokeModelWithResponseStream -
bedrock:Converse/bedrock:ConverseStream -
bedrock:ApplyGuardrail,bedrock:GetGuardrail,bedrock:ListGuardrails -
bedrock:Retrieve/bedrock:RetrieveAndGenerate(Knowledge Bases)

Figure 4 β Two roles, two blast radii. The left role can reach everything; the right role can call exactly one model and one guardrail, and nothing else.
Two practices that pay off:
-
Scope to model and guardrail ARNs: Never write
Resource: "*"in a Bedrock policy. Pin the foundation-model ARN you use and the guardrail ARN you've configured. - Use short-lived credentials: Code calling Bedrock should run as an IAM role assumed via STS, not as a long-lived user with static access keys.
A minimal least-privilege policy:
json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowConverseOnSpecificModel",
"Effect": "Allow",
"Action": [
"bedrock:Converse",
"bedrock:ConverseStream"
],
"Resource": [
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0"
]
},
{
"Sid": "AllowSpecificGuardrail",
"Effect": "Allow",
"Action": [
"bedrock:ApplyGuardrail",
"bedrock:GetGuardrail"
],
"Resource": [
"arn:aws:bedrock:us-east-1:111122223333:guardrail/abcd1234efgh"
]
}
]
}
No bedrock:*, no iam:*, and definitely no *:*. If the application later
needs Knowledge Base APIs or a specific S3 prefix, add those statements
explicitly.
7. Putting It Together β a reference architecture
None of these controls is interesting alone. The value is in how they compose.

Figure 5 β Reference architecture: The Lambda assumes a role scoped to one model and one guardrail
Key design decisions on this diagram:
- The Lambda assumes a role scoped to one model + one guardrail. Nothing else.
- Every call carries a
guardrailConfigβ guardrails are always on. - Knowledge-Base reads are similarly scoped (one KB, one tenant prefix).
- Logs go to CloudWatch with request-id and user/tenant tags.
- Secrets β API keys for any non-AWS service the agent might call, live in Secrets Manager, never baked into Lambda environment variables.
- Data at rest is encrypted with KMS, ideally per-tenant keys.
8. Demo Walkthrough
In the talk we ran a small Python client against this setup. The full,
reproducible steps are in the demo guide; here's the shape of it.

Figure 6 β The demo: a local CLI β STS AssumeRole β Bedrock Converse + Guardrailβ CloudWatch.
Three prompts, three outcomes:
| Prompt | What the guardrail does | What you see |
|---|---|---|
| "Summarise the AWS Well-Architected pillars in 5 bullets." | Nothing β clean | Normal model output |
| "I'm Jane Doe (jane.doe@acme.com), please confirm." | Anonymises email/name before the model sees them | Model answers using the masked version |
| "Should I sue my landlord over a leaky roof?" | Blocks β denied topic Legal advice | Model never invoked; configured refusal returned |
The client is intentionally tiny β it sets guardrailConfig with trace: "enabled"
and prints both the model output and the guardrail trace:
python
resp = client.converse(
modelId=MODEL_ID,
messages=[{"role": "user", "content": [{"text": prompt}]}],
guardrailConfig={
"guardrailIdentifier": GUARDRAIL_ID,
"guardrailVersion": GUARDRAIL_VERSION,
"trace": "enabled",
},
inferenceConfig={"maxTokens": 500, "temperature": 0.2},
)
9. Lessons Learned & Best Practices
Going back to PolicyBot, here is the fix list, generalised.
If you only do five things:
- Pin the model id, guardrail id, and guardrail version in code: Treat them like database schema versions.
- Always attach a guardrail: Even a permissive one is a hook for future tightening.
- Scope the IAM role: Resource ARNs, not wildcards. Short-lived STS creds.
- Log every invocation: request id, principal, model id, guardrail id, and the guardrail trace.
- Red-team before you ship: Prompt injection, jailbreaks, PII probes, denied-topic probes. make it a checklist that runs in CI.
Three pitfalls often seen:
- A
bedrock:*policy attached to a Lambda to make it work. - Logging full prompts that contain PII before the guardrail has masked them.
- Forgetting that the guardrail is also a resource, so it needs IAM, change-control, and an audit trail of its own.
Responsible AI controls worth layering in as you mature: human-in-the-loop for high-impact actions, evaluation/regression suites for quality and safety, and clear user-facing disclosure that they're talking to an AI.
10. Conclusion
Secure generative AI on AWS is not a new discipline. It is the cloud security you already practice, pointed at a workload where the prompt and the completion are the sensitive data. Bedrock gives you the managed model and the audit hooks. Guardrails give you testable, versionable, auditable safety policy. IAM draws the blast-radius boundary around the whole thing.
If you remember one line: secure GenAI is mostly secure cloud, applied to a new kind of workload.
Try it yourself
The demo guide and code from the talk are open-sourced:
Demo guide (markdown) and client (Python): β full step-by-step with validation checks: demo guide
Presentation Video Rewatch: Presentation Video
You'll need an AWS account with Amazon Bedrock available in your Region of choice (serverless models auto-enable on first invocation; first-time Anthropic use may need a short use-case form).
References
All links point to official AWS documentation, AWS blogs, AWS workshops, or recognised standards bodies.
AWS documentation
- Amazon Bedrock User Guide β https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html
- Supported foundation models & access β https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html
- Converse API reference β https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_Converse.html
- Guardrails for Amazon Bedrock β https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html
- Guardrails components & policy types β https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-components.html
-
ApplyGuardrailAPI β https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ApplyGuardrail.html - IAM for Amazon Bedrock β https://docs.aws.amazon.com/bedrock/latest/userguide/security-iam.html
- Identity-based policy examples β https://docs.aws.amazon.com/bedrock/latest/userguide/security_iam_id-based-policy-examples.html
- Model invocation logging β https://docs.aws.amazon.com/bedrock/latest/userguide/model-invocation-logging.html
- VPC endpoints (PrivateLink) β https://docs.aws.amazon.com/bedrock/latest/userguide/vpc-interface-endpoints.html
AWS guidance, blogs & workshops
- AWS Well-Architected β Generative AI Lens β https://docs.aws.amazon.com/wellarchitected/latest/generative-ai-lens/generative-ai-lens.html
- Generative AI Security Scoping Matrix (AWS Security Blog) β https://aws.amazon.com/blogs/security/securing-generative-ai-an-introduction-to-the-generative-ai-security-scoping-matrix/
- Guardrails for Amazon Bedrock GA announcement β https://aws.amazon.com/blogs/aws/guardrails-for-amazon-bedrock-now-available-with-new-safety-filters-and-privacy-controls/
- Amazon Bedrock Workshop (aws-samples) β https://github.com/aws-samples/amazon-bedrock-workshop
Standards
- OWASP Top 10 for LLM Applications β https://owasp.org/www-project-top-10-for-large-language-model-applications/
- NIST AI Risk Management Framework β https://www.nist.gov/itl/ai-risk-management-framework
If this was useful, leave a β€ and tell me in the comments what you'd like covered next
β Abdullateef Ogundipe (Limitless_AO)














