Trust Boundaries
Working definition
Section titled “Working definition”A trust boundary in rag-sample is an edge across which the assumptions on either side about authentication, authorship, content integrity, or operational control differ enough that the receiver must validate, sanitize, authorize, or otherwise treat the inbound flow as untrusted. Boundaries are not only network hops; an in-process edge can be a boundary when the data crossing it changes provenance.
Two implications follow from this definition and are load-bearing for the threat model:
- A boundary can sit inside a single process. The prompt-construction step inside the API Lambda mixes data of different provenance (operator-authored system prompt, third-party retrieved chunks, user-authored question). The mix is the boundary.
- A network hop is not automatically a boundary. API Gateway -> Lambda is one logical edge inside AWS-managed integration; the trust posture does not change. It is enumerated below for completeness but is not where the threats live.
Inventory
Section titled “Inventory”| # | Boundary | Crosses | Provenance change | What the receiver must do |
|---|---|---|---|---|
| B1 | Browser -> API Gateway | Internet -> AWS edge | Anonymous public -> operator-issued bearer-token-authenticated request | TLS termination, request validation (size, schema), bearer-token validation via Lambda authorizer with per-key lifetime quota and 60-day expiry (RAG009). Route-level rate cap on POST /query remains as defense-in-depth. |
| B2 | API Gateway -> API Lambda | Managed AWS edge | None meaningful (both AWS-managed in same account) | Pydantic validation of the parsed body; structural only. |
| B3 | Prompt construction (in-Lambda) | In-process edge inside the request handler | Operator-authored system prompt + third-party-origin retrieved chunks + user-authored question are concatenated | Delimit chunks clearly; instruct the model to treat delimited content as data; cap question length and strip control characters; never echo retrieved content into tool-use arguments. This is the boundary T1 and T2 live on. |
| B4 | API Lambda -> RDS Data API (Aurora) | AWS public endpoint, IAM-authed HTTPS | None (both AWS-internal control plane) | SigV4 over TLS; parameterized SQL via the Data API; IAM role scoped to one cluster ARN. |
| B5 | API Lambda -> Bedrock | AWS public endpoint, IAM-authed HTTPS | None at the channel; provenance change at B3 above | SigV4 over TLS; IAM role scoped to specific models (bedrock:InvokeModel on the Haiku-class generation model and the Titan embedding model). The generation model is invoked via a cross-region inference profile, so the grant targets the inference-profile/ ARN plus the underlying regional foundation-model/ ARNs the profile can route to; scoping to only one form denies the call — see RAG007. |
| B6 | Ingestion -> Hugging Face Hub | AWS or local machine -> third-party public endpoint | AWS (or operator) -> third-party-authored content | TLS; current posture is implicit trust in upstream maintainer. Pin dataset revision SHA if ingestion ever becomes scheduled or unattended (assessment). |
| B7 | Ingestion -> Aurora | Same channel as B4 | None at the channel; data crossing carries the corpus class | Same control surface as B4. Note: ingestion is the only path that creates the third-party-origin data that B3 later mixes. |
| B8 | Operator / CI -> AWS (Terraform apply) | GitHub Actions -> AWS account | Operator authoring infra -> AWS executing it | OIDC-federated role per environment; GitHub Environment manual gate on Prod (RAG001). |
| B9 | Browser -> CloudFront/S3 | Internet -> AWS edge | Anonymous public -> public static assets | TLS; no secrets in the bundle. Listed for completeness; no threat surface. |
The critical insight: B3 is the boundary the threat model spends most of its budget on, and it is not visible in the C4 model, because LikeC4 enumerates containers and relationships, not in-process mixing points. The threat model carries that load explicitly (threat model T1, T2).
Where the B3 mixture goes. The concatenated prompt — operator system prompt, third-party corpus chunks, user question — crosses B5 into Bedrock, and generation is invoked through a cross-region inference profile. The request is addressed to the regional bedrock-runtime endpoint, but the profile may execute it in any region of the us. group (RAG007 requires the IAM grant to cover each of them). The account and trust boundary do not change: the call stays inside AWS under the same IAM grant. What changes is the region of execution, so nothing here confines prompt content to the calling region.
User-input trajectory note. User-authored text crosses B1 (as transport into the system), B5 twice (as the plaintext question sent to the embedding model, and again inside the concatenated prompt sent to the generation model), and B3 (as the question concatenated into the prompt). B4 carries no user text: the similarity search sends the derived vector, not the question. Reading “Lambda -> Bedrock -> Aurora” should not be taken to mean user text is present at every step; it is present only where this row of the inventory says so.
Where these get documented
Section titled “Where these get documented”Decided in Decision #51 (closed 2026-06-01): this page is the canonical inventory. Network-hop boundaries (B1, B4–B7, B9) carry a #boundary tag on the relevant LikeC4 relationship, making them visible in liveQueryDesign and ingestionFlow. B3 stays narrative-only here because LikeC4 cannot model an in-process boundary without a synthetic container that would distort the architecture. B8 (Operator/CI → AWS) has no counterpart in the LikeC4 model and is documented here only.
Re-evaluation triggers
Section titled “Re-evaluation triggers”A new boundary appears or an existing one shifts when:
Authentication is added onRealized RAG009; B1 row updated above./query(B1 changes posture).- A Safety Gate is implemented (a new boundary between the LLM output and the user; Capability #44, Decision #55).
- The corpus is reclassified (data classification) — B6 and B7 change posture.
- Lambda moves into a VPC (B4, B5 become VPC-internal; new boundary at the VPC edge).
- Streaming responses are enabled (RAG004 revisit) — changes the buffering edge inside the handler.
© 2026 Benjamin Arunski