#!/bin/bash # Prerequisites setup script for AgentCore deployment # This script ensures all necessary AWS resources and configurations are in place set -e # Exit on any error echo "๐Ÿ”ง AgentCore Prerequisites Setup" echo "================================" echo "" echo -e "${YELLOW}โš ๏ธ Platform Notice: This script has been tested on macOS only${NC}" echo -e "${BLUE} For other platforms, manual installation may be required${NC}" echo "" # Color codes for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Get script directory and project paths SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")" # Go up two levels to reach AgentCore root CONFIG_DIR="${PROJECT_DIR}/config" # Load configuration if [[ ! -f "${CONFIG_DIR}/static-config.yaml" ]]; then echo -e "${RED}โŒ Config file not found: ${CONFIG_DIR}/static-config.yaml${NC}" exit 1 fi # Extract values from YAML (fallback method if yq not available) get_yaml_value() { local key="$1" local file="$2" # Handle nested YAML keys with proper indentation grep " $key:" "$file" | head -1 | sed 's/.*: *["'\'']*\([^"'\'']*\)["'\'']*$/\1/' | xargs } REGION=$(get_yaml_value "region" "${CONFIG_DIR}/static-config.yaml") ACCOUNT_ID=$(get_yaml_value "account_id" "${CONFIG_DIR}/static-config.yaml") ROLE_NAME="bac-execution-role" ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/${ROLE_NAME}" echo -e "${BLUE}๐Ÿ“ Configuration:${NC}" echo " Region: $REGION" echo " Account ID: $ACCOUNT_ID" echo " Role ARN: $ROLE_ARN" echo "" # Function to check if command exists check_command() { if ! command -v "$1" &> /dev/null; then echo -e "${RED}โŒ $1 is not installed${NC}" return 1 else echo -e "${GREEN}โœ… $1 is available${NC}" return 0 fi } # Function to setup Python virtual environment and dependencies setup_python_environment() { echo -e "${BLUE}๐Ÿ Setting up Python virtual environment...${NC}" # Check if we're already in the AgentCore directory if [[ ! -f "${PROJECT_DIR}/requirements.txt" ]]; then echo -e "${RED}โŒ requirements.txt not found in ${PROJECT_DIR}${NC}" return 1 fi # Create virtual environment if it doesn't exist if [[ ! -d "${PROJECT_DIR}/.venv" ]]; then echo " ๐Ÿ“ฆ Creating virtual environment..." if python3 -m venv "${PROJECT_DIR}/.venv"; then echo -e "${GREEN}โœ… Virtual environment created${NC}" else echo -e "${RED}โŒ Failed to create virtual environment${NC}" return 1 fi else echo -e "${GREEN}โœ… Virtual environment already exists${NC}" fi # Activate virtual environment and install dependencies echo " ๐Ÿ“ฆ Installing Python dependencies..." cd "${PROJECT_DIR}" source .venv/bin/activate # Upgrade pip first pip install --upgrade pip > /dev/null 2>&1 # Install requirements with better error handling echo " ๐Ÿ“ฆ Installing Python dependencies..." # First, try to install bedrock-agentcore specifically echo " ๐Ÿ”ง Installing bedrock-agentcore SDK..." if pip install bedrock-agentcore>=0.1.1 --quiet; then echo -e "${GREEN} โœ… bedrock-agentcore SDK installed${NC}" else echo -e "${RED} โŒ Failed to install bedrock-agentcore SDK${NC}" echo -e "${BLUE} This package is required for OAuth provider creation${NC}" return 1 fi # Install all other requirements if pip install -r "${PROJECT_DIR}/requirements.txt" --quiet; then echo -e "${GREEN}โœ… Python dependencies installed${NC}" else echo -e "${YELLOW}โš ๏ธ Some Python dependencies may have failed to install${NC}" echo -e "${BLUE} This is expected for packages like 'strands' that require compilation${NC}" echo -e "${BLUE} Checking critical dependencies...${NC}" # Test if critical packages are available if python -c "import bedrock_agentcore" 2>/dev/null; then echo -e "${GREEN} โœ… bedrock-agentcore is available${NC}" else echo -e "${RED} โŒ bedrock-agentcore is not available${NC}" return 1 fi fi # Install/upgrade AWS CLI in the virtual environment echo " ๐Ÿ”ง Installing latest AWS CLI in virtual environment..." if pip install --upgrade awscli > /dev/null 2>&1; then echo -e "${GREEN}โœ… Latest AWS CLI installed in virtual environment${NC}" else echo -e "${YELLOW}โš ๏ธ Failed to install AWS CLI in virtual environment${NC}" echo -e "${BLUE} Will use system AWS CLI${NC}" fi return 0 } # Function to check AWS credentials check_aws_credentials() { echo -e "${BLUE}๐Ÿ” Checking AWS credentials...${NC}" if ! aws sts get-caller-identity &> /dev/null; then echo -e "${RED}โŒ AWS credentials not configured or invalid${NC}" echo " Please configure AWS credentials using:" echo " - aws configure" echo " - aws sso login (if using SSO)" echo " - Set AWS_PROFILE environment variable" return 1 fi local caller_identity=$(aws sts get-caller-identity 2>/dev/null) local current_account=$(echo "$caller_identity" | grep -o '"Account": "[^"]*"' | cut -d'"' -f4) if [[ "$current_account" != "$ACCOUNT_ID" ]]; then echo -e "${YELLOW}โš ๏ธ Warning: Current AWS account ($current_account) doesn't match config ($ACCOUNT_ID)${NC}" read -p "Continue anyway? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then return 1 fi fi echo -e "${GREEN}โœ… AWS credentials valid for account: $current_account${NC}" return 0 } # Function to update existing role policies update_existing_role_policies() { # Load permission policy from file and substitute account ID local permission_policy_file="${SCRIPT_DIR}/bac-permissions-policy.json" if [[ ! -f "$permission_policy_file" ]]; then echo -e "${RED}โŒ Permission policy file not found: $permission_policy_file${NC}" return 1 fi local permission_policy=$(sed "s/165938467517/$ACCOUNT_ID/g" "$permission_policy_file") # Update permission policy local policy_name="bac-execution-policy" if aws iam put-role-policy \ --role-name "$ROLE_NAME" \ --policy-name "$policy_name" \ --policy-document "$permission_policy" &> /dev/null; then echo -e "${GREEN}โœ… IAM role permissions updated${NC}" else echo -e "${YELLOW}โš ๏ธ Warning: Failed to update permissions policy${NC}" fi } # Function to create IAM role create_iam_role() { echo -e "${BLUE}๐Ÿ”‘ Checking IAM role: $ROLE_NAME${NC}" if aws iam get-role --role-name "$ROLE_NAME" &> /dev/null; then echo -e "${GREEN}โœ… IAM role already exists${NC}" echo " ๐Ÿ“ Updating role policies with current account ID..." update_existing_role_policies return 0 fi echo " ๐Ÿ“ Creating IAM role..." # Load trust policy from file and substitute account ID local trust_policy_file="${SCRIPT_DIR}/bac-trust-policy.json" if [[ ! -f "$trust_policy_file" ]]; then echo -e "${RED}โŒ Trust policy file not found: $trust_policy_file${NC}" return 1 fi local trust_policy=$(sed "s/165938467517/$ACCOUNT_ID/g" "$trust_policy_file") # Create the role if aws iam create-role \ --role-name "$ROLE_NAME" \ --assume-role-policy-document "$trust_policy" \ --description "Execution role for AgentCore runtime" &> /dev/null; then echo -e "${GREEN}โœ… IAM role created successfully${NC}" else echo -e "${RED}โŒ Failed to create IAM role${NC}" return 1 fi # Load permission policy from file and substitute account ID local permission_policy_file="${SCRIPT_DIR}/bac-permissions-policy.json" if [[ ! -f "$permission_policy_file" ]]; then echo -e "${RED}โŒ Permission policy file not found: $permission_policy_file${NC}" return 1 fi local permission_policy=$(sed "s/165938467517/$ACCOUNT_ID/g" "$permission_policy_file") # Attach permission policy local policy_name="bac-execution-policy" if aws iam put-role-policy \ --role-name "$ROLE_NAME" \ --policy-name "$policy_name" \ --policy-document "$permission_policy" &> /dev/null; then echo -e "${GREEN}โœ… IAM role permissions attached${NC}" else echo -e "${YELLOW}โš ๏ธ Warning: Failed to attach permissions policy${NC}" fi return 0 } # Function to check ECR repositories check_ecr_repositories() { echo -e "${BLUE}๐Ÿ“ฆ Checking ECR repositories...${NC}" local repos=("bac-runtime-repo-diy" "bac-runtime-repo-sdk") for repo in "${repos[@]}"; do if aws ecr describe-repositories --repository-names "$repo" --region "$REGION" &> /dev/null; then echo -e "${GREEN}โœ… ECR repository exists: $repo${NC}" else echo " ๐Ÿ“ฆ Creating ECR repository: $repo" if aws ecr create-repository --repository-name "$repo" --region "$REGION" &> /dev/null; then echo -e "${GREEN}โœ… ECR repository created: $repo${NC}" else echo -e "${RED}โŒ Failed to create ECR repository: $repo${NC}" return 1 fi fi done return 0 } # Function to validate config files validate_config() { echo -e "${BLUE}๐Ÿ“‹ Validating configuration files...${NC}" # Check static-config.yaml if [[ ! -f "${CONFIG_DIR}/static-config.yaml" ]]; then echo -e "${RED}โŒ Missing: static-config.yaml${NC}" return 1 fi # Check dynamic-config.yaml exists (create if missing) if [[ ! -f "${CONFIG_DIR}/dynamic-config.yaml" ]]; then echo -e "${YELLOW}โš ๏ธ Creating missing dynamic-config.yaml${NC}" # Create empty dynamic config if it doesn't exist cat > "${CONFIG_DIR}/dynamic-config.yaml" << 'EOF' # Dynamic Configuration - Updated by deployment scripts only # This file contains all configuration values that are generated/updated during deployment gateway: id: "" arn: "" url: "" oauth_provider: provider_name: "" provider_arn: "" domain: "" scopes: [] mcp_lambda: function_name: "" function_arn: "" role_arn: "" stack_name: "" gateway_execution_role_arn: "" runtime: diy_agent: arn: "" ecr_uri: "" endpoint_arn: "" sdk_agent: arn: "" ecr_uri: "" endpoint_arn: "" client: diy_runtime_endpoint: "" sdk_runtime_endpoint: "" EOF fi # Validate required fields in static config local required_fields=("region" "account_id") for field in "${required_fields[@]}"; do if ! grep -q "$field:" "${CONFIG_DIR}/static-config.yaml"; then echo -e "${RED}โŒ Missing required field in static config: $field${NC}" return 1 fi done echo -e "${GREEN}โœ… Configuration files valid${NC}" return 0 } # Function to test AgentCore Identity permissions test_agentcore_identity_permissions() { echo -e "${BLUE}๐Ÿงช Testing AgentCore Identity permissions...${NC}" # Check if we can list existing resources (basic permission test) if aws bedrock-agentcore-control list-workload-identities --region "$REGION" &> /dev/null; then echo -e "${GREEN}โœ… AgentCore Identity list permissions working${NC}" # Check if we have the critical GetResourceOauth2Token permission # We can't directly test this without creating resources, so we'll note it echo -e "${BLUE}โ„น๏ธ Note: GetResourceOauth2Token permission added for Okta integration${NC}" echo -e "${BLUE} This enables OAuth2 token retrieval from external providers like Okta${NC}" return 0 else echo -e "${YELLOW}โš ๏ธ AgentCore Identity permissions may need time to propagate${NC}" echo -e "${BLUE} If you encounter AccessDeniedException errors:${NC}" echo -e "${BLUE} 1. Wait 2-3 minutes for IAM changes to take effect${NC}" echo -e "${BLUE} 2. Re-run this script to verify permissions${NC}" return 1 fi } # Function to show Okta integration status show_okta_integration_status() { echo -e "${BLUE}๐Ÿ”— Okta Integration Status${NC}" echo -e "${BLUE}=========================${NC}" if grep -q "okta:" "${CONFIG_DIR}/static-config.yaml"; then echo -e "${GREEN}โœ… Okta configuration present in static-config.yaml${NC}" echo -e "${BLUE}๐Ÿ“‹ Okta Integration Requirements:${NC}" echo -e "${BLUE} 1. โœ… AgentCore Identity permissions (included in this setup)${NC}" echo -e "${BLUE} 2. โš™๏ธ Okta application with 'Client Credentials' grant enabled${NC}" echo -e "${BLUE} 3. ๐ŸŽฏ Custom 'api' scope created in Okta authorization server${NC}" echo -e "${BLUE} 4. ๐Ÿ”‘ Valid client ID and secret in static-config.yaml${NC}" else echo -e "${YELLOW}โš ๏ธ Okta configuration not found${NC}" echo -e "${BLUE} Add okta section to ${CONFIG_DIR}/static-config.yaml with your Okta credentials${NC}" fi } # Main execution main() { echo -e "${BLUE}๐Ÿ” Checking dependencies...${NC}" local deps_ok=true check_command "aws" || deps_ok=false check_command "docker" || deps_ok=false check_command "python3" || deps_ok=false # Check for bedrock-agentcore-control CLI (critical for OAuth provider setup) if aws bedrock-agentcore-control help &> /dev/null; then echo -e "${GREEN}โœ… aws bedrock-agentcore-control is available${NC}" else echo -e "${RED}โŒ aws bedrock-agentcore-control is not available${NC}" echo -e "${BLUE} This CLI is required for OAuth provider creation${NC}" echo -e "${BLUE} Please ensure you have the latest AWS CLI version${NC}" echo -e "${BLUE} Run: aws --version (should be 2.15.0 or later)${NC}" deps_ok=false fi if command -v yq &> /dev/null; then echo -e "${GREEN}โœ… yq is available (recommended)${NC}" else echo -e "${YELLOW}โš ๏ธ yq not found (will use fallback parsing)${NC}" fi if [[ "$deps_ok" != true ]]; then echo -e "${RED}โŒ Missing required dependencies${NC}" exit 1 fi echo "" # Setup Python environment setup_python_environment || exit 1 echo "" # Run checks validate_config || exit 1 check_aws_credentials || exit 1 create_iam_role || exit 1 check_ecr_repositories || exit 1 echo "" # Test AgentCore Identity permissions test_agentcore_identity_permissions echo "" # Show Okta integration status show_okta_integration_status echo "" echo -e "${GREEN}๐ŸŽ‰ Prerequisites setup complete!${NC}" echo "" echo -e "${BLUE}๐Ÿ“‹ Next steps:${NC}" echo " 1. Deploy DIY agent: ./deploy-diy.sh" echo " 2. Deploy SDK agent: ./deploy-sdk.sh" echo " 3. Create runtimes: python3 deploy-diy-runtime.py" echo " 4. Create runtimes: python3 deploy-sdk-runtime.py" echo "" echo -e "${BLUE}๐Ÿ”— For Okta integration:${NC}" echo " 5. Test Okta integration: cd src/auth && python okta_working_final.py" echo " 6. Verify AgentCore Identity + Okta OAuth2 token retrieval" } # Run main function main "$@"