Skip to content

Azure RaaS — New Customer Configuration + Initial Terraform Deploy (Ops Playbook)

Audience: Junior Cloud Engineers
Covers: New customer YAML → PR → publish workflow → initial Terraform modules (base account, then base connectivity).
Does NOT cover: Full module rollout beyond initial phases, full VM/bootstrap behavior, and post-deploy validation.


Systems and repos involved

  • RAAS-azure-customer-configs (source of truth; Deploy Lens reads from here)

  • RAAS-azure-terraform-v2 (Terraform execution repo; publish workflow generates/updates changes here)

  • RAAS-azure-ansible-v2 (bootstrap/Ansible repo; publish workflow generates/updates changes here)

  • Deploy Lens (reads customer-configs)

  • Rhapsody SaaS Platform Portal → Cosmos DB (customer map/secrets/IP allocation etc.; typically Seniors)


Inputs you must have before you start

Collect these before you touch the repos:

  • Customer code (e.g., CCAD)

  • Tenant name (usually RAAS, sometimes M42)

  • Salesforce customer number (if available)

  • Environments (dev/dev2/test/stage/prod, etc.)

  • Sizing per environment (VM size, disk size/type)

  • OS image choice (AlmaLinux, shared image gallery, use latest)

  • Any optional “extra modules” (VPN/SIFs/ExpressRoute/peering/monitoring/diagnostics)

  • Networking requirements (VPN details, remote VNet IDs/locations, etc.)

  • Rhapsody/Ansible version targets + any rhapsody.properties overrides


High-level flow (for awareness)

  1. Create/update customer YAML in raas-azure-customer-configs

  2. Raise PR (preferably via Copilot in VS Code)

  3. Merge PR to main

  4. Run GitHub Action “publish customer config” on main (tenant + customer inputs)

  5. Verify downstream updates in Terraform V2 + Ansible V2

  6. Senior reviews/merges downstream changes

  7. Confirm Cosmos DB customer map/secrets/IP allocation exists (Seniors typically)

  8. Terraform Unified Workflow: PLAN/ APPLY base account, then PLAN/ APPLY base connectivity


Part 1 — Customer config + Publish workflow

Step 1 — Clone the customer config repo

  1. Clone and open in VS Code:

    • github.com/Rhapsody-health/RAAS-azure-customer-configs

Expected result: You can browse customers/ and see tenant folders.


Step 2 — Create the customer folder + YAML

  1. Navigate to customers/ (contains a folder per tenant).

  2. Choose the correct tenant folder:

    • RAAS is typical for RaaS customers; M42 exists for M42 tenant customers.
  3. Create a new folder:

    • customers/<TENANT>/<CUSTOMER_CODE>/
  4. Create the YAML:

    • customers/<TENANT>/<CUSTOMER_CODE>/<CUSTOMER_CODE>.yaml
  5. Recommended: copy an existing YAML from the same tenant as your starting template.


Step 3 — Update the “must change” YAML fields

In your new customer YAML, verify:

  1. tenant: matches where the customer lives (RAAS vs M42).

  2. customer_code: is updated everywhere.

  3. Add Salesforce customer number if provided.

  4. Modules rule: do not list default modules as “extra”; only genuinely optional modules belong under modules.extra.

    • Default modules typically include base account, base core, env-raas, base-snapshots, base connectivity.

    • Examples of extra modules: VPN, SIFs, ExpressRoute, peering, monitoring, diagnostics.

  5. Module versions are now tags (example discussed: v3.0.0) rather than commit SHAs.


Step 4 — Define environments (raas_config)

  1. Create one environment entry per required env (dev/dev2/test/stage/prod, etc.).

  2. Set alt_name per environment (tag used so support can identify instances).

  3. Set compute/disk sizing per environment (example discussed: “medium” with ~512GB disk).

  4. Disk redundancy: direction discussed was moving back to ZRS as default.

  5. Image: AlmaLinux from shared image gallery, use “latest”.


Step 5 — Add optional config blocks (only if required)

Only include these blocks if the customer needs them:

  • Ansible version target (example discussed: 7.5.1 — verify per ticket/customer).

  • Host mappings (domain → on-prem IP via VPN) if needed for local name resolution.

  • rhapsody.properties overrides requested by the customer (appended during bootstrap).

  • Per-environment overrides where needed; keep a default “catch-all” for shared values.


Step 6 — Networking + cost-sensitive defaults (do not “improve” these)

  1. Firewall SKU: keep basic unless explicitly approved.

  2. VPN gateway SKU: keep VpnGw1 unless higher throughput/many tunnels required.

  3. VPNs: you can define multiple VPNs by copying/repeating the block; include crypto parameters.

    • Note: some PFS groups (e.g., 14) may not appear in the portal but can still be valid in config.
  4. Peerings: set remote VNet IDs/locations and ensure VNet access/forwarded traffic options are correct (especially with VPN).


Step 7 — Create branch/commit/push/PR using GitHub Copilot (VS Code)

  1. In VS Code Copilot Chat, switch agent/context to Cloud (not Local).

  2. Ask Copilot to create a new branch, commit, and push your changes.

  3. Ask Copilot to create a PR for that branch.

  4. Review the diff carefully before “Ready for Review”.

  5. Watch for accidental inclusion of generated dirs like out/; remove and ensure it’s ignored.


Step 8 — Merge the customer-config PR

  1. Get review/approval per team process.

  2. Merge to main.

  3. Confirm main contains the new customer folder/YAML.


Step 9 — Run GitHub Action: “publish customer config”

  1. In raas-azure-customer-configs on GitHub: Actions → “publish customer config”.

  2. Run workflow from the main branch.

  3. Enter inputs:

    • Tenant

    • Customer code

  4. Decide: dry run vs create downstream changes:

    • Set “render only / only render” true to preview without creating branches/PRs

    • Set it false to create downstream branches/PRs

  5. Monitor workflow logs until completion.


Step 10 — Verify downstream outputs (Terraform + Ansible)

  1. In Terraform V2 repo, confirm a new branch and/or PR was created/updated for the customer.

  2. In Ansible V2 repo, confirm a PR was created/updated for bootstrap config.

  3. If something looks incorrect (stale/broken branch from previous attempts), delete/close old branch/PR and re-run publish workflow.


Step 11 — Handoff

  1. Ask a Senior (Lee/Cole/Emily) to review and merge downstream PRs/branches.

  2. Once merged, proceed to Part 2 (Terraform deploy).


Part 2 — Deploy initial customer infRAAStructure with Terraform Unified Workflow

Rule: Always run PLAN before APPLY.

Step 12 — Confirm prerequisites

Before running any Terraform workflow:

  • Customer config was published from RAAS-azure-customer-configs.

  • Downstream changes are merged to main in Terraform V2 + Ansible V2 (Senior typically merges).

  • Customer exists in Cosmos DB customer map (secrets/subscription/CIDR/snapshots/etc.).

  • You know tenant + customer code.

  • You know which IaC env you’re targeting (typically prod; sandbox for safe testing only when explicitly requested).


Step 13 — Cosmos DB customer map awareness (usually Seniors)

Where: Rhapsody SaaS platform portal → search “Cosmos” → Cosmos DB → Data Explorer → credentialsitems.

Confirm tenant item exists (e.g., RAAS) and that the customer entry exists under customer map.

Typical fields include customer code/name, firewall address, DNS overrides (optional), CIDR allocation (commonly /24, can be /22), subscription ID, timezone, snapshot schedule.

Important: snapshot schedule start date/time must be in the future.

If you don’t have access, get a Senior to confirm before you run Terraform.


Step 14 — Terraform Unified Workflow: Base account (PLAN)

  1. Go to Terraform V2 repo → Actions → Terraform Unified Workflow → Run workflow.

  2. Set:

    • Branch: main

    • Action: plan

    • Tenant: customer tenant (e.g., RAAS)

    • Customer: customer code (e.g., CCAD)

    • IaC environment: typically prod (sandbox only if explicitly requested)

    • Terraform module: base account (always first for new customer)

  3. Optional security scans (Trivy/AI remediation): leave defaults unless instructed otherwise.

Stop condition: If plan output looks wrong, do not proceed.


Step 15 — Terraform Unified Workflow: Base account (APPLY)

  1. Only after plan is correct, rerun workflow with action = apply (same tenant/customer/env/module).

  2. Expected outcome: foundational resources such as App Configuration, Key Vault, Log Analytics workspace, Storage Account.


Step 16 — Verify Base account resources in Azure

  1. Confirm resources were created under the shared Management subscription in a customer-specific RG.

  2. RG naming pattern includes customer code, region (example shown: UAEN), and “BA base account”.

  3. In the RG you should see:

    • App Configuration

    • Key Vault

    • Log Analytics workspace

    • Storage Account (linked to workspace for logging/telemetry)


Step 17 — Terraform Unified Workflow: Base connectivity (PLAN)

  1. Run the workflow again:

    • Action = plan

    • Module = base connectivity

    • Tenant/customer/env unchanged

  2. If plan fails due to module-level issues: escalate to a Senior (do not guess-fix production module code).


Step 18 — Terraform Unified Workflow: Base connectivity (APPLY)

  1. After a clean plan, rerun workflow with action = apply.

  2. Note: base connectivity creates the firewall and it can take several minutes.


Step 19 — Verify connectivity resources

  1. Connectivity resources (VPNs, firewall, ExpressRoute, peerings, etc.) live in Management subscription under a customer/region connectivity RG.

  2. During apply, firewall may sit in “Creating” for a long time — this is normal.


Step 20 — Continue modules in order (as required)

After base account + base connectivity, continue modules in order:
base counterbase corebase-diagnostics (optional) → env-raasbase-snapshots

Rule of thumb: PLAN then APPLY for each module, one at a time, in order.


Step 21 — Day-2 rerun guidance

Once deployed, you typically do not rerun: base account, base counter, base connectivity, base core.
Most day-2 changes are handled by rerunning env-raas or VPN-related modules.


Quick checklists

Before you raise the PR

  • Correct tenant folder selected (RAAS vs M42)

  • Customer code updated everywhere

  • Salesforce customer number added (if provided)

  • Only extra modules listed under modules.extra

  • Firewall SKU is basic; VPN gateway SKU is 1 unless approved

  • No generated directories (e.g., out/) in commit

Before you run “publish customer config”

  • Customer-config PR merged to main

  • You know exact tenant + customer code

  • You decided: dry run (render only) vs create branches/PRs

After publish workflow

  • Terraform repo has new customer branch/updates

  • Ansible repo has new/updated PR

  • Senior notified to review/merge

Before Terraform Unified Workflow (Part 2)

  • Downstream changes merged to main (Terraform + Ansible)

  • CosmosDB customer map/secrets exist (or Senior confirmed)

  • You will PLAN first (never APPLY blind)

  • Correct tenant/customer/IaC env selected; start with base account then base connectivity


Appendix — YAML starter skeleton (illustrative)

Use an existing in-tenant customer YAML as your source of truth; this is just to help you recognize sections.

# customers/<TENANT>/<CUSTOMER_CODE>/<CUSTOMER_CODE>.yaml

tenant: <TENANT>               # e.g., RAAS or M42
customer_code: <CUSTOMER_CODE> # e.g., CCAD
salesforce_customer_number: <SF_NUMBER>  # optional but recommended

modules:
  extra:
    - <OPTIONAL_MODULE_ID>     # e.g., base_vpn, base_sifs, base_express_route

RAAS_config:
  environments:
    dev:
      alt_name: <CUSTOMER>-Rhapsody-dev
      instance_type: <VM_SIZE>
      disk_size_gb: <DISK_SIZE>
      disk_type: <ZRS_or_other>
      image: <image_gallery_latest>
      rhapsody_properties:
        - key: <property.name>
          value: <value>
    prod:
      alt_name: <CUSTOMER>-Rhapsody-prod
      # ...same pattern...

networking:
  firewall_sku: basic
  vpn_gateway_sku: VpnGw1
  peerings: []
  vpns: []