This repository provisions a simple but strict hub-and-spoke-on-one-VNet design in West US 2 using Terraform and GitHub Actions (OIDC), with:
- Application Gateway WAF v2 (ONLY public HTTP/S entry)
- Azure Bastion (ONLY ops ingress) + JumpBox VM
- Azure Firewall Premium + UDRs + DNS proxy
- Azure Functions (Elastic Premium, Linux .NET) with Private Endpoint (no public)
- Azure Service Bus Premium (private only) + queue
q-aaimacdl-hub - Azure Key Vault (private only) storing TLS cert for App Gateway
- Azure Private DNS zones in hub
- Log Analytics workspace
- Remote Terraform state in a private Storage Account via Private Endpoint
Subscription:
be919d3c-e0c6-4f3a-87f3-826d529e6788
One-time bootstrap creates remote state (private Storage Account) with
-backend=false, then we re-init to use that backend.
-
Prereqs
- Azure CLI >= 2.60
- Terraform CLI >= 1.12.x
- You have Contributor/Owner on the subscription
- You know your Tenant ID (set
ARM_TENANT_ID)
-
Create OIDC App Registration (if not already)
- See
docs/oidc-setup.md
- See
-
Bootstrap remote state (from your machine)
cd infra/envs/prod
# Create RG + Storage + Container (backend.tf intentionally points to them but we create with -backend=false first)
terraform init -backend=false
terraform apply -auto-approve -target=module.remote_state
# Now re-init to migrate state into the backend
terraform init
# (Answer 'yes' to copy local state to remote)- Plan / Apply infra
terraform plan -out tfplan
terraform apply tfplan-
Set up self-hosted GitHub runner (inside VNet)
- After infra deploys, follow
docs/self-hosted-runner.mdto register the runner VM to your repo and enable the GitHub Actions workflow.
- After infra deploys, follow
-
Upload Key Vault self-signed cert for App Gateway
- From JumpBox (via Bastion), follow
docs/cert-keyvault.md.
- From JumpBox (via Bastion), follow
-
Deploy sample Function code
- Build the sample in
samples/function-dotnet/and deploy persamples/function-dotnet/README.md.
- Build the sample in