This directory contains Terraform configuration for deploying the AVA Control Plane infrastructure on AWS.
The infrastructure includes:
- API Gateway: HTTP API with VPC Link for private integration
- ECS Fargate: Containerized backend service with auto-scaling
- DynamoDB: Application Catalog and Deployment Metadata tables
- S3: Project archives (Quick Deploy source) and frontend static hosting
- Step Functions: CI/CD deployment pipeline orchestration (Validate → Normalize → Build → Monitor → Capture → Record); source-agnostic — drives both S3 archive and CodeCommit-backed deployments
- CodeBuild: Dual-source IaC execution in isolated Docker containers (Terraform, CDK, CloudFormation). Clones from CodeCommit or unzips an S3 archive based on Step Functions input
- CodeCommit: Pre-seeded
fsi-foundry-*repositories — one per FSI Foundry use case + one per reference implementation — that back the frontend's "Deploy from Git" option. Seeded viascripts/seed-codecommit.sh init - EventBridge: Deployment lifecycle events with dead-letter queue, plus per-repo git push / PR-merge rules that auto-trigger Step Functions
- State Backend: Terraform remote state (S3 + DynamoDB locking) per deployment
- CloudFront: CDN for frontend distribution
- Cognito: User authentication and authorization
- CloudWatch: Logs, metrics, alarms, and dashboards
- ECR: Container registry for backend Docker images
- VPC (Optional): Can use existing VPC or create new one
- Terraform >= 1.0
- AWS CLI configured with appropriate credentials
- Docker (for building container images)
- An AWS account with necessary permissions
Copy the example env file:
cp .env.example .envEdit .env with your configuration:
# Required
AWS_REGION=us-east-1
ENVIRONMENT=dev
# Optional - Use existing VPC (recommended for faster deployment)
VPC_ID=vpc-xxxxx
PUBLIC_SUBNET_IDS=subnet-xxx,subnet-yyy
PRIVATE_SUBNET_IDS=subnet-aaa,subnet-bbb
# Optional - Custom domain
DOMAIN_NAME=ava-platform.example.com
HOSTED_ZONE_ID=Z1234567890ABCCopy the example tfvars file:
cp terraform.tfvars.example terraform.tfvarsEdit terraform.tfvars with your values.
terraform initterraform planterraform applyThis will create all necessary AWS resources. The deployment typically takes 15-20 minutes.
To use an existing VPC (recommended to avoid long VPC creation time):
- Set these variables in your
.envorterraform.tfvars:
vpc_id = "vpc-xxxxx"
public_subnet_ids = ["subnet-xxxxx", "subnet-yyyyy"]
private_subnet_ids = ["subnet-aaaaa", "subnet-bbbbb"]- Leave them empty to create a new VPC:
vpc_id = ""
public_subnet_ids = []
private_subnet_ids = []The Control Plane supports two deployment source modes, and both share the same CodeBuild pipeline:
| Source | UI tab | What gets cloned / unzipped |
|---|---|---|
| S3 archive | Quick Deploy | Backend packages the use case source on demand, uploads to s3://<project-archives>/deployments/<id>/<name>.zip, CodeBuild unzips it |
| CodeCommit | Deploy from Git | CodeBuild git clones one of the pre-seeded fsi-foundry-* repos |
Both paths call the same Step Functions state machine. A NormalizeBuildInput pass state fills in empty defaults for whichever fields the chosen source doesn't set, so InvokeCodeBuild never fails on a missing JSONPath.
Run the seeding script after deploy-full.sh:
cd scripts
./seed-codecommit.sh initThis discovers every FSI Foundry use case listed in applications/fsi_foundry/data/registry/offerings.json plus every reference implementation under applications/reference_implementations/, and creates a CodeCommit repo per item:
fsi-foundry-<use_case>for each of the 34 use cases — e.g.fsi-foundry-kyc_bankingfsi-foundry-use-case-<ref-impl>for each reference implementation — e.g.fsi-foundry-use-case-shopping-concierge-agent
Each seeded repo is a self-contained deployment bundle (infra/, runtime/, ui_iac/, ui/<use_case>/, shared/, docker/, app_src/, use_cases/<use_case>/src/, data/samples/), mirroring the layout that the S3 path packages on demand.
Re-run ./seed-codecommit.sh sync whenever the underlying source changes (e.g. after updating the Bedrock model) to force-push fresh content into each repo.
- Sign in to the Control Plane
- Pick a use case from FSI Foundry
- On Deploy Application, switch to the Deploy from Git tab
- The repo dropdown auto-loads (
GET /api/v1/codecommit/repositories) and selects the one matching the use case - Optionally change the branch (defaults to
main) - Click Deploy from Git — CodeBuild clones the repo and runs the same infra/runtime/UI stages as the S3 path
Each seeded repo gets EventBridge rules (codecommit-push, codecommit-pr-merged) from the codecommit Terraform module. When a developer clones a repo, modifies it, and pushes to main (or merges a PR), the rule fires Step Functions with that repo+branch and the deployment runs automatically. Trigger branches are configurable in terraform.tfvars via codecommit_trigger_branches.
# One-time per developer
git config --global credential.helper '!aws codecommit credential-helper $@'
git config --global credential.UseHttpPath true
# Clone, modify, push
git clone https://git-codecommit.<region>.amazonaws.com/v1/repos/fsi-foundry-<use_case>
cd fsi-foundry-<use_case>
# edit files...
git add .
git commit -m "customize: tweak agent prompt"
git push origin main # triggers deployment via EventBridgeAfter infrastructure is deployed:
- Get ECR repository URL from Terraform outputs:
export ECR_REPO=$(terraform output -raw ecr_repository_url)- Authenticate Docker to ECR:
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $ECR_REPO- Build and push Docker image:
cd ../backend
docker build -t control-plane-backend .
docker tag control-plane-backend:latest $ECR_REPO:latest
docker push $ECR_REPO:latest- Update ECS service to use the new image (automatic if using
latesttag).
After infrastructure is deployed:
- Get S3 bucket and CloudFront distribution ID:
export FRONTEND_BUCKET=$(terraform output -raw frontend_bucket_name)
export CLOUDFRONT_ID=$(terraform output -raw cloudfront_distribution_id)- Build frontend:
cd ../frontend
npm install
npm run build- Deploy to S3:
aws s3 sync dist/ s3://$FRONTEND_BUCKET/- Invalidate CloudFront cache:
aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_ID --paths "/*"infrastructure/
├── main.tf # Main orchestration
├── variables.tf # Input variables
├── outputs.tf # Output values
├── providers.tf # Provider configuration
├── .env.example # Environment variables template
├── terraform.tfvars.example # Terraform variables template
├── scripts/ # Deployment and seeding shell scripts
│ ├── deploy-full.sh # One-command full deployment (infra + backend image + frontend + Cognito users)
│ ├── destroy.sh # Tear down all resources
│ ├── import-existing.sh # Import pre-existing AWS resources into Terraform state
│ ├── seed-codecommit.sh # Shell wrapper around the Python seeder
│ └── seed-codecommit-templates.py # Creates one CodeCommit repo per FSI Foundry use case + ref impl
└── modules/
├── networking/ # VPC, subnets, security groups
├── dynamodb/ # DynamoDB tables
├── s3/ # S3 buckets (project archives + frontend)
├── ecr/ # ECR repository (backend image)
├── ecs/ # ECS cluster, service, tasks (backend API)
├── api_gateway/ # API Gateway with VPC Link
├── step_functions/ # Source-agnostic deployment orchestrator
├── codebuild/ # Dual-source buildspec (Git clone OR S3 unzip)
├── codecommit/ # Pre-seeded use case repos + EventBridge trigger rules
├── eventbridge/ # Deployment lifecycle events with DLQ
├── state_backend/ # Terraform remote state (S3 + DynamoDB)
├── cognito/ # Cognito user pool and identity pool
├── cloudfront/ # CloudFront distribution (control plane frontend)
└── observability/ # CloudWatch dashboards and alarms
For detailed usage of each script in scripts/ — modes, environment variables, when to run which — see scripts/README.md.
After deployment, Terraform outputs key information:
# Get all outputs
terraform output
# Get specific outputs
terraform output api_endpoint
terraform output frontend_url
terraform output cognito_user_pool_id
terraform output ecr_repository_urlTo destroy all infrastructure:
terraform destroyWarning: This will delete all resources including data in DynamoDB and S3.
This infrastructure uses the following AWS services that incur costs:
- ECS Fargate: Pay per vCPU and memory per hour
- API Gateway: Pay per request
- CloudFront: Pay per data transfer
- DynamoDB: On-demand billing
- S3: Pay per GB stored and data transfer
- Step Functions: Pay per state transition
- CloudWatch: Logs and metrics storage
Estimated monthly cost for dev environment: $50-100 (with minimal traffic)
Check CloudWatch logs:
aws logs tail /ecs/ava-control-plane-dev --followCheck:
- ECS service is running
- Target group health checks are passing
- VPC Link is active
Invalidate cache:
aws cloudfront create-invalidation --distribution-id <ID> --paths "/*"For production, enable remote state:
- Uncomment the backend configuration in
main.tf:
backend "s3" {
bucket = "ava-terraform-state"
key = "control-plane/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-lock"
}- Create the S3 bucket and DynamoDB table:
aws s3api create-bucket --bucket ava-terraform-state --region us-east-1
aws dynamodb create-table \
--table-name terraform-state-lock \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--billing-mode PAY_PER_REQUEST- Re-initialize Terraform:
terraform init -migrate-state- All S3 buckets have public access blocked
- ECS tasks run in private subnets
- API Gateway uses VPC Link for private integration
- DynamoDB tables use encryption at rest
- CloudWatch logs are retained for 7 days
- Cognito enforces strong password policy
For issues or questions:
- Check CloudWatch dashboards for metrics
- Review CloudWatch logs for errors