# #Handson Deploying a Secure SQL Server VM on Azure with Infrastructure as Code and Just-in-Time Access

## **Executive Brief**

This deployment demonstrates a modern, secure approach to cloud infrastructure management using **Infrastructure as Code (IaC)** principles with Bicep. By combining **Azure DevOps pipelines**, **Azure Key Vault for secret management**, and **Just-in-Time (JIT) VM access**, we've created a repeatable, auditable, and highly secure deployment pattern.

![Azure_Bicep_Deployment_Diagram.png](https://private-us-east-1.manuscdn.com/users/107476622/uploads/cVTlLyFa0m9ZwlEgVh03iM_na1fn_QXp1cmVfQmljZXBfRGVwbG95bWVudF9EaWFncmFt.png?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9wcml2YXRlLXVzLWVhc3QtMS5tYW51c2Nkbi5jb20vdXNlcnMvMTA3NDc2NjIyL3VwbG9hZHMvY1ZUbEx5RmEwbTlad2xFZ1ZoMDNpTV9uYTFmbl9RWHAxY21WZlFtbGpaWEJmUkdWd2JHOTViV1Z1ZEY5RWFXRm5jbUZ0LnBuZyIsIkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTc5ODc2MTYwMH19fV19&Key-Pair-Id=K2HSFNDJXOU9YS&Signature=XMhIbmNVKHGaRf-skKviDJeTSuBnhrXm~zcsZR55hUPszHZ3hCPDfo6XdSXZ7rQPpNyF~zoTfPAVg3ybW0oNZiPSdmpZIkiiAd4PKlpRsN5issO5n6f2JBZ8op450hPGr6GSdPG2vQuNG3GfTf0g2-Bg5reAJhZYvkFiUtZYHJhmmNuUXAg~TquXfpJf~szD4g6-VEifW94zRyfIZQ6wGxyNwyUfaWCI~~sIOaf-bGDLRWk7~C77egb1pIdlneYrAQMZ3cgmYqoj2TfioaPOtHY6LbiJqyY-s~r-2rSebrGuEvpXYXYKCrrqIyBbLfxrKjHGC6nS22zPVg~Lk-PIHg__ align="left")

The Repo:

### **Key Benefits & Why This Approach Matters:**

1. **Infrastructure as Code (Bicep)**:
    
    * **Version-controlled infrastructure** - Every change is tracked in Git
        
    * **Consistent deployments** - Eliminates configuration drift
        
    * **Self-documenting** - Bicep files serve as living documentation
        
    * **Collaboration enabled** - Team members can review and approve changes via PRs
        
2. **Secure Secret Management with Azure Key Vault**:
    
    * **No hardcoded credentials** in code or pipelines
        
    * **Centralized secret management** - Single source of truth for passwords
        
    * **Automatic rotation support** - Easy password rotation without redeployment
        
    * **Access auditing** - Track who accessed secrets and when
        
3. **Azure DevOps CI/CD Pipeline**:
    
    * **Automated validation** - Bicep syntax and what-if analysis
        
    * **Controlled deployments** - Approval gates and environment promotion
        
    * **Audit trail** - Complete history of who deployed what and when
        
    * **Rollback capability** - Easy to revert to previous versions
        
4. **Just-in-Time (JIT) VM Access**:
    
    * **Zero standing access** - No open RDP/SSH ports by default
        
    * **Time-limited access** - Connections automatically expire (max 3 hours)
        
    * **Approval workflow** - Request/approve access through Defender for Cloud
        
    * **Attack surface reduction** - Eliminates 24/7 exposure to brute force attacks
        
    * **Compliance friendly** - Meets strict security requirements (NIST, CIS, etc.)
        

![Azure_JIT_Access_Diagram.png](https://private-us-east-1.manuscdn.com/sessionFile/yj9Ck1sHOZHSAR7lLbnjxh/sandbox/fhmIXl1wljTzhlW8zxzasV_1764903321365_na1fn_L2hvbWUvdWJ1bnR1L0F6dXJlX0pJVF9BY2Nlc3NfRGlhZ3JhbQ.png?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9wcml2YXRlLXVzLWVhc3QtMS5tYW51c2Nkbi5jb20vc2Vzc2lvbkZpbGUveWo5Q2sxc0hPWkhTQVI3bExibmp4aC9zYW5kYm94L2ZobUlYbDF3bGpUemhsVzh6eHphc1ZfMTc2NDkwMzMyMTM2NV9uYTFmbl9MMmh2YldVdmRXSjFiblIxTDBGNmRYSmxYMHBKVkY5QlkyTmxjM05mUkdsaFozSmhiUS5wbmciLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE3OTg3NjE2MDB9fX1dfQ__&Key-Pair-Id=K2HSFNDJXOU9YS&Signature=tYLaDe8sEa5UJefkNJuCbc3b6nB5oS9m1DxRu1J2TmwC1~bV43auT1vmhn15G4xXEigSd7eBrcR~1D~ctv5TE2vJOdPupVkBFZxHlIBP649aWCaSGhO41HV0KZb7o4lbkhFuLWr6U~q0PT-xamFYNqFlzqOdcvIy2E2X4TI8YHlwvbYl6g1FpLCKzmywghBFzCvdPJporpJnAYZBxjyAackhTxnqTNoMprJiEQxEg3eftJ7fn4QHIavX45Ej9zPeo4I~gAN7rr7FMLDxH8NqdG7ZtR~0LMvTIJXy2I3dyAtPHiD8eMhtDtkU3QjHwMuF0~OXb-QDoKLIZJfK7kHaNg__ align="left")

This approach transforms traditional VM deployment from a manual, error-prone process into a **repeatable, secure, and compliant** operation that scales across teams and environments.

## **Complete Deployment Journey: Step-by-Step**

### **Phase 1: Initial Setup & Repository Creation**

| Step | Where Performed | Action | Commands/Details |
| --- | --- | --- | --- |
| 1\. **Create GitHub Repository** | [GitHub.com](http://GitHub.com) | Created new repository for infrastructure code | [`https://github.com/soyroberto/bicex`](https://github.com/soyroberto/bicex) |
| 2\. **Clone Repository Locally** | Local Terminal | Set up local working directory | `git clone` [`https://github.com/soyroberto/bicex.git`](https://github.com/soyroberto/bicex.git) |
| 3\. **Create Project Structure** | Local Filesystem | Organized Bicep files and pipeline | Created `bicep/` directory and `azure-pipelines.yml` |

### **Phase 2: Bicep Template Development**

| Step | Where Performed | Action | Commands/Details |
| --- | --- | --- | --- |
| 4\. **Create Main Bicep Template** | `bicep/main.bicep` | Defined VM with SQL Server 2019 | Parameters for VM name, size, networking, Key Vault reference |
| 5\. **Create Parameter File** | `bicep/main.bicepparam` | Defined non-sensitive configuration | VM name, admin username, location, subnet details |
| 6\. **Implement Key Vault Integration** | `bicep/main.bicep` | Added secure password retrieval | `reference()` function for Key Vault secret value |

### **Phase 3: Azure Resource Preparation**

| Step | Where Performed | Action | Commands/Details |
| --- | --- | --- | --- |
| 7\. **Create Resource Group** | Azure Portal/CLI | Set up target resource group | `RGAUANSDeploy` in `australiasoutheast` |
| 8\. **Create Key Vault** | Azure Portal/CLI | Set up secure secret storage | `kvaueansdeploy` with RBAC authorization |
| 9\. **Store VM Password** | Azure Key Vault | Created secret for VM admin password | Secret name: `vmAdminPassword` |
| 10\. **Verify Existing Network** | Azure CLI | Confirmed VNet and NSG availability | `vnetausclient` and `nsgauejit` in `RGAUSNetCh` |

### **Phase 4: Azure DevOps Pipeline Setup**

| Step | Where Performed | Action | Commands/Details |
| --- | --- | --- | --- |
| 11\. **Create Service Connection** | Azure DevOps | Connected Azure subscription | Service principal: `AzureServiceConnection` |
| 12\. **Create Variable Group** | Azure DevOps → Library | Stored non-sensitive configuration | Group: `bicep-deployment-secrets` with 7 variables |
| 13\. **Set Secret Variables** | Variable Group | Added sensitive resource IDs | `VNET_RESOURCE_ID` and `NSG_RESOURCE_ID` (marked secret) |

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764914167516/b2fc832e-4e65-4140-97cf-3745b434acb5.png align="center")

### **Phase 5: Permission Configuration**

| Step | Where Performed | Action | Commands/Details |
| --- | --- | --- | --- |
| 14\. **Grant Key Vault Access** | Azure CLI | Added RBAC roles for service principal | `Key Vault Secrets User` role assignment |
| 15\. **Grant Network Permissions** | Azure CLI | Enabled pipeline to modify network | `Network Contributor` on VNet resource group |
| 16\. **Grant Resource Group Access** | Azure CLI | Enabled pipeline to create resources | `Contributor` on target resource group |

### **Phase 6: Pipeline Development & Testing**

| Step | Where Performed | Action | Commands/Details |
| --- | --- | --- | --- |
| 17\. **Create Pipeline YAML** | `azure-pipelines.yml` | Defined CI/CD workflow | Single stage with Bicep installation and deployment |

### **Phase 7: Deployment Execution**

| Step | Where Performed | Action | Commands/Details |
| --- | --- | --- | --- |
| 18\. **Commit and Push Code** | Local Terminal | Triggered pipeline via Git push | `git add . && git commit -m "Ready" && git push origin main` |
| 19\. **Monitor Pipeline Execution** | Azure DevOps Portal | Watched real-time deployment logs | Validated each step: checkout → Bicep install → VM deployment |
| 20\. **Verify Deployment Success** | Azure Portal | Confirmed VM creation | `vmausbixvm01` running in `RGAUANSDeploy` resource group |

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764914440534/8b4287f9-70ea-4a43-b87f-143579c6a76f.png align="center")

### **Phase 8: Post-Deployment Configuration**

| Step | Where Performed | Action | Commands/Details |
| --- | --- | --- | --- |
| 21\. **Retrieve VM Password** | Azure CLI | Retrieved admin credentials from Key Vault | `az keyvault secret show --vault-name kvaueansdeploy --name vmAdminPassword` |
| 22\. **Get VM Public IP** | Azure CLI | Retrieved connection endpoint | `az vm show -g RGAUANSDeploy -n vmausbixvm01 --query publicIps -o tsv` |
| 23\. **Configure JIT Access** | Microsoft Defender for Cloud | Enabled Just-in-Time VM access | Portal: Defender for Cloud → Just-in-time VM access → Enable on vmausbixvm01 |

## Before Requesting access from the Remote Desktop Client:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764914792868/b4789788-bccb-4dcd-8b56-36aef5f2330d.png align="center")

## Requesting Access

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764914919940/9ea964d3-f8ad-4471-9f24-4ca813e8da51.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764914955159/ddf652ca-739a-43ca-92bf-81ce37900867.png align="center")

## After JIT enabled

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764914887401/3b6d4c69-b09a-400d-8042-2fca8818cb68.png align="center")

the NSG is enabled on the selected ports 3389

## RDPing to the VM

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764914969976/eb96f19f-6523-4934-b77f-7f9eb8deb7f8.png align="center")

## **Key Technical Decisions & Learnings**

### **1\. Bicep Over ARM Templates**

* **Cleaner syntax** - More readable than JSON ARM templates
    
* **Better tooling** - VS Code extension with IntelliSense
    
* **Modular design** - Can be broken into reusable modules
    

### **2\. Pipeline Design Choices**

* **Single-stage deployment** - Simplified MVP approach
    
* **Inline script execution** - Avoided external script dependencies
    
* **Variable groups** - Centralized configuration management
    

### **3\. Security Implementation**

* **RBAC over access policies** - More granular permission control
    
* **Secret retrieval at runtime** - Never stored in pipeline variables
    
* **JIT-ready NSG** - Pre-configured for zero-standing-access model
    

### **4\. Error Resolution Process**

* **Iterative debugging** - Fixed issues in sequence:
    
    1. Pipeline script location configuration
        
    2. Parameter file syntax compatibility
        
    3. Key Vault secret retrieval method
        
    4. VM image patch settings compatibility
        

## **Future Enhancement Opportunities**

1. **Multi-environment pipelines** - Dev, Test, Prod promotion
    
2. **Bicep modules** - Reusable network, storage, and security components
    
3. **Integration testing** - Post-deployment validation scripts
    
4. **Cost optimization** - Auto-shutdown schedules and sizing recommendations
    
5. **Monitoring integration** - Azure Monitor alerts and dashboards
    

## **Conclusion**

This deployment demonstrates an automated deployment for a secure Azure VM that balances, automation, and maintainability. By leveraging Infrastructure as Code, secure secret management, and Just-in-Time access, organizations can significantly reduce their attack surface while maintaining operational efficiency.

The complete solution took approximately **4 hours** from initial repository creation to successful VM connection, with the majority of time spent on **configuration and debugging** rather than manual infrastructure provisioning. Subsequent deployments would take **under 15 minutes** (ideally)

Roberto
