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
195 changes: 150 additions & 45 deletions apps/java-spring-ai-agents/scripts/13-mcp-policy.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash
# Deploy Cedar policy to MCP Gateway
# Requires AWS CLI 2.32+
# Deploy Cedar policies to MCP Gateway
# Creates: Policy Engine, Permit all, Forbid cancelTrip, IAM permissions, Gateway attachment
set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
Expand All @@ -10,77 +10,182 @@ if [ -f "$SCRIPT_DIR/.env" ]; then
source "$SCRIPT_DIR/.env"
fi

# Set defaults if not in .env
AWS_REGION=${AWS_REGION:-$(aws configure get region)}
ACCOUNT_ID=${ACCOUNT_ID:-$(aws sts get-caller-identity --query Account --output text)}

# Get gateway ID if not set
if [ -z "$MCP_GATEWAY_ID" ]; then
MCP_GATEWAY_ID=$(aws bedrock-agentcore-control list-gateways --query 'items[0].gatewayId' --output text)
fi

GATEWAY_ARN="arn:aws:bedrock-agentcore:${AWS_REGION}:${ACCOUNT_ID}:gateway/${MCP_GATEWAY_ID}"
POLICY_FILE="${SCRIPT_DIR}/backoffice-policy.cedar"

echo "Deploying Cedar policy..."
echo "Deploying Cedar policies..."
echo " Region: ${AWS_REGION}"
echo " Gateway: ${MCP_GATEWAY_ID}"
echo " Policy Engine: ${MCP_POLICY_ENGINE_ID}"
echo ""

# Read and substitute policy
POLICY_STATEMENT=$(sed "s|\${GATEWAY_ARN}|${GATEWAY_ARN}|g" "$POLICY_FILE")
# Step 1: Create or get Policy Engine
echo "1. Setting up Policy Engine..."
POLICY_ENGINE_ID=$(aws bedrock-agentcore-control list-policy-engines \
--query 'policyEngines[?name==`BackofficePolicyEngine`].policyEngineId' --output text 2>/dev/null || true)

# Delete existing policies and wait for deletion
echo "1. Cleaning up existing policies..."
if [ -z "$POLICY_ENGINE_ID" ]; then
echo " Creating new Policy Engine..."
POLICY_ENGINE_ID=$(aws bedrock-agentcore-control create-policy-engine \
--name "BackofficePolicyEngine" \
--query "policyEngineId" --output text)

echo -n " Waiting for ACTIVE"
while [ "$(aws bedrock-agentcore-control get-policy-engine --policy-engine-id "${POLICY_ENGINE_ID}" \
--query 'status' --output text)" != "ACTIVE" ]; do
echo -n "."; sleep 3
done
echo " Done"
else
echo " Using existing Policy Engine: ${POLICY_ENGINE_ID}"
fi

POLICY_ENGINE_ARN="arn:aws:bedrock-agentcore:${AWS_REGION}:${ACCOUNT_ID}:policy-engine/${POLICY_ENGINE_ID}"

# Step 2: Delete existing policies
echo ""
echo "2. Cleaning up existing policies..."
EXISTING=$(aws bedrock-agentcore-control list-policies \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--policy-engine-id "${POLICY_ENGINE_ID}" \
--query 'policies[].policyId' --output text 2>/dev/null || true)

for PID in $EXISTING; do
echo " Deleting: $PID"
aws bedrock-agentcore-control delete-policy \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--policy-engine-id "${POLICY_ENGINE_ID}" \
--policy-id "$PID" > /dev/null

# Wait for deletion to complete
while true; do
STATUS=$(aws bedrock-agentcore-control get-policy \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--policy-engine-id "${POLICY_ENGINE_ID}" \
--policy-id "$PID" \
--query 'status' --output text 2>/dev/null || echo "DELETED")
[ "$STATUS" = "DELETED" ] || [ -z "$STATUS" ] && break
sleep 2
done
done
echo " Done"

# Step 3: Create permit policy (Cedar is deny-by-default)
echo ""
echo "3. Creating permit policy..."
PERMIT_STATEMENT="permit (principal, action, resource == AgentCore::Gateway::\"${GATEWAY_ARN}\");"

PERMIT_ID=$(aws bedrock-agentcore-control create-policy \
--policy-engine-id "${POLICY_ENGINE_ID}" \
--name "PermitAllActions" \
--validation-mode "IGNORE_ALL_FINDINGS" \
--definition "{\"cedar\":{\"statement\":$(echo "$PERMIT_STATEMENT" | jq -Rs .)}}" \
--query 'policyId' --output text)

echo " Policy ID: $PERMIT_ID"

# Step 4: Create forbid policy
echo ""
echo "4. Creating forbid policy..."
FORBID_STATEMENT="forbid (principal, action == AgentCore::Action::\"backoffice___cancelTrip\", resource == AgentCore::Gateway::\"${GATEWAY_ARN}\");"

FORBID_ID=$(aws bedrock-agentcore-control create-policy \
--policy-engine-id "${POLICY_ENGINE_ID}" \
--name "ForbidCancelTrip" \
--validation-mode "IGNORE_ALL_FINDINGS" \
--definition "{\"cedar\":{\"statement\":$(echo "$FORBID_STATEMENT" | jq -Rs .)}}" \
--query 'policyId' --output text)

echo " Policy ID: $FORBID_ID"

# Step 5: Wait for policies to become ACTIVE
echo ""
echo "5. Waiting for policies to become ACTIVE..."
for PID in "$PERMIT_ID" "$FORBID_ID"; do
for i in {1..30}; do
STATUS=$(aws bedrock-agentcore-control get-policy \
--policy-engine-id "${POLICY_ENGINE_ID}" \
--policy-id "$PID" \
--query 'status' --output text)

if [ "$STATUS" = "DELETED" ] || [ -z "$STATUS" ]; then
if [ "$STATUS" = "ACTIVE" ]; then
echo " $PID: ACTIVE"
break
elif [[ "$STATUS" == *"FAILED"* ]]; then
echo "❌ Policy $PID failed"
exit 1
fi
sleep 2
done
done

# Create new policy
# Step 6: Add IAM permissions for gateway role
echo ""
echo "2. Creating policy..."
POLICY_ID=$(aws bedrock-agentcore-control create-policy \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--name "ForbidDangerousOperations" \
--validation-mode "IGNORE_ALL_FINDINGS" \
--definition "{\"cedar\":{\"statement\":$(echo "$POLICY_STATEMENT" | jq -Rs .)}}" \
--query 'policyId' --output text)
echo "6. Adding IAM permissions..."
cat > /tmp/policy-permissions.json << EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "bedrock-agentcore:*",
"Resource": [
"${GATEWAY_ARN}",
"${POLICY_ENGINE_ARN}",
"${POLICY_ENGINE_ARN}/*"
]
}]
}
EOF

aws iam put-role-policy \
--role-name mcp-gateway-role \
--policy-name PolicyEngineAccess \
--policy-document file:///tmp/policy-permissions.json

echo " Policy ID: $POLICY_ID"
echo " Waiting for IAM propagation..."
sleep 10

# Wait for ACTIVE
# Step 7: Attach policy engine to gateway
echo ""
echo "3. Waiting for policy to become ACTIVE..."
for i in {1..30}; do
STATUS=$(aws bedrock-agentcore-control get-policy \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--policy-id "$POLICY_ID" \
--query 'status' --output text)

echo " Status: $STATUS"

if [ "$STATUS" = "ACTIVE" ]; then
echo ""
echo "✅ Policy deployed successfully!"
exit 0
elif [[ "$STATUS" == *"FAILED"* ]]; then
echo ""
echo "❌ Policy deployment failed"
exit 1
fi
sleep 2
echo "7. Attaching policy engine to gateway..."
MCP_GATEWAY_ROLE_ARN=$(aws bedrock-agentcore-control get-gateway \
--gateway-id "${MCP_GATEWAY_ID}" --query 'roleArn' --output text)

aws bedrock-agentcore-control update-gateway \
--gateway-identifier "${MCP_GATEWAY_ID}" \
--name "mcp-gateway" \
--role-arn "${MCP_GATEWAY_ROLE_ARN}" \
--protocol-type "MCP" \
--authorizer-type "AWS_IAM" \
--policy-engine-configuration "{\"arn\":\"${POLICY_ENGINE_ARN}\",\"mode\":\"ENFORCE\"}" \
--no-cli-pager > /dev/null

echo -n " Waiting for gateway READY"
while [ "$(aws bedrock-agentcore-control get-gateway --gateway-id "${MCP_GATEWAY_ID}" \
--query 'status' --output text)" != "READY" ]; do
echo -n "."; sleep 3
done
echo " Done"

# Save to .env for cleanup script
if ! grep -q "MCP_POLICY_ENGINE_ID" "$SCRIPT_DIR/.env" 2>/dev/null; then
echo "" >> "$SCRIPT_DIR/.env"
echo "# Policy Engine" >> "$SCRIPT_DIR/.env"
echo "MCP_POLICY_ENGINE_ID=${POLICY_ENGINE_ID}" >> "$SCRIPT_DIR/.env"
fi

echo "❌ Timeout waiting for policy"
exit 1
echo ""
echo "✅ Policies deployed successfully!"
echo ""
echo "Policies:"
aws bedrock-agentcore-control list-policies \
--policy-engine-id "${POLICY_ENGINE_ID}" \
--query 'policies[].{Name:name,Status:status}' --output table

echo ""
echo "Gateway:"
aws bedrock-agentcore-control get-gateway --gateway-id "${MCP_GATEWAY_ID}" \
--query '{PolicyEngine:policyEngineConfiguration.arn,Mode:policyEngineConfiguration.mode}' --output table
98 changes: 72 additions & 26 deletions apps/java-spring-ai-agents/scripts/14-mcp-policy-cleanup.sh
Original file line number Diff line number Diff line change
@@ -1,46 +1,92 @@
#!/bin/bash
# Cleanup Cedar policies from MCP Gateway
# Remove Cedar policies from MCP Gateway
set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Load environment
if [ -f "$SCRIPT_DIR/.env" ]; then
source "$SCRIPT_DIR/.env"
fi

echo "Cleaning up policies from engine: ${MCP_POLICY_ENGINE_ID}"
echo ""
# Set defaults if not in .env
AWS_REGION=${AWS_REGION:-$(aws configure get region)}
ACCOUNT_ID=${ACCOUNT_ID:-$(aws sts get-caller-identity --query Account --output text)}

POLICIES=$(aws bedrock-agentcore-control list-policies \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--query 'policies[].policyId' --output text 2>/dev/null || true)
# Get gateway ID if not set
if [ -z "$MCP_GATEWAY_ID" ]; then
MCP_GATEWAY_ID=$(aws bedrock-agentcore-control list-gateways --query 'items[0].gatewayId' --output text)
fi

if [ -z "$POLICIES" ]; then
echo "No policies found."
# Get policy engine ID if not set
if [ -z "$MCP_POLICY_ENGINE_ID" ]; then
MCP_POLICY_ENGINE_ID=$(aws bedrock-agentcore-control list-policy-engines \
--query 'policyEngines[?name==`BackofficePolicyEngine`].policyEngineId' --output text 2>/dev/null || true)
fi

if [ -z "$MCP_POLICY_ENGINE_ID" ]; then
echo "No policy engine found."
exit 0
fi

for PID in $POLICIES; do
echo "Deleting: $PID"
aws bedrock-agentcore-control delete-policy \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--policy-id "$PID" > /dev/null
echo "Removing Cedar policies..."
echo " Gateway: ${MCP_GATEWAY_ID}"
echo " Policy Engine: ${MCP_POLICY_ENGINE_ID}"
echo ""

# Step 1: Detach policy engine from gateway
echo "1. Detaching policy engine from gateway..."
CURRENT_POLICY=$(aws bedrock-agentcore-control get-gateway --gateway-id "${MCP_GATEWAY_ID}" \
--query 'policyEngineConfiguration.arn' --output text 2>/dev/null || echo "None")

if [ "$CURRENT_POLICY" != "None" ] && [ -n "$CURRENT_POLICY" ]; then
MCP_GATEWAY_ROLE_ARN=$(aws bedrock-agentcore-control get-gateway \
--gateway-id "${MCP_GATEWAY_ID}" --query 'roleArn' --output text)

echo " Waiting for deletion..."
while true; do
STATUS=$(aws bedrock-agentcore-control get-policy \
aws bedrock-agentcore-control update-gateway \
--gateway-identifier "${MCP_GATEWAY_ID}" \
--name "mcp-gateway" \
--role-arn "${MCP_GATEWAY_ROLE_ARN}" \
--protocol-type "MCP" \
--authorizer-type "AWS_IAM" \
--no-cli-pager > /dev/null

echo -n " Waiting for gateway READY"
while [ "$(aws bedrock-agentcore-control get-gateway --gateway-id "${MCP_GATEWAY_ID}" \
--query 'status' --output text)" != "READY" ]; do
echo -n "."; sleep 3
done
echo " Done"
else
echo " No policy engine attached to gateway"
fi

# Step 2: Delete all policies
echo ""
echo "2. Deleting policies..."
EXISTING=$(aws bedrock-agentcore-control list-policies \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--query 'policies[].policyId' --output text 2>/dev/null || true)

if [ -z "$EXISTING" ]; then
echo " No policies to delete."
else
for PID in $EXISTING; do
echo " Deleting: $PID"
aws bedrock-agentcore-control delete-policy \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--policy-id "$PID" \
--query 'status' --output text 2>/dev/null || echo "DELETED")
--policy-id "$PID" > /dev/null

if [ "$STATUS" = "DELETED" ] || [ -z "$STATUS" ]; then
echo " ✅ Deleted"
break
fi
echo " Status: $STATUS"
sleep 2
while true; do
STATUS=$(aws bedrock-agentcore-control get-policy \
--policy-engine-id "${MCP_POLICY_ENGINE_ID}" \
--policy-id "$PID" \
--query 'status' --output text 2>/dev/null || echo "DELETED")
[ "$STATUS" = "DELETED" ] || [ -z "$STATUS" ] && break
sleep 2
done
done
done
fi

echo ""
echo "✅ All policies cleaned up!"
echo "✅ Policies removed. Gateway restored to full tool access."
10 changes: 9 additions & 1 deletion apps/java-spring-ai-agents/scripts/backoffice-policy.cedar
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
// Backoffice MCP Gateway Policy
// Forbid dangerous operations - everything else allowed by default
// Cedar is deny-by-default, so we need permit-all first, then forbid specific actions

// Permit all actions on the gateway (required - Cedar denies by default)
permit(
principal,
action,
resource == AgentCore::Gateway::"${GATEWAY_ARN}"
);

// Forbid dangerous operations (takes precedence over permit)
forbid(
principal,
action in [
Expand Down
Loading