# 3LO in Bedrock Managed KB: 5-minute setup, 1 irreversible decision

On September 4, 2026 AWS shipped user-managed setup (3LO) for SharePoint, OneDrive and Confluence in Amazon Bedrock Managed Knowledge Base: you sign in with your own account and the data source is live in minutes. What the docs say in fine print is that this path does not support document-level access control, and that the ACL flag cannot be changed after CreateDataSource. This is the story of the migration that forces — from a 3LO prototype to a production knowledge base on ENTRA_ID_APP_ONLY, certificate and userContext.

- URL: https://fernando.moretes.com/blog/3lo-no-bedrock-managed-kb-5-minutos-de-setup-1-decisao-irreversivel-amazon-bedro

- Markdown: https://fernando.moretes.com/blog/3lo-no-bedrock-managed-kb-5-minutos-de-setup-1-decisao-irreversivel-amazon-bedro/article.md?lang=en

- Published: 2026-09-05T10:15:56.145Z

- Category: AI & Agents

- Tags: bedrock, rag, iam, sharepoint, confluence, governance, oauth

- Reading time: 9 min

- Source: [Amazon Bedrock Managed Knowledge Base introduces user-managed setup for SharePoint, OneDrive, and Confluence data sources](https://aws.amazon.com/about-aws/whats-new/2026/09/amazon-bedrock-managed-knowledge-base-user-managed-setup-sharepoint-onedrive-confluence/)

---

The question that matters in this announcement isn't "how long does it take to connect SharePoint?" — it's "who can read what you indexed once it's connected?". The user-managed setup (3LO) AWS shipped on September 4, 2026 for SharePoint, OneDrive and Confluence in Amazon Bedrock Managed Knowledge Base answers the first question very well: you click **Sign in**, authorize with your corporate account, and Bedrock creates the Secrets Manager secret with the refresh token for you. The second question is where I spent three weeks.

## What the five-minute path actually trades away

The SharePoint setup page is explicit and worth reading twice: *user-managed setup does not support document-level access control (ACL)*. All indexed content is accessible to anyone who can query the knowledge base, and individual SharePoint permissions are not enforced. The same sentence shows up on the Confluence page, word for word.

This isn't a bug or a temporary gap — it follows directly from the flow. In 3LO, Bedrock stores a **delegated refresh token**, issued to you, carrying four permissions: `Sites.Read.All` and `User.Read` on Microsoft Graph, `offline_access` to renew the token, and `AllSites.Read` on the SharePoint Online API. These are *delegated* permissions, inherited from what your account can see. The crawler walks into the tenant wearing your identity and copies everything it can reach into an index that has no notion of who is who.

The path that does support ACL is a different one: `ENTRA_ID_APP_ONLY` for SharePoint, `ENTRA_APP_ID` for OneDrive, `SERVICE_ACCOUNT` for Google Drive, `BASIC` for Confluence. Those are **application** permissions, with admin consent, and for SharePoint with ACLs they require `Sites.FullControl.All` — or `Sites.Selected` with a per-site `fullcontrol` grant — because `Sites.Read.All` is not enough to read item-level permissions.

The trade, stated plainly: 3LO swaps a two-week ticket with the identity team for an index with no internal border. For a prototype over a public engineering wiki, that's a good deal. For the credit policy repository, it's an incident waiting for a date.

## The journey: from a 3LO prototype to a production knowledge base

1. **Week 0 — the prototype is born in the console, asking nobody** — An analyst holding `bedrock:GetDataSourceAuthorizationUrl`, `bedrock:CreateDataSourceToken` and `secretsmanager:CreateSecret` completes the flow alone. Bedrock creates the secret at `arn:aws:secretsmanager:{region}:{account}:secret:bedrock-managedkb-oauth/{prefix}/{connector}/{uuid}` and the data source comes up with `authType=MANAGED_OAUTH2`. No ticket, no tenant ID, no review.

2. **Week 1 — the gate nobody read** — The Entra App-Only page states what locks the whole journey: the decision to enable ACLs *cannot be changed after the data source is created*. And 3LO doesn't offer the option at all. Meaning: there is no in-place upgrade from `MANAGED_OAUTH2` to ACL — there is a new data source and a full re-ingestion.

3. **Week 2 — inventory of what was already copied** — Before building the new path, answer what the old one already indexed. The crawl followed the identity of whoever signed in; if that person is senior, the reach is theirs. List the included sites and spaces, cross them against your data classification, and treat the current index as a copy repository — because that's what it is.

4. **Week 3 — app registration and certificate** — Here the ticket 3LO had eliminated comes back. A Global Administrator or Privileged Role Administrator registers the single-tenant application with no redirect URI, adds the **application** permissions and grants admin consent. You generate a pair with `openssl req -x509 -newkey rsa:2048`, upload the `.cer` to Entra and the `.p12` bundle to S3 with SSE. The `.p12` is mandatory when ACLs are on.

5. **Week 4 — secret, service role and the new data source** — The secret carries `clientId` and `certificatePassword` — always set the password explicitly; if you omit it, Bedrock opens the bundle using the client ID as the password. The service role gets `s3:GetObject` on the certificate object with an `aws:ResourceAccount` condition, plus `kms:Decrypt` if you used a CMK. The data source is created with `certificateS3Path`, which `ENTRA_ID_APP_ONLY` requires even with ACLs off.

6. **Week 5 — the application starts proving who is asking** — `Retrieve` gains `userContext.userId` with the user's universal email. Without it, ACL-enabled data sources return zero results — excellent as a fail-safe, terrible as a production surprise. Authentication stays yours: Bedrock filters by the identity you assert, it does not verify that the assertion is true.

7. **Week 6 — delete the old path, including the secret** — Delete the `MANAGED_OAUTH2` data source and the orphaned `bedrock-managedkb-oauth/*` secret — it still holds a valid refresh token. On the Microsoft side, revoke by disabling or deleting the service principal under **Enterprise applications**; on Atlassian the grant is per site, so every `*.atlassian.net` needs its own revocation.

## The two phases and the immutable gate between them

3LO is fast because it ends in a delegated refresh token; production is slow because it starts from a certificate and admin consent. The gate in the middle isn't a step — it's a decision you can only make once per data source.

### 🧪 Fase 1 — Protótipo (3LO, minutos)

- Console Bedrock KB GetDataSourceAuthorizationUrl (frontend)
- Secrets Manager bedrock-managedkb-oauth/.../uuid (security)
- Data source authType=MANAGED_OAUTH2 (data)

### 🔐 Entra ID / Atlassian — consentimento

- Consentimento delegado Sites.Read.All + offline_access (external)
- Admin consent do tenant obrigatório se o tenant restringe apps (external)

### 🚧 O portão imutável

- aclEnabled não muda após CreateDataSource (security)

### 🟧 AWS — Fase 2 — Produção (2LO + ACL)

- Entra app registration application perms + Sites.FullControl.All (security)
- Amazon S3 certificate.p12 (SSE) (storage)
- Data source ENTRA_ID_APP_ONLY + ACL (data)
- Managed KB conteúdo + permissões crawladas (ai)
- Retrieve userContext.userId = e-mail (ai)

### 👤 Sua aplicação — autenticação verificada

- App corporativa OIDC valida o usuário final (compute)

### Flows

- analista -> signin: 1. Sign in
- signin -> consent: 2. OAuth popup
- consent -> adminconsent: blocked without consent
- signin -> secret3lo: 3. stores refresh token
- secret3lo -> ds3lo: 4. generated secretArn
- ds3lo -> gate: 5. no ACL, permanently
- gate -> dsprod: 6. new data source + re-ingestion
- entraapp -> certs3: .p12 (private key)
- certs3 -> dsprod: certificateS3Path
- dsprod -> kb: content and ACL crawl
- app -> retrieve: already-verified identity
- retrieve -> kb: pre-retrieval filter
- kb -> retrieve: real-time check at the source

## Before and after, in numbers the docs confirm

- **4** — delegated permissions granted on the 3LO path. `Sites.Read.All`, `User.Read`, `offline_access` and `AllSites.Read` — read access to everything the signing account can see, renewable indefinitely.
- **0** — documents filtered by permission under 3LO. No ACL means no `userContext`: whoever queries the knowledge base reads the entire index, regardless of their SharePoint access.
- **365 dias** — default certificate validity on the production path. An expired certificate makes every sync fail. Rotation becomes a runbook item with an owner and a date — not a memory.

## Identity: email is the key, and there is no translation

Getting to the ACL path solves less than it looks, and it solves it in a very specific way. Bedrock Managed Knowledge Base uses **email as the universal identifier** — there is no alias resolution and no cross-identity-provider mapping. The `userId` you pass to `Retrieve` must match exactly the email associated with that user in each connected data source. If your corporate IdP issues `fernando.azevedo@company.com` and Confluence stores `fazevedo@company.com`, the match fails silently and the user simply gets no results from that source. Silence is the worst failure mode a search system can have: nobody files a ticket over an incomplete answer, they file over a wrong one.

Groups run on a different ruler. They're identified however the source represents them — name, ID, whatever — and user→group membership comes from the crawl. The docs are blunt: **group memberships are as fresh as the last sync**. If a permission changed between syncs, the pre-retrieval filter doesn't know. The saving grace is the second layer: for SharePoint, OneDrive, Google Drive and Confluence there's real-time verification against the source, which catches exactly that window. S3 and Custom have no such net, because their ACLs come from a metadata file you supply.

Two notes that change your application design: third-party IdP credentials are cached for up to **1 hour**, and permission changes are eventually consistent, typically within a few minutes. So "I revoked access now" and "the RAG stopped showing it" are not the same instant. In a BACEN- or LGPD-bound environment, that gap belongs in the design document, not in the audit findings.

## The two paths, side by side
| Criterion | Prototype — `MANAGED_OAUTH2` (3LO) | Production — `ENTRA_ID_APP_ONLY` (2LO) |
| --- | --- | --- |
| Who authorizes | The user, in the popup — unless the tenant restricts third-party apps, in which case admin consent is required again | Global Administrator or Privileged Role Administrator, with explicit admin consent |
| Stored credential | Delegated refresh token, in a secret Bedrock creates itself | A `.p12` certificate in S3 plus `clientId`/`certificatePassword` in a secret you create |
| Document-level access control | Not supported — and the flag can't change afterwards | Supported, with pre-retrieval filtering and real-time verification |
| Crawl reach | Whatever the signing account can see — variable, invisible from the AWS console | The whole tenant with `Sites.Read.All`/`Sites.FullControl.All`, or site by site with `Sites.Selected` |
| What breaks | The offboarding of whoever authorized; a token revoked in Entra; content shared after the sync, which needs a resync | An expired certificate (every sync fails); a forgotten per-site grant for a new site, which is not retroactive |

## The failure modes that only show up later

**The token has an owner, and owners resign.** The 3LO refresh token belongs to a person. When they leave and the account is disabled, the sync stops — and the index stays right there, holding whatever content they could reach. The production path has no such coupling: the application authenticates with a certificate, with no human sign-in at crawl time or query time.

**Fail-closed is good, but it looks like a bug.** ACL-aware retrieval fails closed: a group-resolution error, a real-time verification timeout or an internal error means the document is not returned. The response may carry fewer results than the requested `maxResults`, and Bedrock does **not** backfill. Your application must treat partial responses as normal, and tell "zero because of ACL" apart from "zero because of relevance" — the API signals resolution failures precisely for that.

**A document without an ACL is an invisible document.** In an ACL-enabled data source, a document whose permissions weren't extracted goes to nobody. Absence is treated as restricted, not public. After the migration, expect a recall drop and investigate that before blaming the embedding model.

**The secret prefix is your only IAM lever, and the default is ambiguous.** The 3LO IAM page says that without a prefix Bedrock uses `default`; the connector pages say the created secret uses the `bedrock-managedkb-oauth` prefix. Don't build a policy on that assumption: supply an explicit **secret name prefix** at sign-in and write the policy with `Resource` scoped to it *before* anyone runs the flow. That's the difference between `secretsmanager:CreateSecret` on a predictable path and a `Resource: "*"` nobody will review later.

> **The risk isn't 3LO — it's the 3LO nobody planned for:** Two Bedrock permissions (`GetDataSourceAuthorizationUrl` and `CreateDataSourceToken`) plus `secretsmanager:CreateSecret` are enough for anyone with console access to index the corporate SharePoint into a knowledge base with no internal border, without touching a single identity process. If your production account already grants those actions by wildcard in some "Bedrock developer" policy, you don't have a new feature — you have a new path to accidentally authorized exfiltration. Deny `bedrock:CreateDataSourceToken` outside sandbox accounts before you discuss RAG architecture.

## Anti-patterns I've watched grow out of this flow

- **Promoting the prototype by switching `authType`**: it doesn't exist. The ACL flag is immutable per data source, so promoting means creating a new data source and re-ingesting — plan the re-ingestion cost and the duplicate-index window.
- **Authorizing 3LO with the architect's account**: the more senior the authorizer, the wider the crawl. If you're going to use 3LO, use an account with deliberately narrow access to the in-scope sites.
- **Treating ACL awareness as authorization**: the docs themselves say it's filtering, not a security boundary. Bedrock does not authenticate end users — it trusts the `userId` your application asserts.
- **Unblocking user-installed apps in Atlassian "just for a minute"**: while that toggle is open, any user can authorize any OAuth app across the entire site. Have the admin authorize directly instead.
- **Leaving the 3LO secret behind during cleanup**: deleting the data source doesn't delete the secret, and it holds a refresh token that still renews.

## Well-Architected lens on the decision

- **security**: Deny `bedrock:CreateDataSourceToken` in production accounts via SCP; require a secret name prefix and scope `Resource` to it; prefer `Sites.Selected` over `Sites.FullControl.All` whenever the site list is known; store the `.p12` with SSE-KMS and `kms:Decrypt` restricted to the service role.
- **reliability**: A certificate with the default 365-day validity takes every sync down when it expires — alarm 45 days ahead. Per-site grants are not retroactive: a new site without a grant simply isn't crawled, with no visible error on the data source.

## Let the prototype exist — in an account where it can't grow up

The obvious temptation after reading all this is to block 3LO and be done. I wouldn't. The friction it removes is real: without it, every RAG experiment over the internal wiki turns into a two-week ticket with the identity team, and the practical outcome is that nobody experiments — or worse, somebody exports the wiki into a bucket and builds RAG on the side, with no crawler, no sync and none of the checks we just discussed.

The design I recommend is topological, not political. **One sandbox account** where `bedrock:GetDataSourceAuthorizationUrl` and `bedrock:CreateDataSourceToken` are allowed, with no classified data and a short lifecycle — the whole index dies in N days by process, not by memory. **Production accounts** with those two actions denied by SCP, which makes 3LO disappear from the menu without a case-by-case argument.

What crosses that border isn't the data source; it's the learning. The prototype answers the genuinely expensive questions: which Confluence spaces hold content that resolves real doubts, which chunking strategy survives an 80-page policy document, whether agentic retrieval with `maxAgentIteration` above the default of 5 changes the answer enough to justify the cost. None of that depends on ACLs. When the answer is "worth it", then you open the ticket with the Entra team knowing exactly which sites to request under `Sites.Selected` — and the ticket is shorter because you arrive with a scope, not an intention.

> **What I'd do on Monday:** Before enabling anything, I'd grep the production account's policies for `bedrock:*` — the odds that the two new actions are already granted by wildcard are high, and no IAM review done before September 2026 could have accounted for them. Then I'd create the sandbox account with the inverted SCP, because blocking production without offering the right place just pushes the problem outside my field of view. I learned that the expensive way on a financial platform: the architecture decision that looks like security is almost always about ergonomics — people route around inconvenient controls with a creativity no policy anticipates. And I'd keep the rule I apply to every new connector: if the flag can't be changed later, it isn't configuration, it's design — and design goes into an ADR, with the trade-off written and signed before `CreateDataSource`.

## Verdict

Use user-managed setup (3LO) when all three conditions hold together: the content is already readable by the knowledge base's entire audience, the index lives in an account with no classified data, and it has an agreed expiration date. Outside that, go straight to `ENTRA_ID_APP_ONLY` for SharePoint, `ENTRA_APP_ID` for OneDrive or `BASIC` for Confluence — not because 3LO is poorly built, but because the ACL flag can't change after `CreateDataSource`, and today's five-minute shortcut costs a full re-ingestion plus an Entra-team ticket later. This announcement isn't about authentication; it's about where your organization's access boundary exists — and 3LO answers that it stops existing inside the index. That's a legitimate choice for a prototype and an audit finding for everything else.

**Rating:** Adote em sandbox, negue em produção

## References

- [AWS What's New — Bedrock Managed Knowledge Base introduces user-managed setup for SharePoint, OneDrive, and Confluence (](https://aws.amazon.com/about-aws/whats-new/2026/09/amazon-bedrock-managed-knowledge-base-user-managed-setup-sharepoint-onedrive-confluence/)
- [Amazon Bedrock User Guide — SharePoint user-managed setup (3LO)](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-managed-sharepoint-3lo-setup.html)
- [Amazon Bedrock User Guide — Confluence user-managed setup (3LO)](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-managed-confluence-3lo-setup.html)
- [Amazon Bedrock User Guide — IAM permissions for user-managed setup (3LO)](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-managed-3lo-setup.html)
- [Amazon Bedrock User Guide — Access Control Lists awareness enablement](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-managed-acl.html)
- [Amazon Bedrock User Guide — ACL-aware retrieval on managed knowledge bases (userContext)](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-retrieve-acl.html)
- [Amazon Bedrock User Guide — Set up Microsoft Entra ID App-Only authentication for SharePoint](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-managed-sharepoint-entra-setup.html)
- [AWS ML Blog — Build enterprise search for agents with Amazon Bedrock Managed Knowledge Base](https://aws.amazon.com/blogs/machine-learning/build-enterprise-search-for-agents-with-amazon-bedrock-managed-knowledge-base/)
