Part 6: AWS Infrastructure Setup¶
Resource Overview¶
Before deploying the agent, three AWS resources need to be created:
| Resource | Name | Purpose |
|---|---|---|
| Secrets Manager secret | recipe-agent/prisma-airs-api-key |
Stores the Prisma AIRS API key |
| IAM execution role | BedrockAgentCoreRecipeAgent |
Permissions for the running container |
| ECR repository | recipe-extraction-agent |
Docker image registry |
The deploy script (scripts/deploy.sh) creates the IAM role and ECR repo automatically. The Secrets Manager secret is created separately with scripts/setup-secrets.sh.
1. Secrets Manager¶
The AIRS API key needs to be stored securely — not baked into the Docker image or passed as a plain environment variable.
scripts/setup-secrets.sh¶
#!/usr/bin/env bash
set -euo pipefail
REGION="${AWS_REGION:-us-west-2}"
SECRET_NAME="recipe-agent/prisma-airs-api-key"
if [[ -z "${PANW_AI_SEC_API_KEY:-}" ]]; then
echo "ERROR: PANW_AI_SEC_API_KEY env var required" >&2
exit 1
fi
echo "==> Creating secret: ${SECRET_NAME}"
if aws secretsmanager describe-secret \
--secret-id "${SECRET_NAME}" --region "${REGION}" &>/dev/null; then
echo " Secret already exists. Updating value..."
aws secretsmanager put-secret-value \
--secret-id "${SECRET_NAME}" \
--secret-string "${PANW_AI_SEC_API_KEY}" \
--region "${REGION}"
echo " Updated."
else
aws secretsmanager create-secret \
--name "${SECRET_NAME}" \
--secret-string "${PANW_AI_SEC_API_KEY}" \
--description "Prisma AIRS API key for recipe-extraction-agent" \
--region "${REGION}"
echo " Created."
fi
Usage:
The script is idempotent — if the secret already exists, it updates the value.
At runtime, src/main.ts fetches this secret during bootstrap:
const secret = await sm.send(
new GetSecretValueCommand({ SecretId: "recipe-agent/prisma-airs-api-key" }),
);
Note: If you're not using Prisma AIRS, you can skip this step entirely. The agent works without it.
2. IAM Execution Role¶
The AgentCore runtime assumes an IAM role to access AWS services. The deploy script creates BedrockAgentCoreRecipeAgent with four policies:
Trust Policy¶
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "bedrock-agentcore.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}
This allows the AgentCore service to assume the role on behalf of your container.
Policy 1: ECR Read (AWS Managed)¶
Allows AgentCore to pull the Docker image from ECR.
Policy 2: Bedrock Invoke Model¶
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": [
"arn:aws:bedrock:*::foundation-model/*",
"arn:aws:bedrock:*:ACCOUNT_ID:inference-profile/*"
]
}]
}
Grants access to invoke Bedrock models. Two resource ARNs are needed:
- foundation-model/* — direct model access
- inference-profile/* — cross-region inference profiles (the us. prefix in the model ID)
Policy 3: Secrets Manager Read¶
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": "arn:aws:secretsmanager:us-west-2:ACCOUNT_ID:secret:recipe-agent/*"
}]
}
Allows reading the AIRS API key secret. Scoped to the recipe-agent/ prefix.
Policy 4: CloudWatch Logs¶
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-west-2:ACCOUNT_ID:log-group:/aws/bedrock/agentcore/recipe-extraction-agent:*"
}]
}
Allows the CloudWatch stream (from Part 4) to create log streams and write events.
Creation in the deploy script¶
The IAM role section in scripts/deploy.sh:
ROLE_NAME="BedrockAgentCoreRecipeAgent"
TRUST_POLICY='{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "bedrock-agentcore.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
if ! aws iam get-role --role-name "${ROLE_NAME}" &>/dev/null; then
aws iam create-role \
--role-name "${ROLE_NAME}" \
--assume-role-policy-document "${TRUST_POLICY}" \
--description "Execution role for recipe-extraction-agent on AgentCore"
aws iam attach-role-policy \
--role-name "${ROLE_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
aws iam put-role-policy --role-name "${ROLE_NAME}" \
--policy-name BedrockInvokeModel --policy-document '...'
aws iam put-role-policy --role-name "${ROLE_NAME}" \
--policy-name SecretsManagerRead --policy-document '...'
aws iam put-role-policy --role-name "${ROLE_NAME}" \
--policy-name CloudWatchLogs --policy-document '...'
echo "Created role. Waiting for propagation..."
sleep 10
else
echo "Role already exists."
fi
The sleep 10 after creation gives IAM time to propagate globally — without it, the create-agent-runtime call may fail with "role not found."
3. ECR Repository¶
REPO="recipe-extraction-agent"
if ! aws ecr describe-repositories \
--repository-names "${REPO}" --region "${REGION}" &>/dev/null; then
aws ecr create-repository --repository-name "${REPO}" --region "${REGION}"
echo "Created ECR repository."
else
echo "ECR repository already exists."
fi
Idempotent — skips if the repo already exists.
Environment Variable Reference¶
Complete list of environment variables used across the project:
| Variable | Where Set | Required | Description |
|---|---|---|---|
AWS_REGION |
.env / runtime env |
No (defaults to us-west-2) |
AWS region for all service calls |
AWS_ACCOUNT_ID |
.env / runtime env |
No | Used for agent ARN in AIRS metadata |
PANW_AI_SEC_API_KEY |
Secrets Manager | No | AIRS API key (fetched at bootstrap, used by @cdot65/prisma-airs-sdk) |
PRISMA_AIRS_PROFILE_NAME |
Runtime env var | No | AIRS security profile name |
BEDROCK_AGENT_ID |
Runtime env var | No | AgentCore runtime ID (enables CloudWatch + AIRS metadata) |
BEDROCK_AGENT_VERSION |
Runtime env var | No | Agent version (defaults to "1") |
AGENTCORE_RUNTIME_ID |
.env / CI secret |
For --update |
Runtime ID for update deploys |