eSHARS · Estate

Estate Explorer

From root scaffolding to app deployments — the rebuilt Azure estate, how it fits together, and what is automated. Click a node on the map to drill in.
2
tiers (nonprod / prod)
6
environments
18
Terraform roots
24
reusable modules
13
GitHub workflows
0
secrets typed by hand

Generated 2026-07-29 · from eshars-ops develop @ 2d67c92 (docs/ESTATE_WALKTHROUGH.md, .github/workflows/*, infrastructure/*) · ops.myeshars.com platform pages

TL;DR

The eSHARS Azure estate is a layered, CAF-aligned landing zone driven entirely by OpenTofu + GitHub Actions. Six numbered workflows (Infra: 1–6, chained by an Infra: 0 orchestrator, fronted by Port) stand a tier up from zero under a two-identity model. App releases deploy onto it from the HISD repo using the ops VM's managed identity, and database refresh/seeding is self-service via Port — with no stored credentials anywhere.

The map

platform SP (hosted runner) workload SP (self-hosted, in-spoke) edges of the estate manual, once per tier

Click a node

Hover to light up a node's connections; click (or press Enter) to see what it creates, which identity runs it, and where the deep-dive docs live.

Tiers & environments

Everything is built once per tier; an environment is just another workload-env on top of a tier that already exists.

TierEnvironmentsState backendAutomation account
nonprod dev qa regression sattfnonprodcus in rg-eshars-scaffold-nonprod-cus aa-eshars-nonprod-cus
prod uat training prod sattfprodcus in rg-eshars-scaffold-prod-cus aa-eshars-prod-cus

Every Terraform root has its own state blob in its tier's storage account (Entra-auth only, shared keys disabled) — nonprod CI/CD physically cannot touch prod state. There is no staging environment; prod has a staging deployment slot (the zero-downtime swap target).

The identity model — three identities, three blast radii

Platform SPWorkload SPVM managed identities
Namegithub-eshars-platformgithub-eshars-deployper-VM system-assigned
RunsInfra 1–3 (everything that creates resource groups)Infra 4–6 + Port/runbook workflowsApp CD + Automation runbooks
ScopeSubscription Contributor + UAARG-scoped grants minted by workload-core (Reader-only on the ops RG — it can never rewrite its own executor)Narrow data-plane roles
GitHub environmentplatformopsn/a — runner-local az login --identity
RunnerGitHub-hostedSelf-hosted ops VMthe ops VM itself
⚠️
Open hardening item. The final step of the identity split — removing the workload SP's temporary subscription-scope Contributor/UAA and DBA-group ownership — is sequenced last in the plan and still open. Highest-value remaining security task.

Drill-in: how an app instance is wired

The chain every environment's app rides — config, secrets, identity, and the database swap trick. (Candidate for its own standalone explorer.)

App Service starts with two pointers, not secrets
Stamped at deploy time by the tier-aware CD

The web app gets SecureSettingsKeyVault (its per-env vault, kv-eshars-{env}-cus) as an app setting and a token-substituted Web.config — nothing sensitive lives in app settings or config files.

Managed identity reads the vault
RBAC granted by Terraform (workload-env)

The app's system-assigned MI holds Key Vault Secrets User on its env vault (private-endpoint-only). It reads connection strings, vendor keys, and the tier encryption key — no stored credentials anywhere in the chain.

Connection strings point at DNS aliases, not servers
The database DNS abstraction

The ESHARS* connection strings target eshars-primary.db.{env}.eshars.internal (and eshars-reporting) — CNAMEs in a per-env private zone. Swapping the database behind an environment is one CNAME update: no deployment, no KV change, no restart.

Azure SQL, three databases, Entra-first
Created by workload-env

db-eshars-{env} (core) + -log + -audit on sql-eshars-{env}-cus. The server's Entra admin is the tier DBA group; the SQL admin password is Terraform-generated straight into the vault. Prod adds a CanNotDelete lock and prevent_destroy.

GitHub environment variables close the loop
Written by Terraform via a GitHub App

workload-env syncs the per-env deploy variables/secrets into the HISD repo's GitHub environment — infrastructure changes propagate to CD configuration automatically; nobody hand-edits environment variables.

🛑
Never seed masterPassword. It is not a crypto key — any non-empty value is a universal override login into every account. The safe state is absent, and Terraform deliberately does not create it. Details: Configuration & Secrets.

What's automated end-to-end today

⚠️
Known gap. No post-deploy smoke tests, health probes, or automated rollback in app CD yet — prod's slot swap is the only rollback affordance. Top of the backlog with the monitoring build-out.
Source map