Skip to content

Prerequisites

Pick whichever matches the situation. All three deploy the same foundation; the difference is where the tooling lives.

OptionBest forSetup timeCostPersistence
A. Azure Cloud Shell (browser)One-off deploys, evaluations, customer demos, no laptop install~1 minFree shell + ~$0.05/mo for 5 GB clouddrive5 GB home dir survives sessions
B. GitHub Codespaces (browser / VS Code)Multi-day work, contributing back, working from a Chromebook / iPad~2 min (first) / ~30 s (resume)Free tier 60 h/mo on 2-core; then per-hourWhole container survives until deleted
C. Local install (your laptop)Daily driver, offline work, custom toolchain pinning10–30 minFreeForever

If you’ve never deployed Launchpad before, start with Cloud Shell. If you’re going to maintain it, switch to Codespaces or local.

Cloud Shell is a browser-hosted bash shell that comes pre-authenticated to Azure with Terraform, the Azure CLI, Bicep, and Git already installed. Nothing to download.

1. Open it. Either:

First-time use prompts you to create a 5 GB Azure Files share for ~ persistence (≈ $0.05/mo). Pick Bash (not PowerShell).

2. Clone and authenticate.

Terminal window
git clone https://github.com/travishankins/azure-launchpad.git
cd azure-launchpad
# Cloud Shell is already authenticated to your tenant.
az account set --subscription <subscription-id>
export ARM_SUBSCRIPTION_ID=<subscription-id>

Then continue with the Terraform or Bicep quick start. Terraform users bootstrap state there; Bicep users do not need that step.

What’s preinstalled in Cloud Shell (versions move; check with --version):

ToolAvailable?Notes
Azure CLI✅ latest, with bicep extaz, az bicep build
Terraform✅ 1.xIf older than 1.9, see “Pinning Terraform” below
Bicep✅ via az bicepStandalone bicep binary also available
Git
GitHub CLIgh
jq, curl
just❌ not preinstalledOptional — install once: brew install just won’t work; use the binary release from https://just.systems or skip and run the underlying commands directly
tflint, pre-commitOnly needed for contributing back, not for deploys

Pinning Terraform. If Cloud Shell’s bundled Terraform is older than what the repo requires (≥ 1.9), the easiest fix is tfenv:

Terminal window
git clone --depth 1 https://github.com/tfutils/tfenv.git ~/.tfenv
export PATH="$HOME/.tfenv/bin:$PATH"
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bashrc
tfenv install 1.14.9 && tfenv use 1.14.9

The ~/.tfenv directory persists in your clouddrive across sessions.

Cloud Shell caveats:

  • 20-minute idle timeout. Long applies (e.g. firewall + VPN scenarios) usually finish in under 20 min, but if your tunnel drops mid-apply, just re-run — Terraform/Bicep are both idempotent.
  • No outbound to private endpoints. If you’ve already deployed and the workload is locked down behind a private endpoint, you can’t curl it from Cloud Shell unless it’s on a peered VNet (Cloud Shell supports VNet integration; out of scope here).
  • Editor. code . opens the in-shell Monaco editor (read-write on ~). Good enough for tweaking .tfvars / .bicepparam.
  • No GUI for the generator. The configuration generator runs in your browser at azurelaunchpad.com — generate the file there, paste it into Cloud Shell.

A Codespace is a containerized VS Code workspace running on GitHub-hosted infrastructure. Because the repo ships a .devcontainer/devcontainer.json, every tool is preinstalled at a known version — no drift between contributors.

1. Launch. One-click:

Open in GitHub Codespaces

…or in the repo, Code → Codespaces → Create codespace on main. First boot takes ~90 s while features install; subsequent resumes are seconds.

2. Authenticate to Azure.

Terminal window
az login --use-device-code
az account set --subscription <subscription-id>
export ARM_SUBSCRIPTION_ID=<subscription-id>

--use-device-code is required because Codespaces is browser-side; the redirect flow can’t reach your localhost.

3. Deploy. Same as local — pick Terraform or Bicep quick start.

What’s inside the dev container:

ComponentVersion / sourceUsed for
Ubuntu 24.04mcr.microsoft.com/devcontainers/base:ubuntu-24.04Base image
Azure CLIlatest, with bicep extensionaz login, deploys, bootstrap script
Terraform1.14.9 + tflintFoundation + management-groups modules
Node.js22Astro / Starlight docs site (cd site && npm run dev)
Python3.12Helper scripts
GitHub CLIlatestOIDC federated credential setup, repo automation
pre-commitlatestAuto-runs terraform fmt, lint, etc. on commit
justlatestRecipe runner (just plan baseline, just docs, …)

VS Code extensions are pre-pinned: HashiCorp Terraform, Bicep, Azure Resource Groups, GitHub Actions, GitHub Copilot, markdownlint, Astro, just. Port 4321 is auto-forwarded so cd site && npm run dev opens the live docs preview in a browser tab.

postCreateCommand runs pre-commit install and npm install in site/ on first open — give it ~2 min, then you’re ready to az login.

Working in Codespaces — practical tips:

  • Two surfaces, same container. Open the codespace in the browser for quick edits, or Code → Open in VS Code Desktop for full extensions and local keybindings. Both attach to the same remote container, so your shell history and uncommitted changes are shared.
  • Stop, don’t delete. Stopped codespaces don’t burn compute hours but keep your full filesystem. Delete only when you’re done with the customer.
  • Free tier math. GitHub gives 60 h/mo of 2-core (or 30 h/mo of 4-core) for personal accounts. A 2-core is plenty for terraform plan against this repo. Watch usage at https://github.com/settings/billing.
  • Secrets. Store ARM_SUBSCRIPTION_ID, customer prefixes, etc. as Codespace secrets so they’re injected as env vars on every boot. Never paste a service principal secret into a chat or commit it.
  • Rebuild on devcontainer changes. If devcontainer.json is updated upstream, Command Palette → Codespaces: Rebuild Container picks up the changes; existing files survive.
  • Same image, locally. The container also runs under VS Code Dev Containers on a local Docker — install the Dev Containers extension and Reopen in Container. Identical tooling, no GitHub compute usage.

Useful if you want offline work, custom Terraform pinning, or zero browser dependency.

ToolMinimum versionWhy
Terraform1.9Module syntax, validation rules
Azure CLI2.60az login, bootstrap script
Bicep CLI0.30Bundled with az bicep install
GitHub CLI (optional)2.40OIDC federated credential setup
git2.30Clone the repo
just (optional)latestRecipe runner — brew install just
Terminal window
# macOS
brew install terraform azure-cli gh just
az bicep install

Then continue with Local prep.

Use the least-privileged row that matches how you are deploying:

PathRequired access
Interactive Bicep or Terraform foundationContributor on each target subscription
Terraform state bootstrapContributor plus permission to assign roles, or Owner, long enough to create the backend and grant blob-data access
Terraform state accessStorage Blob Data Contributor on the state storage account for every human or OIDC identity that runs Terraform
GitHub ActionsPermission to create/reuse an Entra app registration, federated credentials, repository variables, and protected environments
Management GroupsManagement Group Contributor at Tenant Root; also Resource Policy Contributor when enabling policies
Multi-subscription foundationContributor on connectivity, management, and landing-zone subscriptions

For post-deploy site-to-site VPN wiring, also gather the VPN device public IP, supported IKE versions, shared-key handling process, and reachable on-premises CIDRs.

Terminal window
git clone https://github.com/travishankins/azure-launchpad.git
cd azure-launchpad
az login
az account set --subscription <subscription-id>
Terminal window
export ARM_SUBSCRIPTION_ID=<subscription-id>
./scripts/bootstrap-state.sh

This creates:

  • A resource group rg-tfstate-<prefix>-<region>
  • A storage account st<prefix>tfstate<6-char-hash>
  • A blob container tfstate
  • .launchpad/backend.hcl, an ignored local backend configuration used by scripts/deploy.sh
  • A Storage Blob Data Contributor assignment for the signed-in identity

The script is idempotent. To grant the GitHub OIDC service principal access during bootstrap, also set TFSTATE_EXTRA_PRINCIPAL_ID to its object ID. Role-assignment creation requires one of the elevated bootstrap roles listed above; normal deployments do not.

If you want plan/apply to run in GitHub Actions, you also need:

  • An Entra ID app registration with a federated credential trusting your repo
  • The repo variables listed in CI/CD pipeline

The stock Actions workflows currently support single-subscription foundations. Use the generated local/Cloud Shell commands for multi-subscription foundations.