The GSM infrastructure stack is the foundational CloudFormation template that provisions every AWS resource the application depends on — from the S3-backed CloudFront frontend to the EC2-hosted ECS cluster running the four backend microservices. Deploy this stack first, into any environment (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ti-infinite/GSMInfrastructure/llms.txt
Use this file to discover all available pages before exploring further.
dev, qa, or prod), before deploying the scheduler stack or pushing container images. Re-deployments are safe; the workflow uses no-fail-on-empty-changeset so running it again with no template changes succeeds without error.
What gets created
The template atdevops/infrastructure/template.yml provisions the following resources, all named using the {Environment}-{AppName}-* convention:
Frontend
- S3 bucket —
{env}-{appName}-frontend: versioning enabled, AES-256 server-side encryption, all public access blocked. - CloudFront Origin Access Control (OAC) — restricts S3 access to CloudFront only, signed with SigV4.
- CloudFront Function —
SpaRouterFunctionrewrites extension-less URI paths to/index.htmlfor SPA routing. - CloudFront distribution — HTTPS redirect enforced on the default cache behavior; a dedicated
/api/*cache behavior forwards requests to the EC2 backend with all headers and cookies passed through (MinTTL: 0,DefaultTTL: 0,MaxTTL: 0). UsesPriceClass_100(US/EU/Canada edge locations).
- ECR repository —
{env}-{appName}-respositorywithScanOnPush: true. - ECS cluster —
{env}-{appName}-cluster. - Four ECS task definitions and services (EC2 launch type,
bridgenetwork mode):gateway— port 80, image taggateway-latestauth— port 8081, image tagauth-latestapplication— port 8082, image tagapplication-latestoperations— port 8083, image taggsmoperations-latest
- EC2 instance —
{env}-{appName}-ec2-instance: arm64 architecture, default typet4g.medium, ECS-optimized Amazon Linux 2023 AMI (resolved via SSM at deploy time). User data registers the instance to the ECS cluster automatically. - Elastic IP — allocated and associated to the EC2 instance. Leave
ExistingEIPPublicIpempty to allocate a new EIP, or pass an existing public IP to reuse it.
- Security group —
{env}-{appName}-ecs-security-group: ingress on port 80 from the CloudFront managed prefix list and VPC CIDR; inter-container communication on ports 8081–8083 over the Docker bridge (172.17.0.0/16); egress for HTTPS (443), DNS (UDP 53), and the database port.
- ECS execution role —
{env}-{appName}-ecs-role:AmazonECSTaskExecutionRolePolicy+ SSMGetParameteraccess under{env}/*. - ECS task role —
{env}-{appName}-ecs-task-role: SSM read access under{env}/*. - EC2 instance role —
{env}-{appName}-instance-ecs-role:AmazonEC2ContainerServiceforEC2Role,AmazonSSMManagedInstanceCore, and SSM read access.
- CloudWatch log group —
/ecs/{env}-{appName}-backendwith 7-day retention. - SNS topic —
{env}-{appName}-notification-alerts: email subscription usingAlertEmail. - AWS Budget —
{env}-{appName}-monthly-budget: monthly cost budget in USD; SNS alert fires at 100% of the configured limit.
CloudFormation parameters
All parameters with defaults
All parameters with defaults
| Parameter | Default | Description |
|---|---|---|
Environment | dev | Deployment target — dev, qa, or prod. Controls resource naming and SSM path prefixes. |
AppName | gsmapplication | Base name for all provisioned resources. |
BudgetLimitUSD | 30 | Monthly AWS cost limit in USD before an SNS alert is triggered. |
AlertEmail | (required) | Email address that receives budget breach notifications from the SNS topic. |
CloudFrontHeader | (required) | Secret header value injected by CloudFront into origin requests (X-CloudFront-Origin); validated by the backend. |
TaskNumberDesired | 0 | Number of running tasks for each ECS service. Keep at 0 until container images have been pushed to ECR. |
TaskMemory | 512 | Hard memory limit (MB) applied to each ECS container. |
TaskMemoryReservation | 384 | Soft memory reservation (MB) per ECS container. |
DBPortParameterName | 1433 | TCP port of the SQL Server database used in the security group egress rule. |
DBMasterUrlParameterName | dev/backend/DB_MASTER_URL | SSM Parameter Store path for the master database connection string. |
SqlServerProviderIp | 0.0.0.0/0 | CIDR block of the SQL Server provider, used in the security group egress rule. Narrow this to a /32 in production. |
JWTSecretParameterName | dev/backend/JWT_SECRET | SSM Parameter Store path for the JWT signing secret. |
VpcId | (required) | ID of the existing VPC where the EC2 instance and security group are placed. |
VpcIdCidrBlock | 10.0.0.0/16 | CIDR block of the VPC; used in security group ingress rules. |
PrivateSubnet1Id | (required) | Subnet ID (private, AZ1) in which the EC2 instance is launched. |
Ec2PenKeyName | dev-key-ec2 | Name of the EC2 key pair for SSH access. |
Ec2InstanceType | t4g.medium | EC2 instance type. Must be arm64-compatible to match the Amazon Linux 2023 arm64 AMI. |
ExistingEIPPublicIp | "" | Public IP of an existing Elastic IP to reuse. Leave empty to have CloudFormation allocate a new EIP. |
Deploy manually with AWS CLI
Use the following command to deploy the stack directly from your terminal. Replace placeholder values with those matching your environment:Stack outputs
After a successful deploy, CloudFormation exports these values. Use them as inputs when deploying the scheduler stack:| Output key | Description |
|---|---|
FrontendBucketName | Name of the S3 bucket for frontend assets. Use this as the upload target in your frontend CI/CD pipeline. |
CloudFrontDomain | CloudFront distribution domain name (e.g. d1abc2defg3.cloudfront.net). |
ECSClusterName | Name of the ECS cluster — required by the scheduler stack’s ECSClusterName parameter. |
BudgetName | Name of the AWS Budget resource. Note: the output value contains a double-dash: {env}--{appName}-monthly-budget (source typo). The budget resource itself is named {env}-{appName}-monthly-budget. |
Deploying via GitHub Actions
Pushing any change todevops/infrastructure/template.yml on the develop, quality, or main branches automatically triggers the Deploy Infrastructure workflow — provided the WORKFLOW_INFRASTRUCTURE_ENABLED GitHub Actions variable is set to true for that environment. Branch names map to environments as follows:
| Branch | Environment |
|---|---|
develop | dev |
quality | qa |
main | prod |
environment input. See the CI/CD guide for full details on secrets, variables, and OIDC authentication.
The CloudFormation deploy step uses
no-fail-on-empty-changeset: "1", so re-running the workflow when the template has not changed will succeed without error. This is safe to do at any time.Post-deploy steps
Once the stack is created, the ECS services are running withDesiredCount: 0. Before increasing the task count, push container images to the ECR repository.
Tag and push all four images
The ECR repository URI follows the pattern
<account-id>.dkr.ecr.us-east-1.amazonaws.com/{env}-{appName}-respository.
Each service expects a specific image tag: