Overview
Windows Server 2022 VM for bidirectional SFTP file exchange with TMHP (Texas Medicaid & Healthcare Partnership). The VM runs in a dedicated workload spoke VNet (vnet-eshars-prod-cus) with a tightly scoped NSG that only permits outbound connections to the known TMHP and eSHARS SFTP endpoints.
Replaces vm-tmhp-prod (legacy VM in rg-eshars-prod / legacy VNet).
Architecture
VPN clients (172.16.201.0/24)
┌──────────────────────────────────────────────────────────────────┐
│ rg-eshars-prod-compute-cus │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ vm-tmhp-sftp-prod-cus (Standard_D4s_v5, Windows 2022) │ │
│ │ Private IP: dynamic (snet-vms-vnet-eshars-prod-cus) │ │
│ │ Identity: SystemAssigned → kv-eshars-tmhp (Get/List) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ nsg-vm-tmhp-sftp-prod-cus │
│ ├─ AllowVpnRDP (1000) TCP 3389 from 172.16.201.0/24 │
│ ├─ AllowVpnSFTP (1010) TCP 22 from 172.16.201.0/24 │
│ └─ DenyAllInbound (4096) * │
│ ├─ AllowTmhpUat (1000) TCP 22 → 168.58.234.28 │
│ ├─ AllowTmhpProd (1010) TCP 22 → 168.44.238.59 │
│ ├─ AllowEsharsSftp(1020) TCP 22 → 40.77.98.52 │
│ ├─ AllowKeyVault (1030) TCP 443 → VirtualNetwork │
│ ├─ AllowTeams (1035) TCP 443 → Internet │
│ ├─ AllowSql (1040) TCP 1433,11000-11999 → Sql tag │
│ └─ DenyAllOutbound(4096) * │
└──────────────────────────────────────────────────────────────────┘
│ VNet peering (vnet-eshars-prod-cus → vnet-eshars-core)
┌──────────────────────────────────────────────┐
│ rg-eshars-prod-network-cus │
│ pe-kv-eshars-tmhp → kv-eshars-tmhp │
│ (privatelink.vaultcore.azure.net) │
└──────────────────────────────────────────────┘
TMHP UAT 168.58.234.28:22
TMHP Prod 168.44.238.59:22
eSHARS SFTP 40.77.98.52:22
Resource Inventory
Resource Name Notes Resource Group (compute) rg-eshars-prod-compute-cusShared prod compute RG Resource Group (network) rg-eshars-prod-network-cusWorkload spoke VNet RG Virtual Machine vm-tmhp-sftp-prod-cusStandard_D4s_v5, Central US NIC nic-vm-tmhp-sftp-prod-cusDynamic private IP NSG nsg-vm-tmhp-sftp-prod-cusNIC-level, 9 rules OS Disk disk-vm-tmhp-sftp-prod-cus-os127 GB, Premium_LRS Data Disk disk-vm-tmhp-sftp-prod-cus-data128 GB, Premium_LRS, LUN 0 Managed Identity System-assigned Principal ID on VM KV Access Policy kv-eshars-tmhpGet/List on keys, secrets, certs Private Endpoint pe-kv-eshars-tmhpIn rg-eshars-prod-network-cus SQL VNet Rule vnetrule-tmhp-sftp-prod-cusOn db-eshars-prod Key Vault kv-eshars-tmhpIn rg-eshars-prod
External Connectivity
Endpoint IP Port Direction Purpose TMHP Production SFTP 168.44.238.59 22 Outbound Production file exchange TMHP UAT SFTP 168.58.234.28 22 Outbound UAT/testing file exchange eSHARS SFTP 40.77.98.52 22 Outbound Internal SFTP drop eSHARS SQL (db-eshars-prod) via service endpoint 1433, 11000-11999 Outbound Database writes kv-eshars-tmhpvia private endpoint 443 Outbound Credential retrieval
IaC File Structure
infrastructure/tmhp-sftp/
├── main.tf # NSG, NIC, VM, data disk, KV policy, SQL VNet rule, PE
├── locals.tf # Tags: Project, Environment, ManagedBy, Role=tmhp-sftp
├── prod.backend.hcl # key: tmhp-sftp-prod.tfstate
├── nonprod.tfvars # placeholder — no nonprod deployment yet
Deployment
# Set the VM admin password (never in tfvars)
export TF_VAR_admin_password = ' ... '
Access
Method Path RDP Via P2S VPN → RDP to VM private IP (172.16.201.x → private IP) SFTP (admin) Via P2S VPN → SSH to VM private IP on port 22
No public IP. No Bastion. VPN is the only inbound path.
Security
Control Status Notes No public IP ✅ Private IP only NSG deny-all inbound ✅ VPN-only inbound NSG deny-all outbound ✅ Only known SFTP/SQL/KV endpoints allowed Managed identity for KV ✅ No stored credentials for Key Vault SQL access via VNet rule ✅ Subnet allowlisted on db-eshars-prod KV access via private endpoint ✅ pe-kv-eshars-tmhp in network RGDefender for Servers Check subscription Enabled at subscription level