Skip to content

Subdomain Provisioning & Custom Domain SSL

How CampusCore automatically provisions subdomains and SSL certificates for each deployment, and how clients can use custom domains.


Overview

Each CampusCore deployment gets a subdomain under campuscoreai.com (e.g., vsu-troy-pilot.campuscoreai.com) with an automatically provisioned ACM certificate for HTTPS. Clients who want to use their own domain CNAME to the CampusCore subdomain.

Architecture

Central Admin Account                    Client Account (e.g., VSU)
┌──────────────────────────┐            ┌──────────────────────────┐
│ Route53: campuscoreai.com  │            │ ALB (port 80 + 443)      │
│                          │            │                          │
│ CNAME: vsu-troy-pilot    │───────────▶│ alb-xyz.elb.amazonaws.com│
│   .campuscoreai.com       │            │                          │
│                          │            │ ACM cert for             │
│ CNAME: _acm-validation   │            │ vsu-troy-pilot           │
│   (for cert issuance)    │            │   .campuscoreai.com       │
└──────────────────────────┘            └──────────────────────────┘

Client's DNS (external)
┌──────────────────────────┐
│ ai.vsu.edu CNAME ────────┼───▶ vsu-troy-pilot.campuscoreai.com
└──────────────────────────┘

How It Works

Subdomain Provisioning (Terraform)

When ENABLE_CUSTOM_DOMAIN_WITH_SSL is set to true in the GitHub Environment:

  1. Route53 CNAME — The subdomain module creates {env}.campuscoreai.com pointing to the ALB DNS in the admin account's Route53 hosted zone
  2. ACM Certificate — An ACM certificate is requested in the client's AWS account for {env}.campuscoreai.com
  3. DNS Validation — ACM validation CNAME records are created in the admin account's Route53 zone
  4. HTTPS Listener — Once the cert is validated, an HTTPS listener is added to the ALB in base/main.tf
  5. HTTP Redirect — A listener rule redirects all HTTP traffic to HTTPS

Cross-Account Model

This uses two AWS provider aliases: - aws (default) — client account, via assume_role. Used for ACM certificate, ALB listener - aws.admin — admin account, no assume_role. Used for Route53 records

Circular Dependency Resolution

The ALB is created by the ecs_cluster module, and the subdomain module needs the ALB DNS name. But the HTTPS listener needs the certificate ARN from subdomain. This is resolved by:

  1. ecs_cluster creates the ALB and HTTP listener (always forward)
  2. subdomain creates the Route53 CNAME and ACM cert using the ALB DNS
  3. base/main.tf creates the HTTPS listener and HTTP redirect rule using both the ALB ARN and cert ARN

Custom Domain SSL Modes

The admin UI (Settings > Domain) offers two SSL paths when a CampusCore subdomain is provisioned:

  • Client sets a CNAME: ai.university.edu{env}.campuscoreai.com
  • SSL is handled by the ACM certificate on the ALB
  • No SSL configuration needed by the client

Self-Managed SSL

  • Client sets a CNAME: ai.university.edu → ALB DNS directly
  • Client manages their own SSL (e.g., via Cloudflare, nginx reverse proxy)
  • The ALB serves HTTP; the client's proxy terminates SSL

The SSL mode is stored in AppConfig.custom_domain_ssl_mode and affects DNS verification — the domain is cross-checked against the appropriate target (CampusCore subdomain or ALB DNS).

Configuration

GitHub Environment Variables

Variable Required Description
ENABLE_CUSTOM_DOMAIN_WITH_SSL No Set to true to enable. Defaults to false
CAMPUSCORE_HOSTED_ZONE_ID When provisioning Route53 hosted zone ID for campuscoreai.com

Django Settings

Setting Source Description
CAMPUSCORE_SUBDOMAIN Env var e.g., vsu-troy-pilot.campuscoreai.com. Empty when not provisioned

Terraform Variables

Variable Module Description
enable_custom_domain_with_ssl base Bool, gates all subdomain resources
campuscore_hosted_zone_id base Passed to subdomain module

Files

File Purpose
infrastructure/modules/subdomain/main.tf Route53 CNAME, ACM cert, DNS validation
infrastructure/modules/subdomain/variables.tf Module inputs
infrastructure/modules/subdomain/outputs.tf certificate_arn, campuscore_subdomain
infrastructure/base/main.tf HTTPS listener, HTTP redirect rule, subdomain module wiring
campuscore_app/apps/main_app/models.py custom_domain fields on AppConfig
campuscore_app/apps/main_app/services/domain_service.py DNS verification with subdomain cross-check
campuscore_app/apps/main_app/apis/settings_apis.py Domain settings endpoints
campuscore_app/templates/partials/settings/domain.html Custom domain UI

Deploying Without Subdomain Provisioning

Set ENABLE_CUSTOM_DOMAIN_WITH_SSL to false (or omit it). The subdomain module produces empty outputs, no Route53/ACM resources are created, and no HTTPS listener is added. The ALB serves HTTP only and the custom domain settings UI is hidden.

IAM Permissions

  • Admin role (admin-oidc-role.yaml): Route53 permissions for managing campuscoreai.com DNS records
  • Client deploy role (deploy-role.yaml): ACM permissions for requesting and managing certificates, CloudFormation self-update permissions for automatic role updates via pipeline