Repository navigation
Resources
Every AWS resource the module creates, grouped by the submodule that declares
it. N is the number of availability zones, which is 2 unless the networking
module's availability_zones variable is overridden. <prefix> is
<project_name>-<environment>.
| Resource | Count | What it is for |
|---|---|---|
aws_vpc.main |
1 | The VPC. DNS hostnames and DNS support both on, which RDS and the interface endpoints need. |
aws_subnet.public |
N | ALB and NAT gateways. map_public_ip_on_launch = true. |
aws_subnet.private |
N | ECS tasks and RDS. No public IPs. |
aws_internet_gateway.main |
1 | Egress for the public subnets. |
aws_eip.nat |
1 or N | Elastic IP per NAT gateway. |
aws_nat_gateway.main |
1 or N | Outbound internet for private subnets. N only when enable_multi_az_nat. |
aws_route_table.public |
1 | Default route to the IGW. |
aws_route_table_association.public |
N | Attaches the public subnets. |
aws_route_table.private |
N | One per AZ, so multi-AZ NAT can route each subnet through its local gateway. |
aws_route_table_association.private |
N | Attaches the private subnets. |
aws_vpc_endpoint.s3 |
1 | Gateway endpoint on the private route tables. Free, and keeps S3 (including ECR layer storage in some regions) off the NAT. Always created. |
aws_security_group.vpc_endpoints |
0 or 1 | Allows 443 from the VPC CIDR to the interface endpoints. |
aws_vpc_endpoint.interface |
0 or 4 |
ecr.api, ecr.dkr, logs, secretsmanager, with private DNS, in every private subnet. |
aws_s3_bucket.flow_logs |
0 or 1 | Flow log destination, named with the account id for global uniqueness. force_destroy = true. |
aws_s3_bucket_public_access_block.flow_logs |
0 or 1 | Blocks all public access on that bucket. |
aws_s3_bucket_lifecycle_configuration.flow_logs |
0 or 1 | Expires flow log objects after 30 days. |
aws_flow_log.vpc |
0 or 1 |
traffic_type = ALL, delivered to S3. |
| Resource | Count | What it is for |
|---|---|---|
aws_cloudwatch_log_group.api |
1 | /ecs/<prefix>/api |
aws_cloudwatch_log_group.frontend |
1 | /ecs/<prefix>/frontend |
aws_cloudwatch_log_group.maintenance |
1 | /ecs/<prefix>/maintenance |
aws_cloudwatch_log_group.demo_loop |
1 |
/ecs/<prefix>/demo-loop. Created even when the demo loop is disabled. |
aws_sns_topic.alerts |
1 | Destination for the budget and the NAT alarms. |
aws_sns_topic_subscription.alerts_email |
0 or 1 | Email subscription; skipped when alert_email is empty. |
aws_sns_topic_policy.alerts |
1 | Lets budgets.amazonaws.com and cloudwatch.amazonaws.com publish to the topic. |
aws_budgets_budget.daily |
0 or 1 | Daily cost budget with one ACTUAL notification at 100%. Skipped entirely when alert_email is empty. |
aws_cloudwatch_metric_alarm.nat_bytes_out |
0, 1, or N | One per NAT gateway on hourly BytesOutToDestination. Skipped when nat_bytes_out_alarm_gb is 0. treat_missing_data = notBreaching. |
| Resource | Count | What it is for |
|---|---|---|
aws_security_group.database |
1 | Database SG. Created with create_before_destroy. |
aws_vpc_security_group_ingress_rule.db_from_ecs |
1 per allowed SG | Port 5432 from the ECS tasks security group. |
aws_db_subnet_group.main |
1 | Places the instance in the private subnets. |
aws_db_instance.main |
1 | PostgreSQL 16, gp3, encrypted, not publicly accessible, 7-day backups, final snapshot on destroy, deletion_protection = true, and a prevent_destroy lifecycle block. Performance Insights off. |
Five aws_secretsmanager_secret + aws_secretsmanager_secret_version pairs,
all with a 7-day recovery window.
| Secret name | Contents |
|---|---|
<prefix>/db-password |
The raw database password |
<prefix>/db-connection-string |
Full postgresql:// URL, injected as DATABASE_URL
|
<prefix>/api-internal-secret |
Frontend-to-API shared secret |
<prefix>/kiosk-tokens |
Comma-separated kiosk viewer tokens |
<prefix>/client-passphrase |
Endpoint agent passphrase |
| Resource | Count | What it is for |
|---|---|---|
aws_sqs_queue.ingest |
1 |
<prefix>-osquery-ingest. 4-day retention, 5-minute visibility timeout, 20s long polling. |
aws_sqs_queue.ingest_dlq |
1 | Dead-letter queue, 14-day retention. |
aws_sqs_queue_redrive_policy.ingest |
1 | Moves a message to the DLQ after 3 receives. |
aws_s3_bucket.main |
1 |
<prefix>-storage, for reports, exports, and backups. |
aws_s3_bucket_versioning.main |
1 | Versioning enabled. |
aws_s3_bucket_server_side_encryption_configuration.main |
1 | SSE-KMS with bucket keys. |
aws_s3_bucket_public_access_block.main |
1 | All four public-access blocks on. |
| Resource | Count | What it is for |
|---|---|---|
aws_cognito_user_pool.main |
1 | Email as username, auto-verified email, 12-character password policy requiring all four classes, optional software-token MFA, advanced security ENFORCED, email account recovery. |
aws_cognito_user_pool_domain.main |
1 | Hosted UI at <prefix>. Globally unique across AWS. |
aws_cognito_user_pool_client.web |
1 | Authorization-code flow with a generated secret; openid, email, profile; 1h access/id tokens, 30d refresh; prevent_user_existence_errors on. |
aws_cognito_user_group.admin |
1 | Full administrative access. |
aws_cognito_user_group.user |
1 | Standard read-only access. |
random_password.nextauth_secret |
1 | 64-character NextAuth session secret. |
aws_secretsmanager_secret.cognito_client_id (+ version) |
1 | <prefix>/cognito-client-id |
aws_secretsmanager_secret.cognito_client_secret (+ version) |
1 | <prefix>/cognito-client-secret |
aws_secretsmanager_secret.nextauth_secret (+ version) |
1 | <prefix>/nextauth-secret |
| Resource | Count | What it is for |
|---|---|---|
aws_iam_role.ecs_execution |
1 | Assumed by ecs-tasks.amazonaws.com. Pulls images, fetches secrets, writes logs. |
aws_iam_role_policy_attachment.ecs_execution_base |
1 | The AWS-managed AmazonECSTaskExecutionRolePolicy. |
aws_iam_role_policy.ecs_execution_secrets |
0 or 1 |
secretsmanager:GetSecretValue on exactly the eight secret ARNs the root module passes in. |
aws_iam_role.ecs_task |
1 | The application's own role, assumed by the running container. |
aws_iam_role_policy.ecs_task_logs |
1 |
logs:CreateLogStream and logs:PutLogEvents on /ecs/<prefix>/*. |
The task role has no SQS, S3, or Secrets Manager permissions. The identity
module also declares an ecr_repository_arns variable that no policy uses.
| Resource | Count | What it is for |
|---|---|---|
aws_ecr_repository.api |
1 |
<project_name>-api, mutable tags, scan on push, force_delete = false. |
aws_ecr_repository.frontend |
1 |
<project_name>-frontend, same settings. |
aws_ecr_lifecycle_policy.api |
1 | Expire beyond the last 10 images. |
aws_ecr_lifecycle_policy.frontend |
1 | Expire beyond the last 10 images. |
Note that ECR repository names use project_name only, without the
environment. Two environments in one account share these repositories.
| Resource | Count | What it is for |
|---|---|---|
aws_ecs_cluster.main |
1 |
<prefix>-cluster, Container Insights enabled. |
aws_security_group.alb |
1 | ALB security group. |
aws_vpc_security_group_ingress_rule.alb_http |
1 | Port 80 from 0.0.0.0/0. |
aws_vpc_security_group_ingress_rule.alb_https |
1 | Port 443 from 0.0.0.0/0. |
aws_vpc_security_group_egress_rule.alb_out |
1 | All outbound. |
aws_security_group.ecs_tasks |
1 | Shared by every Fargate task in the deployment, including maintenance and demo-loop. |
aws_vpc_security_group_ingress_rule.ecs_from_alb |
1 | TCP 0–65535 referencing the ALB security group. |
aws_vpc_security_group_egress_rule.ecs_out |
1 | All outbound. |
| Resource | Count | What it is for |
|---|---|---|
aws_lb.main |
1 | Internet-facing application load balancer in the public subnets. |
aws_lb_listener.http |
1 | Port 80, unconditional 301 to port 443 HTTPS. |
aws_lb_listener.https |
1 | Port 443. HTTPS with ELBSecurityPolicy-2016-08 when acm_certificate_arn is set, otherwise plain HTTP. Default action forwards to the frontend target group. |
aws_lb_target_group.api |
1 | Port 8000, target_type = ip, health check /api/v1/health. |
aws_lb_target_group.frontend |
1 | Port 3000, target_type = ip, health check /. |
aws_lb_listener_rule.api |
1 | Priority 100, path pattern /api/v1/*, forwards to the API target group. |
| Resource | Count | What it is for |
|---|---|---|
aws_ecs_task_definition.api |
1 | Fargate, awsvpc, sized by api_cpu/api_memory, container-level curl health check with a 90s start period. |
aws_ecs_task_definition.frontend |
1 | Fargate, awsvpc, sized by frontend_cpu/frontend_memory. |
aws_ecs_service.api |
1 | Desired count 1, private subnets, no public IP, registered with the API target group, 50/200 deployment percentages. |
aws_ecs_service.frontend |
1 | Same shape, frontend target group. |
aws_appautoscaling_target.api |
1 | Min 1, max 5 tasks. |
aws_appautoscaling_policy.api_cpu |
1 | Target-tracking on average CPU at 70%. |
aws_appautoscaling_target.frontend |
1 | Min 1, max 5 tasks. |
aws_appautoscaling_policy.frontend_cpu |
1 | Target-tracking on average CPU at 70%. |
| Resource | Count | What it is for |
|---|---|---|
aws_apigatewayv2_api.websocket |
1 | WebSocket API, route selection on $request.body.action. |
aws_apigatewayv2_integration.default |
1 |
HTTP_PROXY POST to <api_url>/v1/negotiate. |
aws_apigatewayv2_route.connect |
1 | $connect |
aws_apigatewayv2_route.disconnect |
1 | $disconnect |
aws_apigatewayv2_route.default |
1 | $default |
aws_apigatewayv2_stage.production |
1 | Auto-deploying stage, throttled at 50 rps / 100 burst. |
| Resource | Count | What it is for |
|---|---|---|
aws_ecr_repository.maintenance |
1 |
<project_name>-maintenance. Created empty — this repo does not build the image. |
aws_ecr_lifecycle_policy.maintenance |
1 | Expire beyond the last 5 images. |
aws_ecs_task_definition.maintenance |
1 | Fargate 256/512, EVENT_RETENTION_DAYS env, DATABASE_URL secret. |
aws_scheduler_schedule.maintenance |
1 |
cron(0 2 * * ? *) UTC, flexible time window off, runs one Fargate task in the private subnets. |
aws_iam_role.scheduler |
1 | Assumed by scheduler.amazonaws.com. |
aws_iam_role_policy.scheduler_ecs |
1 |
ecs:RunTask on that one task definition, plus iam:PassRole on the execution and task roles. |
| Resource | Count | What it is for |
|---|---|---|
aws_ecr_repository.demo_loop |
1 |
<project_name>-demo-loop. |
aws_ecr_lifecycle_policy.demo_loop |
1 | Expire beyond the last 5 images. |
aws_ecs_task_definition.demo_loop |
1 | Fargate 256/512 running demo-data-generator.py --loop, with REPORTMATE_PASSPHRASE from Secrets Manager. |
aws_ecs_service.demo_loop |
1 | Desired count 1, private subnets, 0/100 deployment percentages. |
Defaults: 300 devices, batches of 15 every 120 seconds, full fleet refresh every 1800 seconds.
| Resource | Count | What it is for |
|---|---|---|
aws_s3_bucket.state |
1 |
<project_name>-terraform-state, with prevent_destroy. |
aws_s3_bucket_versioning.state |
1 | Versioning enabled, so a corrupted state can be rolled back. |
aws_s3_bucket_server_side_encryption_configuration.state |
1 | SSE-KMS with bucket keys. |
aws_s3_bucket_public_access_block.state |
1 | All four blocks on. |
aws_dynamodb_table.lock |
1 |
<project_name>-terraform-lock, pay-per-request, hash key LockID. |
Worth stating plainly, because the variable names suggest otherwise: there is
no CloudFront distribution, no ACM certificate, no Route 53 zone or record, and
no WAF. enable_custom_domain and domain_name are inert. Bring your own
certificate ARN and put whatever CDN or DNS you want in front of the ALB.
MIT licensed. — reportmate.app