Implement reversible PII de-identification round trip (T1–T7)
Build the AWS side of the HNCB demo end to end (region ap-southeast-1): - T1 /tokenize + T2 /restore: Lambdas behind a public API Gateway (shared-secret auth), Presidio detection, random per-request tokens, DynamoDB vault; overlap resolution so a ROC ID stays TW_ROC_ID. - T3: Presidio made private (SG-locked to the tokenize Lambda in-VPC; DynamoDB gateway endpoint); only /tokenize + /restore are public. - T4: RAG Lambda registered as an MCP tool on an AgentCore Gateway (AWS_IAM/SigV4); agentcore_setup.sh + a SigV4 MCP invoke test. - T5: Strands agent deployed to AgentCore Runtime; SigV4 gateway auth, apac inference profile, pinned deps. - T6: advisor UI on S3+CloudFront with a Fusion-less demo orchestrator (/demo) chaining tokenize -> runtime -> restore. - T7: README runbook + trace check; teardown deletes gateway/runtime/memory/ECR. Verified live: the cloud AgentCore/Bedrock trace shows only tokens, never the real name. Secrets stay in gitignored local.auto.tfvars. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,41 +1,117 @@
|
||||
#!/usr/bin/env bash
|
||||
# AgentCore setup (steps 3-4-7). Terraform's AgentCore coverage lags, so this
|
||||
# stage uses the AgentCore CLI / SDK. Commands below reflect the current CLI
|
||||
# shape -- CHECK against `agentcore --help`, the surface moves fast.
|
||||
# stage uses the AWS CLI's `bedrock-agentcore-control` API. Verified against the
|
||||
# CLI on 2026-07-01; the surface moves fast, so re-check with
|
||||
# `aws bedrock-agentcore-control help` if a call rejects.
|
||||
#
|
||||
# T4 (implemented below): create an MCP Gateway and register the RAG Lambda as a
|
||||
# tool. Inbound auth is AWS_IAM (SigV4) -- no Cognito needed. The Gateway assumes
|
||||
# the IAM role from Terraform (`terraform output -raw gateway_role_arn`) to invoke
|
||||
# the Lambda.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
: "${REGION:?set REGION}"
|
||||
: "${RAG_LAMBDA_ARN:?set RAG_LAMBDA_ARN (from: terraform output -raw rag_lambda_arn)}"
|
||||
: "${RAG_LAMBDA_ARN:?set RAG_LAMBDA_ARN (from: terraform -chdir=terraform output -raw rag_lambda_arn)}"
|
||||
: "${GATEWAY_ROLE_ARN:?set GATEWAY_ROLE_ARN (from: terraform -chdir=terraform output -raw gateway_role_arn)}"
|
||||
: "${BEDROCK_MODEL_ID:=anthropic.claude-3-5-sonnet-20241022-v2:0}"
|
||||
GW_NAME="${GW_NAME:-hncb-rag-gateway}"
|
||||
TAG='conan hncb demo'
|
||||
export AWS_PAGER=""
|
||||
|
||||
echo "==> 1. Install the AgentCore CLI (recommended tooling)"
|
||||
echo " npm install -g @aws/agentcore # or: pip install bedrock-agentcore-starter-toolkit"
|
||||
echo "==> 1. Create the MCP Gateway (AWS_IAM inbound auth)"
|
||||
GW_JSON="$(aws bedrock-agentcore-control create-gateway \
|
||||
--region "$REGION" \
|
||||
--name "$GW_NAME" \
|
||||
--role-arn "$GATEWAY_ROLE_ARN" \
|
||||
--protocol-type MCP \
|
||||
--authorizer-type AWS_IAM \
|
||||
--tags "Owner=$TAG" 2>/dev/null \
|
||||
|| aws bedrock-agentcore-control list-gateways --region "$REGION" \
|
||||
--query "items[?name=='$GW_NAME']|[0]" --output json)"
|
||||
GW_ID="$(echo "$GW_JSON" | python3 -c 'import sys,json;print(json.load(sys.stdin)["gatewayId"])')"
|
||||
echo " gatewayId=$GW_ID"
|
||||
|
||||
echo "==> 2. Create a Gateway that exposes the RAG Lambda as an MCP tool"
|
||||
echo " AgentCore Gateway turns a Lambda into an MCP tool with no code changes."
|
||||
echo "==> 2. Wait for the Gateway to be READY"
|
||||
for i in $(seq 1 20); do
|
||||
ST="$(aws bedrock-agentcore-control get-gateway --region "$REGION" --gateway-identifier "$GW_ID" --query status --output text)"
|
||||
echo " [$i] status=$ST"
|
||||
[ "$ST" = "READY" ] && break
|
||||
sleep 6
|
||||
done
|
||||
GW_URL="$(aws bedrock-agentcore-control get-gateway --region "$REGION" --gateway-identifier "$GW_ID" --query gatewayUrl --output text)"
|
||||
|
||||
echo "==> 3. Register the RAG Lambda as an MCP tool target"
|
||||
# Build the target config: mcp.lambda with the tool schema from agent/tool_schema.json
|
||||
# (wrapped in the inlinePayload list). The Gateway's inputSchema is a RESTRICTED
|
||||
# JSON-Schema subset (only type/properties/required/items/description), so we strip
|
||||
# anything else (e.g. the "default" on period_days) recursively.
|
||||
python3 - "$RAG_LAMBDA_ARN" > /tmp/hncb_target.json <<'PY'
|
||||
import json, sys, os
|
||||
ALLOWED = {"type", "properties", "required", "items", "description"}
|
||||
def clean(s):
|
||||
if not isinstance(s, dict):
|
||||
return s
|
||||
out = {k: v for k, v in s.items() if k in ALLOWED}
|
||||
if "properties" in out:
|
||||
out["properties"] = {k: clean(v) for k, v in out["properties"].items()}
|
||||
if "items" in out:
|
||||
out["items"] = clean(out["items"])
|
||||
return out
|
||||
lambda_arn = sys.argv[1]
|
||||
schema = json.load(open(os.path.join("..", "agent", "tool_schema.json")))
|
||||
schema["inputSchema"] = clean(schema["inputSchema"])
|
||||
if "outputSchema" in schema:
|
||||
schema["outputSchema"] = clean(schema["outputSchema"])
|
||||
print(json.dumps({
|
||||
"mcp": {"lambda": {"lambdaArn": lambda_arn, "toolSchema": {"inlinePayload": [schema]}}}
|
||||
}))
|
||||
PY
|
||||
if aws bedrock-agentcore-control list-gateway-targets --region "$REGION" \
|
||||
--gateway-identifier "$GW_ID" --query 'items[?name==`rag`]' --output text | grep -q rag; then
|
||||
echo " target 'rag' already exists -- reusing"
|
||||
else
|
||||
aws bedrock-agentcore-control create-gateway-target \
|
||||
--region "$REGION" \
|
||||
--gateway-identifier "$GW_ID" \
|
||||
--name "rag" \
|
||||
--target-configuration file:///tmp/hncb_target.json \
|
||||
--credential-provider-configurations '[{"credentialProviderType":"GATEWAY_IAM_ROLE"}]' \
|
||||
--query '{target:targetId,status:status}' --output json
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Gateway ready. MCP URL:"
|
||||
echo " $GW_URL"
|
||||
echo "Export it for the agent + the invoke test:"
|
||||
echo " export AGENTCORE_GATEWAY_URL=$GW_URL"
|
||||
echo ""
|
||||
echo "Verify T4 (manual invoke returns the evidence package):"
|
||||
echo " REGION=$REGION AGENTCORE_GATEWAY_URL=$GW_URL python3 scripts/gateway_invoke_test.py CUST_000123"
|
||||
|
||||
########################################
|
||||
# T5: deploy the agent to AgentCore Runtime (uses the starter toolkit CLI).
|
||||
# In ap-southeast-1 Claude 3.5 Sonnet v2 is INFERENCE_PROFILE-only -> use the
|
||||
# apac.* profile id, not the raw model id.
|
||||
########################################
|
||||
APAC_MODEL="apac.anthropic.claude-3-5-sonnet-20241022-v2:0"
|
||||
echo ""
|
||||
echo "==> (T5) Deploy the agent to AgentCore Runtime:"
|
||||
cat <<EOF
|
||||
agentcore gateway create \\
|
||||
--name hncb-rag-gateway \\
|
||||
--region ${REGION} \\
|
||||
--target-type lambda \\
|
||||
--target-arn ${RAG_LAMBDA_ARN} \\
|
||||
--tool-name get_customer_activity_summary \\
|
||||
--tool-description "Return a de-identified activity summary for a customer TOKEN" \\
|
||||
--tool-schema file://../agent/tool_schema.json
|
||||
# Note the printed Gateway MCP URL -> export AGENTCORE_GATEWAY_URL=...
|
||||
cd ../agent # requirements.txt is version-pinned
|
||||
pip install bedrock-agentcore-starter-toolkit # provides 'agentcore'
|
||||
agentcore configure -e agent.py -n hncb_advisor_agent -r ${REGION} \\
|
||||
-rf requirements.txt --non-interactive
|
||||
agentcore launch --env AGENTCORE_GATEWAY_URL=${GW_URL} --env BEDROCK_MODEL_ID=${APAC_MODEL}
|
||||
# -> note the printed Runtime ARN (Fusion / the UI will invoke this).
|
||||
|
||||
# REQUIRED post-launch: the auto-created execution role can't call the Gateway
|
||||
# yet. Grant it (role name is printed by launch as AmazonBedrockAgentCoreSDKRuntime-*):
|
||||
ROLE=\$(aws iam list-roles --query "Roles[?starts_with(RoleName,'AmazonBedrockAgentCoreSDKRuntime-${REGION}')].RoleName | [0]" --output text)
|
||||
GW_ARN=\$(aws bedrock-agentcore-control get-gateway --region ${REGION} --gateway-identifier ${GW_ID} --query gatewayArn --output text)
|
||||
aws iam put-role-policy --role-name "\$ROLE" --policy-name hncb-gateway-invoke \\
|
||||
--policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"bedrock-agentcore:InvokeGateway\"],\"Resource\":[\"\$GW_ARN\",\"\$GW_ARN/*\"]}]}"
|
||||
|
||||
# Verify: agentcore invoke '{"prompt":"talking points for CUST_000123"}'
|
||||
EOF
|
||||
|
||||
echo "==> 3. Deploy the agent to AgentCore Runtime"
|
||||
cat <<EOF
|
||||
cd ../agent
|
||||
agentcore configure --entrypoint agent.py --name hncb-advisor-agent --region ${REGION}
|
||||
AGENTCORE_GATEWAY_URL=<from step 2> BEDROCK_MODEL_ID=${BEDROCK_MODEL_ID} \\
|
||||
agentcore launch
|
||||
# Note the printed Runtime ARN -> Fusion will invoke this.
|
||||
EOF
|
||||
|
||||
echo "==> 4. (recommended) Lock the Runtime to accept calls only from the Gateway"
|
||||
echo " Use a resource policy (SigV4) or allowedWorkloadConfiguration (JWT)."
|
||||
echo " See AgentCore 'Runtime targets' docs."
|
||||
|
||||
echo "Done printing steps. Fill AGENTCORE_GATEWAY_URL + Runtime ARN into fusion/POLICY_SETUP.md."
|
||||
echo "Fill AGENTCORE_GATEWAY_URL + Runtime ARN into fusion/POLICY_SETUP.md."
|
||||
|
||||
Reference in New Issue
Block a user