Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,25 @@ export function grantManagedKbProvisioning(
'bedrock:DeleteKnowledgeBase',
'bedrock:CreateDataSource',
'bedrock:DeleteDataSource',
// `CreateKnowledgeBase` is called WITH tags (provisioning.py passes
// `tags=build_tags(...)`), and AWS authorises the tagging as a separate
// `bedrock:TagResource` action against `knowledge-base/*` — the resource
// does not exist yet, so the wildcard is the only thing it can match.
// Without this the create fails outright:
//
// AccessDeniedException: not authorized to perform bedrock:TagResource
//
// and it fails *after* passing every review, because the create action
// itself is granted. Those tags are not decoration: they are what the
// reconciler and teardown match knowledge bases on, so creating untagged
// would be worse than failing.
'bedrock:TagResource',
// The reconciler reads tags to decide what belongs to this project
// (`tombstones.iter_project_knowledge_bases` → `list_tags_for_resource`).
// It fails closed on a read error, so without this permission every
// knowledge base looks untagged, matches nothing, and the orphan sweep
// silently reports a clean account forever.
'bedrock:ListTagsForResource',
],
resources: [knowledgeBaseArnWildcard(config)],
}));
Expand Down
26 changes: 26 additions & 0 deletions infrastructure/test/managed-kb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,36 @@ describe('ManagedKbRoleConstruct — caller grants', () => {
'bedrock:DeleteKnowledgeBase',
'bedrock:CreateDataSource',
'bedrock:DeleteDataSource',
'bedrock:TagResource',
'bedrock:ListTagsForResource',
]);
expect(s.Resource).toBe(KB_ARN_WILDCARD);
});

it('can tag a knowledge base at create time', () => {
// `CreateKnowledgeBase` is called WITH tags, and AWS authorises the tagging
// as a separate action. Missing it, provisioning failed in dev with
//
// AccessDeniedException: not authorized to perform bedrock:TagResource
//
// *after* passing review, because the create action itself was granted. The
// tags are what the reconciler and teardown match on, so an untagged
// knowledge base would be worse than a failed create.
const s = statementBySid(t, 'ManagedKbProvisionCrud');
expect(s.Action).toContain('bedrock:TagResource');
// Must be the wildcard: at create time the knowledge base has no ARN, so a
// resource-specific grant could never match.
expect(s.Resource).toBe(KB_ARN_WILDCARD);
});

it('can read tags, which is how the reconciler recognises its own resources', () => {
// `iter_project_knowledge_bases` fails closed on a tag read error, so
// without this the orphan sweep sees every knowledge base as untagged,
// matches nothing, and reports a clean account forever.
const s = statementBySid(t, 'ManagedKbProvisionCrud');
expect(s.Action).toContain('bedrock:ListTagsForResource');
});

it('keeps the non-resource-scopable create/list actions in their own statement', () => {
const s = statementBySid(t, 'ManagedKbProvisionCreateList');
expect(s.Action).toEqual(['bedrock:CreateKnowledgeBase', 'bedrock:ListKnowledgeBases']);
Expand Down