Skip to content

feat: Terraform IaC for per-client Azure provisioning - #2

Merged
countercheck merged 11 commits into
mainfrom
feature/infra
Feb 24, 2026
Merged

feat: Terraform IaC for per-client Azure provisioning#2
countercheck merged 11 commits into
mainfrom
feature/infra

Conversation

@countercheck

Copy link
Copy Markdown
Owner

Summary

  • Adds infra/azure/ Terraform configuration to provision a per-client VM, networking, managed identity, and backup blob container on Azure
  • Provider-prefixed directory structure (infra/azure/) establishes an explicit isolation seam — a future infra/aws/ would accept the same inputs and produce the same outputs
  • Replaces the placeholder Bicep/ARM description in infra/README.md with the actual Terraform approach and usage instructions

What gets provisioned

Per terraform apply -var-file=clients/edmonton.tfvars:

  • Resource group tiller-{client_name}
  • VNet + subnet, static public IP, NSG (SSH/HTTP/HTTPS inbound), NIC
  • User-assigned managed identity with Storage Blob Data Contributor on the shared backup account — enables backup.sh --auth-mode login without stored credentials
  • Ubuntu 22.04 LTS B2ms VM with SSH key auth
  • Blob container {client_name}-backups in pre-existing shared tillerbackups storage account

State is local (terraform.tfstate, gitignored). The .tfvars files in clients/ are committed — they contain no secrets (SSH public key only).

Test Plan

  • Deploy scripts test suite: 12/12 passing
  • terraform init && terraform validate in infra/azure/ — requires Terraform >= 1.9 installed
  • terraform plan -var-file=clients/edmonton.tfvars — requires ARM_SUBSCRIPTION_ID set and az login authenticated

Copilot AI review requested due to automatic review settings February 23, 2026 01:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Terraform-based Azure IaC implementation under infra/azure/ to provision per-client infrastructure (VM, networking, managed identity, and a per-client backup blob container), and updates infra documentation to reflect the Terraform approach and the provider-isolation contract.

Changes:

  • Introduces root Terraform configuration (providers.tf, variables.tf, main.tf, outputs.tf) for per-client Azure provisioning.
  • Adds two Terraform modules: modules/vm (VM + networking + managed identity + role assignment) and modules/backup-container (per-client blob container in shared storage).
  • Updates infra/README.md and adds design/implementation plan docs describing the new approach.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
infra/azure/providers.tf Pins Terraform/provider requirements and configures the AzureRM provider.
infra/azure/variables.tf Defines the input contract for per-client provisioning.
infra/azure/main.tf Composes the VM and backup-container modules.
infra/azure/outputs.tf Exposes public IP, RG name, and backup container name as the output contract.
infra/azure/modules/vm/main.tf Implements resource group, identity + role assignment, VNet/subnet, NSG, NIC, and Linux VM.
infra/azure/modules/vm/variables.tf Module inputs for VM provisioning.
infra/azure/modules/vm/outputs.tf Module outputs for public IP and resource group name.
infra/azure/modules/backup-container/main.tf Creates a per-client blob container in a shared storage account.
infra/azure/modules/backup-container/variables.tf Module inputs for backup container creation.
infra/azure/modules/backup-container/outputs.tf Module output for the container name.
infra/azure/clients/edmonton.tfvars Example per-client tfvars file (non-secret values + SSH public key placeholder).
infra/azure/.gitignore Ignores local Terraform state and plan artifacts for this directory.
infra/README.md Updates infra documentation from placeholder Bicep/ARM to Terraform usage instructions.
docs/plans/2026-02-22-infra.md Adds a step-by-step implementation plan for the Terraform infra work.
docs/plans/2026-02-22-infra-design.md Adds design rationale and the provider-isolation contract description.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +29 to +66
Note: `.terraform.lock.hcl` is intentionally NOT ignored — it pins provider versions and should be committed (like a lockfile).

**Step 2: Create providers.tf**

```hcl
# infra/azure/providers.tf
terraform {
required_version = ">= 1.9"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
}
}

provider "azurerm" {
features {}
# subscription_id is read from ARM_SUBSCRIPTION_ID environment variable.
# Set it before running terraform: export ARM_SUBSCRIPTION_ID="<your-sub-id>"
}
```

**Step 3: Run terraform init**

```bash
cd infra/azure
terraform init
```

Expected: "Terraform has been successfully initialized!" and `.terraform.lock.hcl` is created.

**Step 4: Commit**

```bash
git add infra/azure/.gitignore infra/azure/providers.tf infra/azure/.terraform.lock.hcl
git commit -m "feat: bootstrap infra/azure with terraform provider config"
```

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This plan states that .terraform.lock.hcl "should be committed", and the sample commit command includes it, but the PR doesn't add the lockfile. Either commit infra/azure/.terraform.lock.hcl (recommended to pin provider versions) or update the plan to avoid implying it’s present/committed.

Copilot uses AI. Check for mistakes.
Comment thread infra/README.md Outdated
Comment thread infra/azure/variables.tf
Comment on lines +54 to +64
security_rule {
name = "SSH"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SSH NSG rule currently allows inbound TCP/22 from any source (source_address_prefix = "*"). This exposes the VM SSH port to the internet; consider restricting this to an allowlisted CIDR (e.g., an input variable like ssh_source_cidr) and/or documenting why unrestricted SSH is acceptable.

Copilot uses AI. Check for mistakes.
Comment thread infra/azure/modules/vm/main.tf Outdated
countercheck and others added 3 commits February 23, 2026 00:24
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@countercheck
countercheck merged commit 6086642 into main Feb 24, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants