Skip to content

Add advanced Policy + Lambda Interceptor sample to lakehouse-agent#1389

Open
ren8k wants to merge 12 commits intoawslabs:mainfrom
ren8k:feature/advanced-agentcore-policy-gateway-interceptor
Open

Add advanced Policy + Lambda Interceptor sample to lakehouse-agent#1389
ren8k wants to merge 12 commits intoawslabs:mainfrom
ren8k:feature/advanced-agentcore-policy-gateway-interceptor

Conversation

@ren8k
Copy link
Copy Markdown

@ren8k ren8k commented Apr 22, 2026

Important

  1. We strictly follow a issue-first approach, please first open an issue relating to this Pull Request.
  2. Once this Pull Request is ready for review please attach review ready label to it. Only PRs with review ready will be reviewed.

Issue number:

Concise description of the PR

Adds an advanced AgentCore Policy + Lambda Interceptor sample alongside 02-use-cases/lakehouse-agent/, as publicly runnable reference code for the companion blog post "Build Secure AI Agent Behavior with Policy and Lambda Interceptors in Amazon Bedrock AgentCore". The sample covers all three patterns described in the post: Policy only, Interceptor only, and Policy + Interceptor.

The change is strictly additive — no existing Phase 1 code is modified. Everything new lives in a single new folder, 02-use-cases/lakehouse-agent/deployment/advanced-agentcore-policy-gateway-interceptor/. The only edits to pre-existing files are three README-level additions that link to the new folder. Phase 1 still works standalone.

User experience

Before: lakehouse-agent/ demonstrates OAuth + Lake Formation row/column-level security, but has no runnable example of Cedar-based AgentCore Policy or of combining Policy with a Lambda Interceptor.

After: Readers of the blog post can clone the repo, run Phase 1 as before, then cd into the new folder and run two commands (bash scripts/pre-deploy.sh and npx cdk deploy) to deploy Phase 2. Phase 2 reads all of its inputs from SSM parameters that Phase 1 already writes — no manual wiring. verification/verify_policy.py exercises all three patterns end to end and prints Results: 13/13 passed.

What this PR adds under the new folder:

  • A CDK (TypeScript) stack that provisions the LakehousePolicyEngine, four Cedar policies (permit_all, forbid_policyholder_summary, forbid_eu_individual_claims, forbid_restricted_geography), the IAM permissions the Gateway role needs, and an UpdateGateway call that re-attaches both Interceptors together with the Policy Engine in ENFORCE mode.
  • A Design 3 request Interceptor Lambda source that injects USER_GEOGRAPHY for Cedar to evaluate as context.input.geography.
  • A pre-deploy.sh helper that generates cdk.json from SSM, temporarily detaches the Interceptors (required so Cedar policy validation succeeds), and redeploys the Design 3 Lambda. One caveat — that it overwrites the Phase 1 Lambda source on disk while packaging — is documented in the Phase 2 README together with the rollback command.
  • verification/verify_policy.py, a 13-check end-to-end verification script.
  • README additions that thread Phase 2 into the existing guides and call out that each Cognito test user must sign in once through the Streamlit UI before verify_policy.py runs (discovered during a clean-account end-to-end deploy; setup_cognito.py leaves users in FORCE_CHANGE_PASSWORD state).

Tested

End-to-end on a clean AWS account (us-east-1), following the updated READMEs verbatim:

  • Phase 1 (Step 1–7) completes cleanly; SSM parameters populated, sample data loaded (9 claims + 5 users).
  • Phase 2 CDK deploys in ~2 minutes; the Policy Engine and all four Cedar policies report ACTIVE.
  • verification/verify_policy.pyResults: 13/13 passed (7 Design 1 checks, 3 Design 2 checks, 3 Design 3 checks).

Checklist

  • I have reviewed the contributing guidelines
  • Add your name to CONTRIBUTORS.md
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?
  • Are you uploading a dataset?
  • Have you documented Introduction, Architecture Diagram, Prerequisites, Usage, Sample Prompts, and Clean Up steps in your example README?
    • Introduction / Prerequisites / Usage / Cleanup are in deployment/advanced-agentcore-policy-gateway-interceptor/README.md. Architecture is deliberately not duplicated — it is the same as the existing Phase 1 diagram and is covered by the blog post.
  • I agree to resolve any issues created for this example in the future.
  • I have performed a self-review of this change
  • Changes have been tested (see "Tested" section above)
  • Changes are documented

Acknowledgment

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.

ren8k added 11 commits April 21, 2026 11:11
…a Interceptor

Add package.json, tsconfig.json, cdk.json.example, and .gitignore under
deployment/advanced-agentcore-policy-gateway-interceptor/ as the base for
Phase 2 (AgentCore Cedar Policy + Lambda Interceptor) deployment.

- cdk.json is generated at deploy-time by scripts/generate-cdk-context.sh
  from SSM Parameter Store, so only cdk.json.example is tracked.
PolicyStack provisions:
- CfnPolicyEngine (AgentCore Policy Engine)
- CfnPolicy x N (Cedar policies, permit_all first then forbids)
- IAM inline policy on Gateway role for policy evaluation permissions
- AwsCustomResource to re-attach Interceptors + Policy Engine to the Gateway

bin/app.ts reads account/region from CDK context (or CDK_DEFAULT_ACCOUNT/REGION)
so no hard-coded AWS account ID is required for public distribution.
The repository root .gitignore excludes lib/ globally (matches Node.js
build output convention). Add a negation rule for the advanced
AgentCore Policy sample so lib/policy-stack.ts is tracked.

Also adds lib/policy-stack.ts itself, which was silently ignored in
the previous commit.
- permit_all.cedar: baseline allow (deny-by-default without this)
- forbid_policyholder_summary.cedar: Design 1 — policyholders group
  cannot invoke get_claims_summary
- forbid_eu_individual_claims.cedar: Design 3 — users flagged as EU
  geography cannot invoke query_claims / get_claim_details
- forbid_restricted_geography.cedar: Design 3 — RESTRICTED geography
  is denied on all tools

{gateway_arn} in each file is substituted at synth time by PolicyStack.
Design 3 version of the request interceptor injects user geography into
params.arguments.geography so the Cedar policy can evaluate it as
context.input.geography.

During pre-deploy, this file overwrites the Phase 1 Lambda source at
deployment/5-gateway-setup/interceptor-request/lambda_function.py and
redeploys the Lambda.
- generate-cdk-context.sh: auto-generates cdk.json from SSM parameters
  populated by Phase 1 deployment (account, gateway ARN, interceptor
  ARNs, cognito client IDs, etc.). Uses `aws sts get-caller-identity`
  to derive the account ID instead of hard-coding it.
- detach-interceptors.py: detaches Interceptors from the Gateway so
  Cedar Policy validation can complete (its internal MCP validation
  requests are SigV4-signed and fail on JWT-validating Interceptors).
- pre-deploy.sh: orchestrates the 3 preparation steps (context,
  detach, Lambda update) before `cdk deploy`.
verification/verify_policy.py runs 13 checks covering all three
design patterns described in the blog post:
- Design 1 (Policy Only): forbid policyholders from get_claims_summary
- Design 2 (Interceptor Only): row-level isolation + column masking
  via Lake Formation using tenant-scoped credentials
- Design 3 (Policy + Interceptor): geography-based access control
  where the interceptor injects geography and Cedar evaluates it

The script loads all configuration from SSM Parameter Store and uses
the default boto3 credential chain, so no AWS profile is hard-coded.

Lives under verification/ rather than test/ so it is not mistaken for
a CDK unit-test directory.
README covers:
- Prerequisites (depends on Phase 1 being deployed)
- Directory layout
- Deploy: pre-deploy.sh (generate cdk.json, detach interceptors,
  update Lambda) + cdk deploy + activation check + verify_policy
- Policy-by-policy explanation of what each Cedar file enforces
- Cleanup (Phase 2 then Phase 1, in reverse order) including how to
  roll back the Design 3 Lambda changes before Phase 1 cleanup
- Troubleshooting table for common failure modes
…hase 1 guide

- Intro: describe the Phase 1 / Phase 2 split up front so readers know the
  CDK sample is opt-in.
- New Step 9 section points to advanced-agentcore-policy-gateway-interceptor/README.md
  and summarizes what it adds (Policy Engine, 4 Cedar policies, Gateway re-attach,
  Design 3 Lambda upgrade).
- Quick Reference row and Directory Structure entry updated to include the
  Phase 2 directory.
- Cleanup: call out that Phase 2 must be destroyed first (cdk destroy) so
  Phase 1 cleanup can remove the Gateway role without attached policy
  evaluation permissions.
…Interceptor sample

Adds a short "Optional: Advanced AgentCore Policy + Lambda Interceptors (Phase 2)"
section after the base deployment options. It introduces the three designs
from the blog post (Policy Only / Interceptor Only / Policy + Interceptor)
and links to the detailed Phase 2 README.
…e verify_policy.py

setup_cognito.py creates users with a temporary password, so every user
starts in Cognito FORCE_CHANGE_PASSWORD state. admin_initiate_auth then
returns a NEW_PASSWORD_REQUIRED challenge instead of an
AuthenticationResult, which breaks any client that does not handle the
challenge — including the Phase 2 verify_policy.py.

Surface this prerequisite in two READMEs:

- deployment/README.md (Step 1 Cognito): tell readers to complete the
  first sign-in through the Streamlit UI once per user, and note that
  PasswordHistorySize is unset so reusing TempPass123! as the new
  password works.
- deployment/advanced-agentcore-policy-gateway-interceptor/README.md
  (before Step 4): call out the same requirement right before the
  verify_policy.py run so Phase 2 users notice it.

Discovered during a clean-account walkthrough of the full deploy path;
without this step verify_policy.py aborts at the first authenticate_user
call with KeyError: 'AuthenticationResult'.
@github-actions github-actions Bot added the 02-use-cases 02-use-cases label Apr 22, 2026
@ren8k ren8k changed the title Feature/advanced agentcore policy gateway interceptor Add advanced Policy + Lambda Interceptor sample to lakehouse-agent Apr 22, 2026
Follows the Pull Request checklist item "Add your name to
CONTRIBUTORS.md" for the advanced AgentCore Policy + Lambda
Interceptor sample (PR awslabs#1389).
@BharathiSrini BharathiSrini self-requested a review April 22, 2026 15:45

if tenant_credentials:
logger.info(
f"🔑 Obtained temporary credentials for role: {tenant_credentials['RoleName']}"
@github-actions
Copy link
Copy Markdown

Latest scan for commit: fd26a69 | Updated: 2026-04-22 15:50:24 UTC

Security Scan Results

Scan Metadata

  • Project: ASH
  • Scan executed: 2026-04-22T15:50:12+00:00
  • ASH version: 3.0.0

Summary

Scanner Results

The table below shows findings by scanner, with status based on severity thresholds and dependencies:

Column Explanations:

Severity Levels (S/C/H/M/L/I):

  • Suppressed (S): Security findings that have been explicitly suppressed/ignored and don't affect the scanner's pass/fail status
  • Critical (C): The most severe security vulnerabilities requiring immediate remediation (e.g., SQL injection, remote code execution)
  • High (H): Serious security vulnerabilities that should be addressed promptly (e.g., authentication bypasses, privilege escalation)
  • Medium (M): Moderate security risks that should be addressed in normal development cycles (e.g., weak encryption, input validation issues)
  • Low (L): Minor security concerns with limited impact (e.g., information disclosure, weak recommendations)
  • Info (I): Informational findings for awareness with minimal security risk (e.g., code quality suggestions, best practice recommendations)

Other Columns:

  • Time: Duration taken by each scanner to complete its analysis
  • Action: Total number of actionable findings at or above the configured severity threshold that require attention

Scanner Results:

  • PASSED: Scanner found no security issues at or above the configured severity threshold - code is clean for this scanner
  • FAILED: Scanner found security vulnerabilities at or above the threshold that require attention and remediation
  • MISSING: Scanner could not run because required dependencies/tools are not installed or available
  • SKIPPED: Scanner was intentionally disabled or excluded from this scan
  • ERROR: Scanner encountered an execution error and could not complete successfully

Severity Thresholds (Thresh Column):

  • CRITICAL: Only Critical severity findings cause scanner to fail
  • HIGH: High and Critical severity findings cause scanner to fail
  • MEDIUM (MED): Medium, High, and Critical severity findings cause scanner to fail
  • LOW: Low, Medium, High, and Critical severity findings cause scanner to fail
  • ALL: Any finding of any severity level causes scanner to fail

Threshold Source: Values in parentheses indicate where the threshold is configured:

  • (g) = global: Set in the global_settings section of ASH configuration
  • (c) = config: Set in the individual scanner configuration section
  • (s) = scanner: Default threshold built into the scanner itself

Statistics calculation:

  • All statistics are calculated from the final aggregated SARIF report
  • Suppressed findings are counted separately and do not contribute to actionable findings
  • Scanner status is determined by comparing actionable findings to the threshold
Scanner S C H M L I Time Action Result Thresh
bandit 0 1 0 0 1 0 856ms 1 FAILED MED (g)
cdk-nag 0 0 0 0 0 0 28.4s 0 PASSED MED (g)
cfn-nag 0 0 0 0 0 0 8ms 0 PASSED MED (g)
checkov 0 0 0 0 0 0 5.2s 0 PASSED MED (g)
detect-secrets 0 1 0 0 0 0 821ms 1 FAILED MED (g)
grype 0 0 0 2 0 0 34.8s 2 FAILED MED (g)
npm-audit 0 0 0 0 0 0 877ms 0 PASSED MED (g)
opengrep 0 0 0 0 0 0 <1ms 0 SKIPPED MED (g)
semgrep 0 0 0 0 0 0 <1ms 0 MISSING MED (g)
syft 0 0 0 0 0 0 2.5s 0 PASSED MED (g)

Detailed Findings

Show 4 actionable findings

Finding 1: B310

  • Severity: HIGH
  • Scanner: bandit
  • Rule ID: B310
  • Location: 02-use-cases/lakehouse-agent/deployment/advanced-agentcore-policy-gateway-interceptor/lambda/interceptor-request/lambda_function.py:129-131

Description:
Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected.

Code Snippet:

with urllib.request.urlopen(jwks_url) as response:
            _jwks = json.loads(response.read())

Finding 2: SECRET-SECRET-KEYWORD

  • Severity: HIGH
  • Scanner: detect-secrets
  • Rule ID: SECRET-SECRET-KEYWORD
  • Location: 02-use-cases/lakehouse-agent/deployment/advanced-agentcore-policy-gateway-interceptor/verification/verify_policy.py:30

Description:
Secret of type 'Secret Keyword' detected in file '02-use-cases/lakehouse-agent/deployment/advanced-agentcore-policy-gateway-interceptor/verification/verify_policy.py' at line 30

Code Snippet:

Secret of type Secret Keyword detected

Finding 3: GHSA-48c2-rrv3-qjmp-yaml

  • Severity: MEDIUM
  • Scanner: grype
  • Rule ID: GHSA-48c2-rrv3-qjmp-yaml
  • Location: 02-use-cases/lakehouse-agent/deployment/advanced-agentcore-policy-gateway-interceptor/package-lock.json:1

Description:
A medium vulnerability in npm package: yaml, version 1.10.2 was found at: /02-use-cases/lakehouse-agent/deployment/advanced-agentcore-policy-gateway-interceptor/package-lock.json


Finding 4: GHSA-f886-m6hf-6m8v-brace-expansion

  • Severity: MEDIUM
  • Scanner: grype
  • Rule ID: GHSA-f886-m6hf-6m8v-brace-expansion
  • Location: 02-use-cases/lakehouse-agent/deployment/advanced-agentcore-policy-gateway-interceptor/package-lock.json:1

Description:
A medium vulnerability in npm package: brace-expansion, version 5.0.3 was found at: /02-use-cases/lakehouse-agent/deployment/advanced-agentcore-policy-gateway-interceptor/package-lock.json


Report generated by Automated Security Helper (ASH) at 2026-04-22T15:50:06+00:00

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

02-use-cases 02-use-cases

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants