mirror of
https://github.com/Sea-Haven-Industries/proposal-system.git
synced 2026-10-04 23:02:03 +00:00
fix(infra): scope Bedrock model ARN, AOSS permissions, require deploy approval (INF-M1, M2, M9)
INF-M1: Replace wildcard anthropic.claude-* foundation-model ARN with the specific cross-region inference profile ARN and its backing foundation model. Both suggestions and pdf-extract Lambdas use us.anthropic.claude-sonnet-4-5-20250929-v1:0. INF-M2: Replace aoss:* data access policy permissions with scoped actions. KB role gets DescribeCollectionItems/CreateCollectionItems/UpdateCollectionItems on collection and DescribeIndex/ReadDocument/WriteDocument on indexes. Index creator gets CreateIndex/DescribeIndex/WriteDocument plus collection describe/create. INF-M9: Change --require-approval never to --require-approval broadening in infra/package.json deploy script so IAM/security changes require manual confirmation during local development.
This commit is contained in:
parent
8212c48d1e
commit
8da87e9301
3 changed files with 75 additions and 15 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
**Date:** 2026-05-27
|
**Date:** 2026-05-27
|
||||||
**Auditor:** Claude Code (6 parallel specialist agents)
|
**Auditor:** Claude Code (6 parallel specialist agents)
|
||||||
**Scope:** Full monorepo — API, Web, Mobile, Lambdas, Infrastructure/CI/CD, QA/Testing
|
**Scope:** Full monorepo — API, Web, Mobile, Lambdas, Infrastructure/CI/CD, QA/Testing
|
||||||
**Remediation Status:** Phase 1-5 complete (2026-05-27). All Critical and High findings fixed. 17 Medium findings fixed. CI pipeline runs all 108 tests. Test infrastructure bootstrapped.
|
**Remediation Status:** Phase 1-6 complete (2026-05-27). All Critical and High findings fixed. 20 Medium findings fixed. CI pipeline runs all 108 tests. Test infrastructure bootstrapped.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -178,12 +178,13 @@ All items below have been remediated:
|
||||||
|
|
||||||
| ID | Finding | Status |
|
| ID | Finding | Status |
|
||||||
|----|---------|--------|
|
|----|---------|--------|
|
||||||
| INF-M1-M2 | Bedrock wildcard model ARN, AOSS `aoss:*` permissions | |
|
| INF-M1 | Bedrock wildcard model ARN | **FIXED** — scoped to specific inference profile + foundation model ARN |
|
||||||
|
| INF-M2 | AOSS `aoss:*` data access permissions | **FIXED** — scoped to specific actions per principal (KB role vs index creator) |
|
||||||
| INF-M3-M4 | No Cognito advanced security, Google OAuth not in CDK | |
|
| INF-M3-M4 | No Cognito advanced security, Google OAuth not in CDK | |
|
||||||
| INF-M5 | No S3 enforceSSL | **FIXED** — `enforceSSL: true` on all 4 buckets |
|
| INF-M5 | No S3 enforceSSL | **FIXED** — `enforceSSL: true` on all 4 buckets |
|
||||||
| INF-M6-M7 | No custom domain on CF, no WAF | |
|
| INF-M6-M7 | No custom domain on CF, no WAF | |
|
||||||
| INF-M8 | Workflows pinned to @main | **FIXED** — SHA-pinned across all 3 workflow files |
|
| INF-M8 | Workflows pinned to @main | **FIXED** — SHA-pinned across all 3 workflow files |
|
||||||
| INF-M9 | `--require-approval never` locally | |
|
| INF-M9 | `--require-approval never` locally | **FIXED** — changed to `--require-approval broadening` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -269,10 +270,15 @@ Validators tested (36 tests). Lambda handlers tested (19 pytest tests for pdf-ge
|
||||||
48. ~~INF-M5~~ — DONE (enforceSSL on all 4 S3 buckets)
|
48. ~~INF-M5~~ — DONE (enforceSSL on all 4 S3 buckets)
|
||||||
49. ~~INF-M8~~ — DONE (SHA-pinned workflow refs in all 3 workflow files)
|
49. ~~INF-M8~~ — DONE (SHA-pinned workflow refs in all 3 workflow files)
|
||||||
|
|
||||||
### Phase 6 — Remaining (not yet started)
|
### Phase 6 — Infrastructure Medium Fixes (INF-M1, M2, M9)
|
||||||
|
50. ~~INF-M1~~ — DONE (Bedrock IAM scoped to specific inference profile ARN)
|
||||||
|
51. ~~INF-M2~~ — DONE (AOSS data access policy scoped per principal)
|
||||||
|
52. ~~INF-M9~~ — DONE (`--require-approval broadening` in deploy script)
|
||||||
|
|
||||||
|
### Phase 7 — Remaining (not yet started)
|
||||||
- WEB-H1: Token refresh mechanism (requires backend refresh token flow)
|
- WEB-H1: Token refresh mechanism (requires backend refresh token flow)
|
||||||
- Mobile High findings (MOB-H1 through H4): separate release cycle
|
- Mobile High findings (MOB-H1 through H4): separate release cycle
|
||||||
- Remaining Medium findings: API-M1/M2/M5/M7/M9/M10/M12/M13, WEB-M1/M3/M4/M8/M9/M11/M12, LAM-M2-M4/M6-M7/M9-M14, INF-M1-M4/M6-M7/M9
|
- Remaining Medium findings: API-M1/M2/M5/M7/M9/M10/M12/M13, WEB-M1/M3/M4/M8/M9/M11/M12, LAM-M2-M4/M6-M7/M9-M14, INF-M3-M4/M6-M7
|
||||||
- QA-C6: Mobile test coverage
|
- QA-C6: Mobile test coverage
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -132,16 +132,61 @@ export class ComputeStack extends cdk.Stack {
|
||||||
resources: [ossCollection.attrArn],
|
resources: [ossCollection.attrArn],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Fix: INF-M2 — scope AOSS data access policy permissions (was aoss:* on both
|
||||||
|
// collection and index). KB role needs read/write for embeddings. Index creator
|
||||||
|
// needs create/describe for bootstrapping the vector index.
|
||||||
const ossDataAccessPolicy = new opensearchserverless.CfnAccessPolicy(this, 'OssDataAccessPolicy', {
|
const ossDataAccessPolicy = new opensearchserverless.CfnAccessPolicy(this, 'OssDataAccessPolicy', {
|
||||||
name: 'proposal-system-kb-access',
|
name: 'proposal-system-kb-access',
|
||||||
type: 'data',
|
type: 'data',
|
||||||
policy: JSON.stringify([{
|
policy: JSON.stringify([
|
||||||
Rules: [
|
{
|
||||||
{ ResourceType: 'collection', Resource: ['collection/proposal-system-kb'], Permission: ['aoss:*'] },
|
Description: 'Bedrock KB role — read/write documents and describe collection',
|
||||||
{ ResourceType: 'index', Resource: ['index/proposal-system-kb/*'], Permission: ['aoss:*'] },
|
Rules: [
|
||||||
],
|
{
|
||||||
Principal: [kbRole.roleArn, indexCreatorFn.role!.roleArn],
|
ResourceType: 'collection',
|
||||||
}]),
|
Resource: ['collection/proposal-system-kb'],
|
||||||
|
Permission: [
|
||||||
|
'aoss:DescribeCollectionItems',
|
||||||
|
'aoss:CreateCollectionItems',
|
||||||
|
'aoss:UpdateCollectionItems',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ResourceType: 'index',
|
||||||
|
Resource: ['index/proposal-system-kb/*'],
|
||||||
|
Permission: [
|
||||||
|
'aoss:DescribeIndex',
|
||||||
|
'aoss:ReadDocument',
|
||||||
|
'aoss:WriteDocument',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Principal: [kbRole.roleArn],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Description: 'Index creator Lambda — create and describe index during bootstrap',
|
||||||
|
Rules: [
|
||||||
|
{
|
||||||
|
ResourceType: 'collection',
|
||||||
|
Resource: ['collection/proposal-system-kb'],
|
||||||
|
Permission: [
|
||||||
|
'aoss:DescribeCollectionItems',
|
||||||
|
'aoss:CreateCollectionItems',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ResourceType: 'index',
|
||||||
|
Resource: ['index/proposal-system-kb/*'],
|
||||||
|
Permission: [
|
||||||
|
'aoss:CreateIndex',
|
||||||
|
'aoss:DescribeIndex',
|
||||||
|
'aoss:WriteDocument',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Principal: [indexCreatorFn.role!.roleArn],
|
||||||
|
},
|
||||||
|
]),
|
||||||
});
|
});
|
||||||
ossDataAccessPolicy.addDependency(ossCollection);
|
ossDataAccessPolicy.addDependency(ossCollection);
|
||||||
|
|
||||||
|
|
@ -354,9 +399,14 @@ export class ComputeStack extends cdk.Stack {
|
||||||
internalApiKeySecret.grantRead(suggestionsFunction);
|
internalApiKeySecret.grantRead(suggestionsFunction);
|
||||||
// Fix: LAM-C1/INF-H1 — grant Function URL invoke permission for IAM auth
|
// Fix: LAM-C1/INF-H1 — grant Function URL invoke permission for IAM auth
|
||||||
apiFunctionUrl.grantInvokeUrl(suggestionsFunction);
|
apiFunctionUrl.grantInvokeUrl(suggestionsFunction);
|
||||||
|
// Fix: INF-M1 — scope Bedrock model ARN to the specific inference profile used
|
||||||
|
// (was wildcard anthropic.claude-*). Lambda MODEL_ID is a cross-region inference profile.
|
||||||
suggestionsFunction.addToRolePolicy(new iam.PolicyStatement({
|
suggestionsFunction.addToRolePolicy(new iam.PolicyStatement({
|
||||||
actions: ['bedrock:InvokeModel'],
|
actions: ['bedrock:InvokeModel'],
|
||||||
resources: [`arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-*`],
|
resources: [
|
||||||
|
`arn:aws:bedrock:us-east-1:${this.account}:inference-profile/us.anthropic.claude-sonnet-4-5-20250929-v1:0`,
|
||||||
|
`arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-5-20250929-v1:0`,
|
||||||
|
],
|
||||||
}));
|
}));
|
||||||
suggestionsFunction.addToRolePolicy(new iam.PolicyStatement({
|
suggestionsFunction.addToRolePolicy(new iam.PolicyStatement({
|
||||||
actions: ['bedrock:Retrieve'],
|
actions: ['bedrock:Retrieve'],
|
||||||
|
|
@ -388,9 +438,13 @@ export class ComputeStack extends cdk.Stack {
|
||||||
// Fix: LAM-C1/INF-H1 — grant Function URL invoke permission for IAM auth
|
// Fix: LAM-C1/INF-H1 — grant Function URL invoke permission for IAM auth
|
||||||
apiFunctionUrl.grantInvokeUrl(pdfExtractFunction);
|
apiFunctionUrl.grantInvokeUrl(pdfExtractFunction);
|
||||||
props.uploadsBucket.grantRead(pdfExtractFunction);
|
props.uploadsBucket.grantRead(pdfExtractFunction);
|
||||||
|
// Fix: INF-M1 — scope Bedrock model ARN to the specific inference profile used
|
||||||
pdfExtractFunction.addToRolePolicy(new iam.PolicyStatement({
|
pdfExtractFunction.addToRolePolicy(new iam.PolicyStatement({
|
||||||
actions: ['bedrock:InvokeModel'],
|
actions: ['bedrock:InvokeModel'],
|
||||||
resources: [`arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-*`],
|
resources: [
|
||||||
|
`arn:aws:bedrock:us-east-1:${this.account}:inference-profile/us.anthropic.claude-sonnet-4-5-20250929-v1:0`,
|
||||||
|
`arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-5-20250929-v1:0`,
|
||||||
|
],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Python Lambda: PDF Generate
|
// Python Lambda: PDF Generate
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
"watch": "tsc -w",
|
"watch": "tsc -w",
|
||||||
"cdk": "cdk",
|
"cdk": "cdk",
|
||||||
"synth": "cdk synth",
|
"synth": "cdk synth",
|
||||||
"deploy": "cdk deploy --all --require-approval never"
|
"deploy": "cdk deploy --all --require-approval broadening"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aws-cdk-lib": "2.257.0",
|
"aws-cdk-lib": "2.257.0",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue